From: Meador Inge Date: Wed, 31 Oct 2012 04:29:58 +0000 (+0000) Subject: instcombine: Migrate strpbrk optimizations X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=08684d1f069711692502d091669a6031c31cdd4a;p=oota-llvm.git instcombine: Migrate strpbrk optimizations This patch migrates the strpbrk optimizations from the simplify-libcalls pass into the instcombine library call simplifier. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@167105 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Transforms/Scalar/SimplifyLibCalls.cpp b/lib/Transforms/Scalar/SimplifyLibCalls.cpp index a0235c15b61..7002eb41197 100644 --- a/lib/Transforms/Scalar/SimplifyLibCalls.cpp +++ b/lib/Transforms/Scalar/SimplifyLibCalls.cpp @@ -118,44 +118,6 @@ static bool IsOnlyUsedInEqualityComparison(Value *V, Value *With) { //===----------------------------------------------------------------------===// namespace { -//===---------------------------------------===// -// 'strpbrk' Optimizations - -struct StrPBrkOpt : public LibCallOptimization { - virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) { - FunctionType *FT = Callee->getFunctionType(); - if (FT->getNumParams() != 2 || - FT->getParamType(0) != B.getInt8PtrTy() || - FT->getParamType(1) != FT->getParamType(0) || - FT->getReturnType() != FT->getParamType(0)) - return 0; - - StringRef S1, S2; - bool HasS1 = getConstantStringInfo(CI->getArgOperand(0), S1); - bool HasS2 = getConstantStringInfo(CI->getArgOperand(1), S2); - - // strpbrk(s, "") -> NULL - // strpbrk("", s) -> NULL - if ((HasS1 && S1.empty()) || (HasS2 && S2.empty())) - return Constant::getNullValue(CI->getType()); - - // Constant folding. - if (HasS1 && HasS2) { - size_t I = S1.find_first_of(S2); - if (I == std::string::npos) // No match. - return Constant::getNullValue(CI->getType()); - - return B.CreateGEP(CI->getArgOperand(0), B.getInt64(I), "strpbrk"); - } - - // strpbrk(s, "a") -> strchr(s, 'a') - if (TD && HasS2 && S2.size() == 1) - return EmitStrChr(CI->getArgOperand(0), S2[0], B, TD, TLI); - - return 0; - } -}; - //===---------------------------------------===// // 'strto*' Optimizations. This handles strtol, strtod, strtof, strtoul, etc. @@ -1104,7 +1066,6 @@ namespace { StringMap Optimizations; // String and Memory LibCall Optimizations - StrPBrkOpt StrPBrk; StrToOpt StrTo; StrSpnOpt StrSpn; StrCSpnOpt StrCSpn; StrStrOpt StrStr; MemCmpOpt MemCmp; MemCpyOpt MemCpy; MemMoveOpt MemMove; MemSetOpt MemSet; // Math Library Optimizations @@ -1173,7 +1134,6 @@ void SimplifyLibCalls::AddOpt(LibFunc::Func F1, LibFunc::Func F2, /// we know. void SimplifyLibCalls::InitOptimizations() { // String and Memory LibCall Optimizations - Optimizations["strpbrk"] = &StrPBrk; Optimizations["strtol"] = &StrTo; Optimizations["strtod"] = &StrTo; Optimizations["strtof"] = &StrTo; diff --git a/lib/Transforms/Utils/SimplifyLibCalls.cpp b/lib/Transforms/Utils/SimplifyLibCalls.cpp index 658e7c34287..1aac8c5745d 100644 --- a/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ b/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -717,6 +717,41 @@ struct StrLenOpt : public LibCallOptimization { } }; +struct StrPBrkOpt : public LibCallOptimization { + virtual Value *callOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) { + FunctionType *FT = Callee->getFunctionType(); + if (FT->getNumParams() != 2 || + FT->getParamType(0) != B.getInt8PtrTy() || + FT->getParamType(1) != FT->getParamType(0) || + FT->getReturnType() != FT->getParamType(0)) + return 0; + + StringRef S1, S2; + bool HasS1 = getConstantStringInfo(CI->getArgOperand(0), S1); + bool HasS2 = getConstantStringInfo(CI->getArgOperand(1), S2); + + // strpbrk(s, "") -> NULL + // strpbrk("", s) -> NULL + if ((HasS1 && S1.empty()) || (HasS2 && S2.empty())) + return Constant::getNullValue(CI->getType()); + + // Constant folding. + if (HasS1 && HasS2) { + size_t I = S1.find_first_of(S2); + if (I == std::string::npos) // No match. + return Constant::getNullValue(CI->getType()); + + return B.CreateGEP(CI->getArgOperand(0), B.getInt64(I), "strpbrk"); + } + + // strpbrk(s, "a") -> strchr(s, 'a') + if (TD && HasS2 && S2.size() == 1) + return EmitStrChr(CI->getArgOperand(0), S2[0], B, TD, TLI); + + return 0; + } +}; + } // End anonymous namespace. namespace llvm { @@ -745,6 +780,7 @@ class LibCallSimplifierImpl { StpCpyOpt StpCpy; StrNCpyOpt StrNCpy; StrLenOpt StrLen; + StrPBrkOpt StrPBrk; void initOptimizations(); public: @@ -777,6 +813,7 @@ void LibCallSimplifierImpl::initOptimizations() { Optimizations["stpcpy"] = &StpCpy; Optimizations["strncpy"] = &StrNCpy; Optimizations["strlen"] = &StrLen; + Optimizations["strpbrk"] = &StrPBrk; } Value *LibCallSimplifierImpl::optimizeCall(CallInst *CI) { diff --git a/test/Transforms/InstCombine/strpbrk-1.ll b/test/Transforms/InstCombine/strpbrk-1.ll new file mode 100644 index 00000000000..a5d0d86501b --- /dev/null +++ b/test/Transforms/InstCombine/strpbrk-1.ll @@ -0,0 +1,68 @@ +; Test that the strpbrk 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 [12 x i8] c"hello world\00" +@w = constant [2 x i8] c"w\00" +@null = constant [1 x i8] zeroinitializer + +declare i8* @strpbrk(i8*, i8*) + +; Check strpbrk(s, "") -> NULL. + +define i8* @test_simplify1(i8* %str) { +; CHECK: @test_simplify1 + %pat = getelementptr [1 x i8]* @null, i32 0, i32 0 + + %ret = call i8* @strpbrk(i8* %str, i8* %pat) + ret i8* %ret +; CHECK-NEXT: ret i8* null +} + +; Check strpbrk("", s) -> NULL. + +define i8* @test_simplify2(i8* %pat) { +; CHECK: @test_simplify2 + %str = getelementptr [1 x i8]* @null, i32 0, i32 0 + + %ret = call i8* @strpbrk(i8* %str, i8* %pat) + ret i8* %ret +; CHECK-NEXT: ret i8* null +} + +; Check strpbrk(s1, s2), where s1 and s2 are constants. + +define i8* @test_simplify3() { +; CHECK: @test_simplify3 + %str = getelementptr [12 x i8]* @hello, i32 0, i32 0 + %pat = getelementptr [2 x i8]* @w, i32 0, i32 0 + + %ret = call i8* @strpbrk(i8* %str, i8* %pat) + ret i8* %ret +; CHECK-NEXT: ret i8* getelementptr inbounds ([12 x i8]* @hello, i32 0, i32 6) +} + +; Check strpbrk(s, "a") -> strchr(s, 'a'). + +define i8* @test_simplify4(i8* %str) { +; CHECK: @test_simplify4 + %pat = getelementptr [2 x i8]* @w, i32 0, i32 0 + + %ret = call i8* @strpbrk(i8* %str, i8* %pat) +; CHECK-NEXT: [[VAR:%[a-z]+]] = call i8* @strchr(i8* %str, i32 119) + ret i8* %ret +; CHECK-NEXT: ret i8* [[VAR]] +} + +; Check cases that shouldn't be simplified. + +define i8* @test_no_simplify1(i8* %str, i8* %pat) { +; CHECK: @test_no_simplify1 + + %ret = call i8* @strpbrk(i8* %str, i8* %pat) +; CHECK-NEXT: %ret = call i8* @strpbrk(i8* %str, i8* %pat) + ret i8* %ret +; CHECK-NEXT: ret i8* %ret +} diff --git a/test/Transforms/InstCombine/strpbrk-2.ll b/test/Transforms/InstCombine/strpbrk-2.ll new file mode 100644 index 00000000000..31ac2905df2 --- /dev/null +++ b/test/Transforms/InstCombine/strpbrk-2.ll @@ -0,0 +1,23 @@ +; Test that the strpbrk 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 [12 x i8] c"hello world\00" +@w = constant [2 x i8] c"w\00" + +declare i16* @strpbrk(i8*, i8*) + +; Check that 'strpbrk' functions with the wrong prototype aren't simplified. + +define i16* @test_no_simplify1() { +; CHECK: @test_no_simplify1 + %str = getelementptr [12 x i8]* @hello, i32 0, i32 0 + %pat = getelementptr [2 x i8]* @w, i32 0, i32 0 + + %ret = call i16* @strpbrk(i8* %str, i8* %pat) +; CHECK-NEXT: %ret = call i16* @strpbrk + ret i16* %ret +; CHECK-NEXT: ret i16* %ret +} diff --git a/test/Transforms/SimplifyLibCalls/StrPBrk.ll b/test/Transforms/SimplifyLibCalls/StrPBrk.ll deleted file mode 100644 index 29c3b7477b4..00000000000 --- a/test/Transforms/SimplifyLibCalls/StrPBrk.ll +++ /dev/null @@ -1,25 +0,0 @@ -; RUN: opt < %s -simplify-libcalls -S | FileCheck %s - -target datalayout = "-p:64:64:64" - -@hello = constant [12 x i8] c"hello world\00" -@w = constant [2 x i8] c"w\00" -@null = constant [1 x i8] zeroinitializer - -declare i8* @strpbrk(i8*, i8*) - -define void @test(i8* %s1, i8* %s2) { - %hello_p = getelementptr [12 x i8]* @hello, i32 0, i32 0 - %w_p = getelementptr [2 x i8]* @w, i32 0, i32 0 - %null_p = getelementptr [1 x i8]* @null, i32 0, i32 0 - %test1 = call i8* @strpbrk(i8* %null_p, i8* %s2) - %test2 = call i8* @strpbrk(i8* %s1, i8* %null_p) -; CHECK-NOT: call i8* @strpbrk - %test3 = call i8* @strpbrk(i8* %s1, i8* %w_p) -; CHECK: call i8* @strchr(i8* %s1, i32 119) - %test4 = call i8* @strpbrk(i8* %hello_p, i8* %w_p) -; CHECK: getelementptr i8* %hello_p, i64 6 - %test5 = call i8* @strpbrk(i8* %s1, i8* %s2) -; CHECK: call i8* @strpbrk(i8* %s1, i8* %s2) - ret void -}