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
This commit is contained in:
Meador Inge 2012-10-31 04:29:58 +00:00
parent c5c970ee85
commit 08684d1f06
5 changed files with 128 additions and 65 deletions

View File

@ -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<LibCallOptimization*> 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;

View File

@ -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) {

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}