Index: llvm/include/llvm/Analysis/TargetLibraryInfo.def =================================================================== --- llvm/include/llvm/Analysis/TargetLibraryInfo.def +++ llvm/include/llvm/Analysis/TargetLibraryInfo.def @@ -434,6 +434,9 @@ /// size_t dstsize); TLI_DEFINE_ENUM_INTERNAL(strlcpy_chk) TLI_DEFINE_STRING_INTERNAL("__strlcpy_chk") +/// char *__strlen_chk(const char *s1, size_t s1size); +TLI_DEFINE_ENUM_INTERNAL(strlen_chk) +TLI_DEFINE_STRING_INTERNAL("__strlen_chk") /// char *strncat_chk(char *s1, const char *s2, size_t n, size_t s1size); TLI_DEFINE_ENUM_INTERNAL(strncat_chk) TLI_DEFINE_STRING_INTERNAL("__strncat_chk") Index: llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h =================================================================== --- llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h +++ llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h @@ -60,6 +60,7 @@ /// Str/Stp cpy are similar enough to be handled in the same functions. Value *optimizeStrpCpyChk(CallInst *CI, IRBuilder<> &B, LibFunc Func); Value *optimizeStrpNCpyChk(CallInst *CI, IRBuilder<> &B, LibFunc Func); + Value *optimizeStrLenChk(CallInst *CI, IRBuilder<> &B); Value *optimizeMemCCpyChk(CallInst *CI, IRBuilder<> &B); Value *optimizeSNPrintfChk(CallInst *CI, IRBuilder<> &B); Value *optimizeSPrintfChk(CallInst *CI,IRBuilder<> &B); Index: llvm/lib/Analysis/TargetLibraryInfo.cpp =================================================================== --- llvm/lib/Analysis/TargetLibraryInfo.cpp +++ llvm/lib/Analysis/TargetLibraryInfo.cpp @@ -659,6 +659,11 @@ FTy.getParamType(1)->isPointerTy() && FTy.getParamType(2)->isPointerTy() && FTy.getReturnType()->isIntegerTy(32)); + case LibFunc_strlen_chk: + --NumParams; + if (!IsSizeTTy(FTy.getParamType(NumParams))) + return false; + LLVM_FALLTHROUGH; case LibFunc_strlen: return (NumParams == 1 && FTy.getParamType(0)->isPointerTy() && FTy.getReturnType()->isIntegerTy()); Index: llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp =================================================================== --- llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -3093,6 +3093,10 @@ // Try to further simplify the result. CallInst *SimplifiedCI = dyn_cast(SimplifiedFortifiedCI); if (SimplifiedCI && SimplifiedCI->getCalledFunction()) { + // Ensure that SimplifiedCI's uses are complete, since some calls have + // their uses analyzed. + replaceAllUsesWith(CI, SimplifiedCI); + // Use an IR Builder from SimplifiedCI if available instead of CI // to guarantee we reach all uses we might replace later on. IRBuilder<> TmpBuilder(SimplifiedCI); @@ -3354,6 +3358,14 @@ return Ret; } +Value *FortifiedLibCallSimplifier::optimizeStrLenChk(CallInst *CI, + IRBuilder<> &B) { + if (isFortifiedCallFoldable(CI, 1, None, 0)) + return emitStrLen(CI->getArgOperand(0), B, CI->getModule()->getDataLayout(), + TLI); + return nullptr; +} + Value *FortifiedLibCallSimplifier::optimizeStrpNCpyChk(CallInst *CI, IRBuilder<> &B, LibFunc Func) { @@ -3494,6 +3506,8 @@ case LibFunc_stpcpy_chk: case LibFunc_strcpy_chk: return optimizeStrpCpyChk(CI, Builder, Func); + case LibFunc_strlen_chk: + return optimizeStrLenChk(CI, Builder); case LibFunc_stpncpy_chk: case LibFunc_strncpy_chk: return optimizeStrpNCpyChk(CI, Builder, Func); Index: llvm/test/Transforms/InstCombine/strlen_chk.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/InstCombine/strlen_chk.ll @@ -0,0 +1,47 @@ +; Test that __strlen_chk simplification works correctly. +; +; RUN: opt < %s -instcombine -S | FileCheck %s + +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" + +@hello = constant [6 x i8] c"hello\00" +@hello_no_nul = constant [5 x i8] c"hello" + +declare i32 @__strlen_chk(i8*, i32) + +; Check __strlen_chk(string constant) -> strlen or constants + +; CHECK-LABEL: @unknown_str_known_object_size +define i32 @unknown_str_known_object_size(i8* %c) { + ; CHECK: call i32 @__strlen_chk + %1 = call i32 @__strlen_chk(i8* %c, i32 8) + ret i32 %1 +} + +; CHECK-LABEL: @known_str_known_object_size +define i32 @known_str_known_object_size(i8* %c) { + ; CHECK: ret i32 5 + %1 = call i32 @__strlen_chk(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @hello, i32 0, i32 0), i32 6) + ret i32 %1 +} + +; CHECK-LABEL: @known_str_too_small_object_size +define i32 @known_str_too_small_object_size(i8* %c) { + ; CHECK: call i32 @__strlen_chk + %1 = call i32 @__strlen_chk(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @hello, i32 0, i32 0), i32 5) + ret i32 %1 +} + +; CHECK-LABEL: @known_str_no_nul +define i32 @known_str_no_nul(i8* %c) { + ; CHECK: call i32 @__strlen_chk + %1 = call i32 @__strlen_chk(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @hello_no_nul, i32 0, i32 0), i32 5) + ret i32 %1 +} + +; CHECK-LABEL: @unknown_str_unknown_object_size +define i32 @unknown_str_unknown_object_size(i8* %c) { + ; CHECK: call i32 @strlen + %1 = call i32 @__strlen_chk(i8* %c, i32 -1) + ret i32 %1 +} Index: llvm/unittests/Analysis/TargetLibraryInfoTest.cpp =================================================================== --- llvm/unittests/Analysis/TargetLibraryInfoTest.cpp +++ llvm/unittests/Analysis/TargetLibraryInfoTest.cpp @@ -474,6 +474,7 @@ "declare i32 @__sprintf_chk(i8*, i32, i64, i8*, ...)\n" "declare i8* @__strcat_chk(i8*, i8*, i64)\n" "declare i64 @__strlcat_chk(i8*, i8*, i64, i64)\n" + "declare i64 @__strlen_chk(i8*, i64)\n" "declare i8* @__strncat_chk(i8*, i8*, i64, i64)\n" "declare i64 @__strlcpy_chk(i8*, i8*, i64, i64)\n" "declare i32 @__vsnprintf_chk(i8*, i64, i32, i64, i8*, %struct*)\n"