From a239c2e6a7775e890bcfb0867b84e512ceb993de Mon Sep 17 00:00:00 2001 From: Meador Inge Date: Mon, 15 Oct 2012 03:47:37 +0000 Subject: [PATCH] instcombine: Migrate strcmp and strncmp optimizations This patch migrates the strcmp and strncmp optimizations from the simplify-libcalls pass into the instcombine library call simplifier. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@165915 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Transforms/Scalar/SimplifyLibCalls.cpp | 105 ------------------ lib/Transforms/Utils/SimplifyLibCalls.cpp | 99 +++++++++++++++++ test/Transforms/InstCombine/strcmp-1.ll | 82 ++++++++++++++ test/Transforms/InstCombine/strcmp-2.ll | 20 ++++ test/Transforms/InstCombine/strncmp-1.ll | 97 ++++++++++++++++ test/Transforms/InstCombine/strncmp-2.ll | 20 ++++ test/Transforms/InstCombine/weak-symbols.ll | 33 ++++++ test/Transforms/SimplifyLibCalls/StrCmp.ll | 65 ----------- test/Transforms/SimplifyLibCalls/StrNCmp.ll | 78 ------------- .../SimplifyLibCalls/weak-symbols.ll | 26 ----- 10 files changed, 351 insertions(+), 274 deletions(-) create mode 100644 test/Transforms/InstCombine/strcmp-1.ll create mode 100644 test/Transforms/InstCombine/strcmp-2.ll create mode 100644 test/Transforms/InstCombine/strncmp-1.ll create mode 100644 test/Transforms/InstCombine/strncmp-2.ll create mode 100644 test/Transforms/InstCombine/weak-symbols.ll delete mode 100644 test/Transforms/SimplifyLibCalls/StrCmp.ll delete mode 100644 test/Transforms/SimplifyLibCalls/StrNCmp.ll delete mode 100644 test/Transforms/SimplifyLibCalls/weak-symbols.ll diff --git a/lib/Transforms/Scalar/SimplifyLibCalls.cpp b/lib/Transforms/Scalar/SimplifyLibCalls.cpp index 4cd8742cc3f..6df0ee23223 100644 --- a/lib/Transforms/Scalar/SimplifyLibCalls.cpp +++ b/lib/Transforms/Scalar/SimplifyLibCalls.cpp @@ -134,108 +134,6 @@ static bool IsOnlyUsedInEqualityComparison(Value *V, Value *With) { //===----------------------------------------------------------------------===// namespace { -//===---------------------------------------===// -// 'strcmp' Optimizations - -struct StrCmpOpt : public LibCallOptimization { - virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) { - // Verify the "strcmp" function prototype. - FunctionType *FT = Callee->getFunctionType(); - if (FT->getNumParams() != 2 || - !FT->getReturnType()->isIntegerTy(32) || - FT->getParamType(0) != FT->getParamType(1) || - FT->getParamType(0) != B.getInt8PtrTy()) - return 0; - - Value *Str1P = CI->getArgOperand(0), *Str2P = CI->getArgOperand(1); - if (Str1P == Str2P) // strcmp(x,x) -> 0 - return ConstantInt::get(CI->getType(), 0); - - StringRef Str1, Str2; - bool HasStr1 = getConstantStringInfo(Str1P, Str1); - bool HasStr2 = getConstantStringInfo(Str2P, Str2); - - // strcmp(x, y) -> cnst (if both x and y are constant strings) - if (HasStr1 && HasStr2) - return ConstantInt::get(CI->getType(), Str1.compare(Str2)); - - if (HasStr1 && Str1.empty()) // strcmp("", x) -> -*x - return B.CreateNeg(B.CreateZExt(B.CreateLoad(Str2P, "strcmpload"), - CI->getType())); - - if (HasStr2 && Str2.empty()) // strcmp(x,"") -> *x - return B.CreateZExt(B.CreateLoad(Str1P, "strcmpload"), CI->getType()); - - // strcmp(P, "x") -> memcmp(P, "x", 2) - uint64_t Len1 = GetStringLength(Str1P); - uint64_t Len2 = GetStringLength(Str2P); - if (Len1 && Len2) { - // These optimizations require DataLayout. - if (!TD) return 0; - - return EmitMemCmp(Str1P, Str2P, - ConstantInt::get(TD->getIntPtrType(*Context), - std::min(Len1, Len2)), B, TD, TLI); - } - - return 0; - } -}; - -//===---------------------------------------===// -// 'strncmp' Optimizations - -struct StrNCmpOpt : public LibCallOptimization { - virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) { - // Verify the "strncmp" function prototype. - FunctionType *FT = Callee->getFunctionType(); - if (FT->getNumParams() != 3 || - !FT->getReturnType()->isIntegerTy(32) || - FT->getParamType(0) != FT->getParamType(1) || - FT->getParamType(0) != B.getInt8PtrTy() || - !FT->getParamType(2)->isIntegerTy()) - return 0; - - Value *Str1P = CI->getArgOperand(0), *Str2P = CI->getArgOperand(1); - if (Str1P == Str2P) // strncmp(x,x,n) -> 0 - return ConstantInt::get(CI->getType(), 0); - - // Get the length argument if it is constant. - uint64_t Length; - if (ConstantInt *LengthArg = dyn_cast(CI->getArgOperand(2))) - Length = LengthArg->getZExtValue(); - else - return 0; - - if (Length == 0) // strncmp(x,y,0) -> 0 - return ConstantInt::get(CI->getType(), 0); - - if (TD && Length == 1) // strncmp(x,y,1) -> memcmp(x,y,1) - return EmitMemCmp(Str1P, Str2P, CI->getArgOperand(2), B, TD, TLI); - - StringRef Str1, Str2; - bool HasStr1 = getConstantStringInfo(Str1P, Str1); - bool HasStr2 = getConstantStringInfo(Str2P, Str2); - - // strncmp(x, y) -> cnst (if both x and y are constant strings) - if (HasStr1 && HasStr2) { - StringRef SubStr1 = Str1.substr(0, Length); - StringRef SubStr2 = Str2.substr(0, Length); - return ConstantInt::get(CI->getType(), SubStr1.compare(SubStr2)); - } - - if (HasStr1 && Str1.empty()) // strncmp("", x, n) -> -*x - return B.CreateNeg(B.CreateZExt(B.CreateLoad(Str2P, "strcmpload"), - CI->getType())); - - if (HasStr2 && Str2.empty()) // strncmp(x, "", n) -> *x - return B.CreateZExt(B.CreateLoad(Str1P, "strcmpload"), CI->getType()); - - return 0; - } -}; - - //===---------------------------------------===// // 'strcpy' Optimizations @@ -1378,7 +1276,6 @@ namespace { StringMap Optimizations; // String and Memory LibCall Optimizations - StrCmpOpt StrCmp; StrNCmpOpt StrNCmp; StrCpyOpt StrCpy; StrCpyOpt StrCpyChk; StpCpyOpt StpCpy; StpCpyOpt StpCpyChk; StrNCpyOpt StrNCpy; @@ -1452,8 +1349,6 @@ void SimplifyLibCalls::AddOpt(LibFunc::Func F1, LibFunc::Func F2, /// we know. void SimplifyLibCalls::InitOptimizations() { // String and Memory LibCall Optimizations - Optimizations["strcmp"] = &StrCmp; - Optimizations["strncmp"] = &StrNCmp; Optimizations["strcpy"] = &StrCpy; Optimizations["strncpy"] = &StrNCpy; Optimizations["stpcpy"] = &StpCpy; diff --git a/lib/Transforms/Utils/SimplifyLibCalls.cpp b/lib/Transforms/Utils/SimplifyLibCalls.cpp index 5ce5843b216..bd28ec35273 100644 --- a/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ b/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -402,6 +402,101 @@ struct StrRChrOpt : public LibCallOptimization { } }; +struct StrCmpOpt : public LibCallOptimization { + virtual Value *callOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) { + // Verify the "strcmp" function prototype. + FunctionType *FT = Callee->getFunctionType(); + if (FT->getNumParams() != 2 || + !FT->getReturnType()->isIntegerTy(32) || + FT->getParamType(0) != FT->getParamType(1) || + FT->getParamType(0) != B.getInt8PtrTy()) + return 0; + + Value *Str1P = CI->getArgOperand(0), *Str2P = CI->getArgOperand(1); + if (Str1P == Str2P) // strcmp(x,x) -> 0 + return ConstantInt::get(CI->getType(), 0); + + StringRef Str1, Str2; + bool HasStr1 = getConstantStringInfo(Str1P, Str1); + bool HasStr2 = getConstantStringInfo(Str2P, Str2); + + // strcmp(x, y) -> cnst (if both x and y are constant strings) + if (HasStr1 && HasStr2) + return ConstantInt::get(CI->getType(), Str1.compare(Str2)); + + if (HasStr1 && Str1.empty()) // strcmp("", x) -> -*x + return B.CreateNeg(B.CreateZExt(B.CreateLoad(Str2P, "strcmpload"), + CI->getType())); + + if (HasStr2 && Str2.empty()) // strcmp(x,"") -> *x + return B.CreateZExt(B.CreateLoad(Str1P, "strcmpload"), CI->getType()); + + // strcmp(P, "x") -> memcmp(P, "x", 2) + uint64_t Len1 = GetStringLength(Str1P); + uint64_t Len2 = GetStringLength(Str2P); + if (Len1 && Len2) { + // These optimizations require DataLayout. + if (!TD) return 0; + + return EmitMemCmp(Str1P, Str2P, + ConstantInt::get(TD->getIntPtrType(*Context), + std::min(Len1, Len2)), B, TD, TLI); + } + + return 0; + } +}; + +struct StrNCmpOpt : public LibCallOptimization { + virtual Value *callOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) { + // Verify the "strncmp" function prototype. + FunctionType *FT = Callee->getFunctionType(); + if (FT->getNumParams() != 3 || + !FT->getReturnType()->isIntegerTy(32) || + FT->getParamType(0) != FT->getParamType(1) || + FT->getParamType(0) != B.getInt8PtrTy() || + !FT->getParamType(2)->isIntegerTy()) + return 0; + + Value *Str1P = CI->getArgOperand(0), *Str2P = CI->getArgOperand(1); + if (Str1P == Str2P) // strncmp(x,x,n) -> 0 + return ConstantInt::get(CI->getType(), 0); + + // Get the length argument if it is constant. + uint64_t Length; + if (ConstantInt *LengthArg = dyn_cast(CI->getArgOperand(2))) + Length = LengthArg->getZExtValue(); + else + return 0; + + if (Length == 0) // strncmp(x,y,0) -> 0 + return ConstantInt::get(CI->getType(), 0); + + if (TD && Length == 1) // strncmp(x,y,1) -> memcmp(x,y,1) + return EmitMemCmp(Str1P, Str2P, CI->getArgOperand(2), B, TD, TLI); + + StringRef Str1, Str2; + bool HasStr1 = getConstantStringInfo(Str1P, Str1); + bool HasStr2 = getConstantStringInfo(Str2P, Str2); + + // strncmp(x, y) -> cnst (if both x and y are constant strings) + if (HasStr1 && HasStr2) { + StringRef SubStr1 = Str1.substr(0, Length); + StringRef SubStr2 = Str2.substr(0, Length); + return ConstantInt::get(CI->getType(), SubStr1.compare(SubStr2)); + } + + if (HasStr1 && Str1.empty()) // strncmp("", x, n) -> -*x + return B.CreateNeg(B.CreateZExt(B.CreateLoad(Str2P, "strcmpload"), + CI->getType())); + + if (HasStr2 && Str2.empty()) // strncmp(x, "", n) -> *x + return B.CreateZExt(B.CreateLoad(Str1P, "strcmpload"), CI->getType()); + + return 0; + } +}; + } // End anonymous namespace. namespace llvm { @@ -423,6 +518,8 @@ class LibCallSimplifierImpl { StrNCatOpt StrNCat; StrChrOpt StrChr; StrRChrOpt StrRChr; + StrCmpOpt StrCmp; + StrNCmpOpt StrNCmp; void initOptimizations(); public: @@ -443,6 +540,8 @@ void LibCallSimplifierImpl::initOptimizations() { Optimizations["__stpcpy_chk"] = &StrCpyChk; Optimizations["__strncpy_chk"] = &StrNCpyChk; Optimizations["__stpncpy_chk"] = &StrNCpyChk; + Optimizations["strcmp"] = &StrCmp; + Optimizations["strncmp"] = &StrNCmp; // String and memory library call optimizations. Optimizations["strcat"] = &StrCat; diff --git a/test/Transforms/InstCombine/strcmp-1.ll b/test/Transforms/InstCombine/strcmp-1.ll new file mode 100644 index 00000000000..0679246e091 --- /dev/null +++ b/test/Transforms/InstCombine/strcmp-1.ll @@ -0,0 +1,82 @@ +; Test that the strcmp library call simplifier 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" +@hell = constant [5 x i8] c"hell\00" +@bell = constant [5 x i8] c"bell\00" +@null = constant [1 x i8] zeroinitializer + +declare i32 @strcmp(i8*, i8*) + +; strcmp("", x) -> -*x +define i32 @test1(i8* %str2) { +; CHECK: @test1 +; CHECK: %strcmpload = load i8* %str +; CHECK: %1 = zext i8 %strcmpload to i32 +; CHECK: %2 = sub i32 0, %1 +; CHECK: ret i32 %2 + + %str1 = getelementptr inbounds [1 x i8]* @null, i32 0, i32 0 + %temp1 = call i32 @strcmp(i8* %str1, i8* %str2) + ret i32 %temp1 + +} + +; strcmp(x, "") -> *x +define i32 @test2(i8* %str1) { +; CHECK: @test2 +; CHECK: %strcmpload = load i8* %str +; CHECK: %1 = zext i8 %strcmpload to i32 +; CHECK: ret i32 %1 + + %str2 = getelementptr inbounds [1 x i8]* @null, i32 0, i32 0 + %temp1 = call i32 @strcmp(i8* %str1, i8* %str2) + ret i32 %temp1 +} + +; strcmp(x, y) -> cnst +define i32 @test3() { +; CHECK: @test3 +; CHECK: ret i32 -1 + + %str1 = getelementptr inbounds [5 x i8]* @hell, i32 0, i32 0 + %str2 = getelementptr inbounds [6 x i8]* @hello, i32 0, i32 0 + %temp1 = call i32 @strcmp(i8* %str1, i8* %str2) + ret i32 %temp1 +} + +define i32 @test4() { +; CHECK: @test4 +; CHECK: ret i32 1 + + %str1 = getelementptr inbounds [5 x i8]* @hell, i32 0, i32 0 + %str2 = getelementptr inbounds [1 x i8]* @null, i32 0, i32 0 + %temp1 = call i32 @strcmp(i8* %str1, i8* %str2) + ret i32 %temp1 +} + +; strcmp(x, y) -> memcmp(x, y, ) +; (This transform is rather difficult to trigger in a useful manner) +define i32 @test5(i1 %b) { +; CHECK: @test5 +; CHECK: %memcmp = call i32 @memcmp(i8* getelementptr inbounds ([6 x i8]* @hello, i32 0, i32 0), i8* %str2, i32 5) +; CHECK: ret i32 %memcmp + + %str1 = getelementptr inbounds [6 x i8]* @hello, i32 0, i32 0 + %temp1 = getelementptr inbounds [5 x i8]* @hell, i32 0, i32 0 + %temp2 = getelementptr inbounds [5 x i8]* @bell, i32 0, i32 0 + %str2 = select i1 %b, i8* %temp1, i8* %temp2 + %temp3 = call i32 @strcmp(i8* %str1, i8* %str2) + ret i32 %temp3 +} + +; strcmp(x,x) -> 0 +define i32 @test6(i8* %str) { +; CHECK: @test6 +; CHECK: ret i32 0 + + %temp1 = call i32 @strcmp(i8* %str, i8* %str) + ret i32 %temp1 +} diff --git a/test/Transforms/InstCombine/strcmp-2.ll b/test/Transforms/InstCombine/strcmp-2.ll new file mode 100644 index 00000000000..20518960f30 --- /dev/null +++ b/test/Transforms/InstCombine/strcmp-2.ll @@ -0,0 +1,20 @@ +; Test that the strcmp library call simplifier 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" +@hell = constant [5 x i8] c"hell\00" + +declare i16 @strcmp(i8*, i8*) + +define i16 @test_nosimplify() { +; CHECK: @test_nosimplify +; CHECK: call i16 @strcmp +; CHECK: ret i16 %temp1 + + %str1 = getelementptr inbounds [5 x i8]* @hell, i32 0, i32 0 + %str2 = getelementptr inbounds [6 x i8]* @hello, i32 0, i32 0 + %temp1 = call i16 @strcmp(i8* %str1, i8* %str2) + ret i16 %temp1 +} diff --git a/test/Transforms/InstCombine/strncmp-1.ll b/test/Transforms/InstCombine/strncmp-1.ll new file mode 100644 index 00000000000..48b26d1a5f3 --- /dev/null +++ b/test/Transforms/InstCombine/strncmp-1.ll @@ -0,0 +1,97 @@ +; Test that the strncmp library call simplifier 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" +@hell = constant [5 x i8] c"hell\00" +@bell = constant [5 x i8] c"bell\00" +@null = constant [1 x i8] zeroinitializer + +declare i32 @strncmp(i8*, i8*, i32) + +; strncmp("", x, n) -> -*x +define i32 @test1(i8* %str2) { +; CHECK: @test1 +; CHECK: %strcmpload = load i8* %str +; CHECK: %1 = zext i8 %strcmpload to i32 +; CHECK: %2 = sub i32 0, %1 +; CHECK: ret i32 %2 + + %str1 = getelementptr inbounds [1 x i8]* @null, i32 0, i32 0 + %temp1 = call i32 @strncmp(i8* %str1, i8* %str2, i32 10) + ret i32 %temp1 +} + +; strncmp(x, "", n) -> *x +define i32 @test2(i8* %str1) { +; CHECK: @test2 +; CHECK: %strcmpload = load i8* %str1 +; CHECK: %1 = zext i8 %strcmpload to i32 +; CHECK: ret i32 %1 + + %str2 = getelementptr inbounds [1 x i8]* @null, i32 0, i32 0 + %temp1 = call i32 @strncmp(i8* %str1, i8* %str2, i32 10) + ret i32 %temp1 +} + +; strncmp(x, y, n) -> cnst +define i32 @test3() { +; CHECK: @test3 +; CHECK: ret i32 -1 + + %str1 = getelementptr inbounds [5 x i8]* @hell, i32 0, i32 0 + %str2 = getelementptr inbounds [6 x i8]* @hello, i32 0, i32 0 + %temp1 = call i32 @strncmp(i8* %str1, i8* %str2, i32 10) + ret i32 %temp1 +} + +define i32 @test4() { +; CHECK: @test4 +; CHECK: ret i32 1 + + %str1 = getelementptr inbounds [5 x i8]* @hell, i32 0, i32 0 + %str2 = getelementptr inbounds [1 x i8]* @null, i32 0, i32 0 + %temp1 = call i32 @strncmp(i8* %str1, i8* %str2, i32 10) + ret i32 %temp1 +} + +define i32 @test5() { +; CHECK: @test5 +; CHECK: ret i32 0 + + %str1 = getelementptr inbounds [5 x i8]* @hell, i32 0, i32 0 + %str2 = getelementptr inbounds [6 x i8]* @hello, i32 0, i32 0 + %temp1 = call i32 @strncmp(i8* %str1, i8* %str2, i32 4) + ret i32 %temp1 +} + +; strncmp(x,y,1) -> memcmp(x,y,1) +; TODO: Once the memcmp simplifier gets moved into the instcombine pass +; the following memcmp will be folded into two loads and a subtract. +define i32 @test6(i8* %str1, i8* %str2) { +; CHECK: @test6 +; CHECK: call i32 @memcmp +; CHECK: ret i32 %memcmp + + %temp1 = call i32 @strncmp(i8* %str1, i8* %str2, i32 1) + ret i32 %temp1 +} + +; strncmp(x,y,0) -> 0 +define i32 @test7(i8* %str1, i8* %str2) { +; CHECK: @test7 +; CHECK: ret i32 0 + + %temp1 = call i32 @strncmp(i8* %str1, i8* %str2, i32 0) + ret i32 %temp1 +} + +; strncmp(x,x,n) -> 0 +define i32 @test8(i8* %str, i32 %n) { +; CHECK: @test8 +; CHECK: ret i32 0 + + %temp1 = call i32 @strncmp(i8* %str, i8* %str, i32 %n) + ret i32 %temp1 +} diff --git a/test/Transforms/InstCombine/strncmp-2.ll b/test/Transforms/InstCombine/strncmp-2.ll new file mode 100644 index 00000000000..3fc43a6fd4f --- /dev/null +++ b/test/Transforms/InstCombine/strncmp-2.ll @@ -0,0 +1,20 @@ +; Test that the strncmp library call simplifier 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" +@hell = constant [5 x i8] c"hell\00" + +declare i16 @strncmp(i8*, i8*, i32) + +define i16 @test_nosimplify() { +; CHECK: @test_nosimplify +; CHECK: call i16 @strncmp +; CHECK: ret i16 %temp1 + + %str1 = getelementptr inbounds [5 x i8]* @hell, i32 0, i32 0 + %str2 = getelementptr inbounds [6 x i8]* @hello, i32 0, i32 0 + %temp1 = call i16 @strncmp(i8* %str1, i8* %str2, i32 10) + ret i16 %temp1 +} diff --git a/test/Transforms/InstCombine/weak-symbols.ll b/test/Transforms/InstCombine/weak-symbols.ll new file mode 100644 index 00000000000..0039b5962f7 --- /dev/null +++ b/test/Transforms/InstCombine/weak-symbols.ll @@ -0,0 +1,33 @@ +; PR4738 - Test that the library call simplifier doesn't assume anything about +; weak symbols. +; +; RUN: opt < %s -instcombine -S | FileCheck %s + +@real_init = weak_odr constant [2 x i8] c"y\00" +@fake_init = weak constant [2 x i8] c"y\00" +@.str = private constant [2 x i8] c"y\00" + +define i32 @foo() nounwind { +; CHECK: define i32 @foo +; CHECK: call i32 @strcmp +; CHECK: ret i32 %temp1 + +entry: + %str1 = getelementptr inbounds [2 x i8]* @fake_init, i64 0, i64 0 + %str2 = getelementptr inbounds [2 x i8]* @.str, i64 0, i64 0 + %temp1 = call i32 @strcmp(i8* %str1, i8* %str2) nounwind readonly + ret i32 %temp1 +} + +define i32 @bar() nounwind { +; CHECK: define i32 @bar +; CHECK: ret i32 0 + +entry: + %str1 = getelementptr inbounds [2 x i8]* @real_init, i64 0, i64 0 + %str2 = getelementptr inbounds [2 x i8]* @.str, i64 0, i64 0 + %temp1 = call i32 @strcmp(i8* %str1, i8* %str2) nounwind readonly + ret i32 %temp1 +} + +declare i32 @strcmp(i8*, i8*) nounwind readonly diff --git a/test/Transforms/SimplifyLibCalls/StrCmp.ll b/test/Transforms/SimplifyLibCalls/StrCmp.ll deleted file mode 100644 index 60854d76c97..00000000000 --- a/test/Transforms/SimplifyLibCalls/StrCmp.ll +++ /dev/null @@ -1,65 +0,0 @@ -; Test that the StrCmpOptimizer works correctly -; RUN: opt < %s -simplify-libcalls -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" ; <[6 x i8]*> [#uses=1] -@hell = constant [5 x i8] c"hell\00" ; <[5 x i8]*> [#uses=1] -@bell = constant [5 x i8] c"bell\00" ; <[5 x i8]*> [#uses=1] -@null = constant [1 x i8] zeroinitializer ; <[1 x i8]*> [#uses=1] - -declare i32 @strcmp(i8*, i8*) - -; strcmp("", x) -> -*x -define i32 @test1(i8* %str) { - %temp1 = call i32 @strcmp(i8* getelementptr inbounds ([1 x i8]* @null, i32 0, i32 0), i8* %str) - ret i32 %temp1 - ; CHECK: @test1 - ; CHECK: %strcmpload = load i8* %str - ; CHECK: %1 = zext i8 %strcmpload to i32 - ; CHECK: %temp1 = sub i32 0, %1 - ; CHECK: ret i32 %temp1 -} - -; strcmp(x, "") -> *x -define i32 @test2(i8* %str) { - %temp1 = call i32 @strcmp(i8* %str, i8* getelementptr inbounds ([1 x i8]* @null, i32 0, i32 0)) - ret i32 %temp1 - ; CHECK: @test2 - ; CHECK: %strcmpload = load i8* %str - ; CHECK: %temp1 = zext i8 %strcmpload to i32 - ; CHECK: ret i32 %temp1 -} - -; strcmp(x, y) -> cnst -define i32 @test3() { - %temp1 = call i32 @strcmp(i8* getelementptr inbounds ([5 x i8]* @hell, i32 0, i32 0), i8* getelementptr inbounds ([6 x i8]* @hello, i32 0, i32 0)) - ret i32 %temp1 - ; CHECK: @test3 - ; CHECK: ret i32 -1 -} -define i32 @test4() { - %temp1 = call i32 @strcmp(i8* getelementptr inbounds ([5 x i8]* @hell, i32 0, i32 0), i8* getelementptr inbounds ([1 x i8]* @null, i32 0, i32 0)) - ret i32 %temp1 - ; CHECK: @test4 - ; CHECK: ret i32 1 -} - -; strcmp(x, y) -> memcmp(x, y, ) -; (This transform is rather difficult to trigger in a useful manner) -define i32 @test5(i1 %b) { - %sel = select i1 %b, i8* getelementptr inbounds ([5 x i8]* @hell, i32 0, i32 0), i8* getelementptr inbounds ([5 x i8]* @bell, i32 0, i32 0) - %temp1 = call i32 @strcmp(i8* getelementptr inbounds ([6 x i8]* @hello, i32 0, i32 0), i8* %sel) - ret i32 %temp1 - ; CHECK: @test5 - ; CHECK: %memcmp = call i32 @memcmp(i8* getelementptr inbounds ([6 x i8]* @hello, i32 0, i32 0), i8* %sel, i32 5) - ; CHECK: ret i32 %memcmp -} - -; strcmp(x,x) -> 0 -define i32 @test6(i8* %str) { - %temp1 = call i32 @strcmp(i8* %str, i8* %str) - ret i32 %temp1 - ; CHECK: @test6 - ; CHECK: ret i32 0 -} diff --git a/test/Transforms/SimplifyLibCalls/StrNCmp.ll b/test/Transforms/SimplifyLibCalls/StrNCmp.ll deleted file mode 100644 index 0b2a501a3c8..00000000000 --- a/test/Transforms/SimplifyLibCalls/StrNCmp.ll +++ /dev/null @@ -1,78 +0,0 @@ -; Test that the StrCmpOptimizer works correctly -; RUN: opt < %s -simplify-libcalls -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" ; <[6 x i8]*> [#uses=1] -@hell = constant [5 x i8] c"hell\00" ; <[5 x i8]*> [#uses=1] -@bell = constant [5 x i8] c"bell\00" ; <[5 x i8]*> [#uses=1] -@null = constant [1 x i8] zeroinitializer ; <[1 x i8]*> [#uses=1] - -declare i32 @strncmp(i8*, i8*, i32) - -; strcmp("", x) -> -*x -define i32 @test1(i8* %str) { - %temp1 = call i32 @strncmp(i8* getelementptr inbounds ([1 x i8]* @null, i32 0, i32 0), i8* %str, i32 10) - ret i32 %temp1 - ; CHECK: @test1 - ; CHECK: %strcmpload = load i8* %str - ; CHECK: %1 = zext i8 %strcmpload to i32 - ; CHECK: %temp1 = sub i32 0, %1 - ; CHECK: ret i32 %temp1 -} - -; strcmp(x, "") -> *x -define i32 @test2(i8* %str) { - %temp1 = call i32 @strncmp(i8* %str, i8* getelementptr inbounds ([1 x i8]* @null, i32 0, i32 0), i32 10) - ret i32 %temp1 - ; CHECK: @test2 - ; CHECK: %strcmpload = load i8* %str - ; CHECK: %temp1 = zext i8 %strcmpload to i32 - ; CHECK: ret i32 %temp1 -} - -; strncmp(x, y, n) -> cnst -define i32 @test3() { - %temp1 = call i32 @strncmp(i8* getelementptr inbounds ([5 x i8]* @hell, i32 0, i32 0), i8* getelementptr inbounds ([6 x i8]* @hello, i32 0, i32 0), i32 10) - ret i32 %temp1 - ; CHECK: @test3 - ; CHECK: ret i32 -1 -} -define i32 @test4() { - %temp1 = call i32 @strncmp(i8* getelementptr inbounds ([5 x i8]* @hell, i32 0, i32 0), i8* getelementptr inbounds ([1 x i8]* @null, i32 0, i32 0), i32 10) - ret i32 %temp1 - ; CHECK: @test4 - ; CHECK: ret i32 1 -} -define i32 @test5() { - %temp1 = call i32 @strncmp(i8* getelementptr inbounds ([5 x i8]* @hell, i32 0, i32 0), i8* getelementptr inbounds ([6 x i8]* @hello, i32 0, i32 0), i32 4) - ret i32 %temp1 - ; CHECK: @test5 - ; CHECK: ret i32 0 -} - -; strncmp(x,y,1) -> memcmp(x,y,1) -define i32 @test6(i8* %str1, i8* %str2) { - %temp1 = call i32 @strncmp(i8* %str1, i8* %str2, i32 1) - ret i32 %temp1 - ; CHECK: @test6 - ; CHECK: load i8* - ; CHECK: load i8* - ; CHECK: sub i32 -} - -; strncmp(x,y,0) -> 0 -define i32 @test7(i8* %str1, i8* %str2) { - %temp1 = call i32 @strncmp(i8* %str1, i8* %str2, i32 0) - ret i32 %temp1 - ; CHECK: @test7 - ; CHECK: ret i32 0 -} - -; strncmp(x,x,n) -> 0 -define i32 @test8(i8* %str, i32 %n) { - %temp1 = call i32 @strncmp(i8* %str, i8* %str, i32 %n) - ret i32 %temp1 - ; CHECK: @test8 - ; CHECK: ret i32 0 -} diff --git a/test/Transforms/SimplifyLibCalls/weak-symbols.ll b/test/Transforms/SimplifyLibCalls/weak-symbols.ll deleted file mode 100644 index 5875b211f77..00000000000 --- a/test/Transforms/SimplifyLibCalls/weak-symbols.ll +++ /dev/null @@ -1,26 +0,0 @@ -; RUN: opt < %s -simplify-libcalls -S | FileCheck %s -; PR4738 - -; SimplifyLibcalls shouldn't assume anything about weak symbols. - -@real_init = weak_odr constant [2 x i8] c"y\00" -@fake_init = weak constant [2 x i8] c"y\00" -@.str = private constant [2 x i8] c"y\00" - -; CHECK: define i32 @foo -; CHECK: call i32 @strcmp -define i32 @foo() nounwind { -entry: - %t0 = call i32 @strcmp(i8* getelementptr inbounds ([2 x i8]* @fake_init, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8]* @.str, i64 0, i64 0)) nounwind readonly - ret i32 %t0 -} - -; CHECK: define i32 @bar -; CHECK: ret i32 0 -define i32 @bar() nounwind { -entry: - %t0 = call i32 @strcmp(i8* getelementptr inbounds ([2 x i8]* @real_init, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8]* @.str, i64 0, i64 0)) nounwind readonly - ret i32 %t0 -} - -declare i32 @strcmp(i8*, i8*) nounwind readonly