From: Benjamin Kramer Date: Wed, 29 Sep 2010 21:50:51 +0000 (+0000) Subject: Teach SimplifyLibCalls how to optimize strrchr. X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=06f25cfb334d6630fc5018260a78129f4b956bad;p=oota-llvm.git Teach SimplifyLibCalls how to optimize strrchr. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@115091 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Transforms/Scalar/SimplifyLibCalls.cpp b/lib/Transforms/Scalar/SimplifyLibCalls.cpp index d7ce53f3671..fffd3250738 100644 --- a/lib/Transforms/Scalar/SimplifyLibCalls.cpp +++ b/lib/Transforms/Scalar/SimplifyLibCalls.cpp @@ -271,6 +271,47 @@ struct StrChrOpt : public LibCallOptimization { } }; +//===---------------------------------------===// +// 'strrchr' Optimizations + +struct StrRChrOpt : public LibCallOptimization { + virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) { + // Verify the "strrchr" function prototype. + const FunctionType *FT = Callee->getFunctionType(); + if (FT->getNumParams() != 2 || + FT->getReturnType() != Type::getInt8PtrTy(*Context) || + FT->getParamType(0) != FT->getReturnType()) + return 0; + + Value *SrcStr = CI->getArgOperand(0); + ConstantInt *CharC = dyn_cast(CI->getArgOperand(1)); + + // Cannot fold anything if we're not looking for a constant. + if (!CharC) + return 0; + + std::string Str; + if (!GetConstantStringInfo(SrcStr, Str)) { + // strrchr(s, 0) -> strchr(s, 0) + if (TD && CharC->isZero()) + return EmitStrChr(SrcStr, '\0', B, TD); + return 0; + } + + // strrchr can find the nul character. + Str += '\0'; + + // Compute the offset. + size_t I = Str.rfind(CharC->getSExtValue()); + if (I == std::string::npos) // Didn't find the char. Return null. + return Constant::getNullValue(CI->getType()); + + // strrchr(s+n,c) -> gep(s+n+i,c) + Value *Idx = ConstantInt::get(Type::getInt64Ty(*Context), I); + return B.CreateGEP(SrcStr, Idx, "strrchr"); + } +}; + //===---------------------------------------===// // 'strcmp' Optimizations @@ -1220,8 +1261,8 @@ namespace { class SimplifyLibCalls : public FunctionPass { StringMap Optimizations; // String and Memory LibCall Optimizations - StrCatOpt StrCat; StrNCatOpt StrNCat; StrChrOpt StrChr; StrCmpOpt StrCmp; - StrNCmpOpt StrNCmp; StrCpyOpt StrCpy; StrCpyOpt StrCpyChk; + StrCatOpt StrCat; StrNCatOpt StrNCat; StrChrOpt StrChr; StrRChrOpt StrRChr; + StrCmpOpt StrCmp; StrNCmpOpt StrNCmp; StrCpyOpt StrCpy; StrCpyOpt StrCpyChk; StrNCpyOpt StrNCpy; StrLenOpt StrLen; StrToOpt StrTo; StrStrOpt StrStr; MemCmpOpt MemCmp; MemCpyOpt MemCpy; MemMoveOpt MemMove; MemSetOpt MemSet; @@ -1269,6 +1310,7 @@ void SimplifyLibCalls::InitOptimizations() { Optimizations["strcat"] = &StrCat; Optimizations["strncat"] = &StrNCat; Optimizations["strchr"] = &StrChr; + Optimizations["strrchr"] = &StrRChr; Optimizations["strcmp"] = &StrCmp; Optimizations["strncmp"] = &StrNCmp; Optimizations["strcpy"] = &StrCpy; @@ -2173,10 +2215,6 @@ bool SimplifyLibCalls::doInitialization(Module &M) { // stpcpy: // * stpcpy(str, "literal") -> // llvm.memcpy(str,"literal",strlen("literal")+1,1) -// strrchr: -// * strrchr(s,c) -> reverse_offset_of_in(c,s) -// (if c is a constant integer and s is a constant string) -// * strrchr(s1,0) -> strchr(s1,0) // // strpbrk: // * strpbrk(s,a) -> offset_in_for(s,a) diff --git a/test/Transforms/SimplifyLibCalls/StrRChr.ll b/test/Transforms/SimplifyLibCalls/StrRChr.ll new file mode 100644 index 00000000000..2259fc0289f --- /dev/null +++ b/test/Transforms/SimplifyLibCalls/StrRChr.ll @@ -0,0 +1,23 @@ +; Test that the StrRChrOptimizer works correctly +; RUN: opt < %s -simplify-libcalls -S | FileCheck %s + +target datalayout = "-p:64:64:64" + +@hello = constant [14 x i8] c"hello world\5Cn\00" +@null = constant [1 x i8] zeroinitializer + +declare i8* @strrchr(i8*, i32) + +define void @foo(i8* %bar) { + %hello_p = getelementptr [14 x i8]* @hello, i32 0, i32 0 + %null_p = getelementptr [1 x i8]* @null, i32 0, i32 0 + %world = call i8* @strrchr(i8* %hello_p, i32 119) +; CHECK: getelementptr i8* %hello_p, i64 6 + %ignore = call i8* @strrchr(i8* %null_p, i32 119) +; CHECK-NOT: call i8* strrchr + %null = call i8* @strrchr(i8* %hello_p, i32 0) +; CHECK: getelementptr i8* %hello_p, i64 13 + %strchr = call i8* @strrchr(i8* %bar, i32 0) +; CHECK: call i8* @strchr(i8* %bar, i32 0) + ret void +}