[llvm-commits] [PATCH 3/3] instcombine: Migrate strchr and strrchr optimizations

Eric Christopher echristo at gmail.com
Fri Oct 12 15:21:30 PDT 2012


Looks mechanical assuming the earlier patch right?

-eric

On Mon, Oct 8, 2012 at 8:25 AM, Meador Inge <meadori at codesourcery.com> wrote:
> This patch migrates the strchr and strrchr optimizations from the
> simplify-libcalls pass into the instcombine library call simplifier.
> ---
>  lib/Transforms/Scalar/SimplifyLibCalls.cpp  |   91 ---------------------------
>  lib/Transforms/Utils/SimplifyLibCalls.cpp   |   86 +++++++++++++++++++++++++
>  test/Transforms/InstCombine/strchr-1.ll     |   54 ++++++++++++++++
>  test/Transforms/InstCombine/strchr-2.ll     |   21 +++++++
>  test/Transforms/InstCombine/strrchr-1.ll    |   54 ++++++++++++++++
>  test/Transforms/InstCombine/strrchr-2.ll    |   21 +++++++
>  test/Transforms/SimplifyLibCalls/StrChr.ll  |   26 --------
>  test/Transforms/SimplifyLibCalls/StrRChr.ll |   23 -------
>  8 files changed, 236 insertions(+), 140 deletions(-)
>  create mode 100644 test/Transforms/InstCombine/strchr-1.ll
>  create mode 100644 test/Transforms/InstCombine/strchr-2.ll
>  create mode 100644 test/Transforms/InstCombine/strrchr-1.ll
>  create mode 100644 test/Transforms/InstCombine/strrchr-2.ll
>  delete mode 100644 test/Transforms/SimplifyLibCalls/StrChr.ll
>  delete mode 100644 test/Transforms/SimplifyLibCalls/StrRChr.ll
>
> diff --git a/lib/Transforms/Scalar/SimplifyLibCalls.cpp b/lib/Transforms/Scalar/SimplifyLibCalls.cpp
> index 88586d9..7d95a02 100644
> --- a/lib/Transforms/Scalar/SimplifyLibCalls.cpp
> +++ b/lib/Transforms/Scalar/SimplifyLibCalls.cpp
> @@ -135,94 +135,6 @@ static bool IsOnlyUsedInEqualityComparison(Value *V, Value *With) {
>
>  namespace {
>  //===---------------------------------------===//
> -// 'strchr' Optimizations
> -
> -struct StrChrOpt : public LibCallOptimization {
> -  virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
> -    // Verify the "strchr" function prototype.
> -    FunctionType *FT = Callee->getFunctionType();
> -    if (FT->getNumParams() != 2 ||
> -        FT->getReturnType() != B.getInt8PtrTy() ||
> -        FT->getParamType(0) != FT->getReturnType() ||
> -        !FT->getParamType(1)->isIntegerTy(32))
> -      return 0;
> -
> -    Value *SrcStr = CI->getArgOperand(0);
> -
> -    // If the second operand is non-constant, see if we can compute the length
> -    // of the input string and turn this into memchr.
> -    ConstantInt *CharC = dyn_cast<ConstantInt>(CI->getArgOperand(1));
> -    if (CharC == 0) {
> -      // These optimizations require TargetData.
> -      if (!TD) return 0;
> -
> -      uint64_t Len = GetStringLength(SrcStr);
> -      if (Len == 0 || !FT->getParamType(1)->isIntegerTy(32))// memchr needs i32.
> -        return 0;
> -
> -      return EmitMemChr(SrcStr, CI->getArgOperand(1), // include nul.
> -                        ConstantInt::get(TD->getIntPtrType(*Context), Len),
> -                        B, TD, TLI);
> -    }
> -
> -    // Otherwise, the character is a constant, see if the first argument is
> -    // a string literal.  If so, we can constant fold.
> -    StringRef Str;
> -    if (!getConstantStringInfo(SrcStr, Str))
> -      return 0;
> -
> -    // Compute the offset, make sure to handle the case when we're searching for
> -    // zero (a weird way to spell strlen).
> -    size_t I = CharC->getSExtValue() == 0 ?
> -        Str.size() : Str.find(CharC->getSExtValue());
> -    if (I == StringRef::npos) // Didn't find the char.  strchr returns null.
> -      return Constant::getNullValue(CI->getType());
> -
> -    // strchr(s+n,c)  -> gep(s+n+i,c)
> -    return B.CreateGEP(SrcStr, B.getInt64(I), "strchr");
> -  }
> -};
> -
> -//===---------------------------------------===//
> -// 'strrchr' Optimizations
> -
> -struct StrRChrOpt : public LibCallOptimization {
> -  virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
> -    // Verify the "strrchr" function prototype.
> -    FunctionType *FT = Callee->getFunctionType();
> -    if (FT->getNumParams() != 2 ||
> -        FT->getReturnType() != B.getInt8PtrTy() ||
> -        FT->getParamType(0) != FT->getReturnType() ||
> -        !FT->getParamType(1)->isIntegerTy(32))
> -      return 0;
> -
> -    Value *SrcStr = CI->getArgOperand(0);
> -    ConstantInt *CharC = dyn_cast<ConstantInt>(CI->getArgOperand(1));
> -
> -    // Cannot fold anything if we're not looking for a constant.
> -    if (!CharC)
> -      return 0;
> -
> -    StringRef Str;
> -    if (!getConstantStringInfo(SrcStr, Str)) {
> -      // strrchr(s, 0) -> strchr(s, 0)
> -      if (TD && CharC->isZero())
> -        return EmitStrChr(SrcStr, '\0', B, TD, TLI);
> -      return 0;
> -    }
> -
> -    // Compute the offset.
> -    size_t I = CharC->getSExtValue() == 0 ?
> -        Str.size() : Str.rfind(CharC->getSExtValue());
> -    if (I == StringRef::npos) // Didn't find the char. Return null.
> -      return Constant::getNullValue(CI->getType());
> -
> -    // strrchr(s+n,c) -> gep(s+n+i,c)
> -    return B.CreateGEP(SrcStr, B.getInt64(I), "strrchr");
> -  }
> -};
> -
> -//===---------------------------------------===//
>  // 'strcmp' Optimizations
>
>  struct StrCmpOpt : public LibCallOptimization {
> @@ -1464,7 +1376,6 @@ namespace {
>
>      StringMap<LibCallOptimization*> Optimizations;
>      // String and Memory LibCall Optimizations
> -    StrChrOpt StrChr; StrRChrOpt StrRChr;
>      StrCmpOpt StrCmp; StrNCmpOpt StrNCmp;
>      StrCpyOpt StrCpy; StrCpyOpt StrCpyChk;
>      StpCpyOpt StpCpy; StpCpyOpt StpCpyChk;
> @@ -1539,8 +1450,6 @@ void SimplifyLibCalls::AddOpt(LibFunc::Func F1, LibFunc::Func F2,
>  /// we know.
>  void SimplifyLibCalls::InitOptimizations() {
>    // String and Memory LibCall Optimizations
> -  Optimizations["strchr"] = &StrChr;
> -  Optimizations["strrchr"] = &StrRChr;
>    Optimizations["strcmp"] = &StrCmp;
>    Optimizations["strncmp"] = &StrNCmp;
>    Optimizations["strcpy"] = &StrCpy;
> diff --git a/lib/Transforms/Utils/SimplifyLibCalls.cpp b/lib/Transforms/Utils/SimplifyLibCalls.cpp
> index f4e6af8..0ed780a 100644
> --- a/lib/Transforms/Utils/SimplifyLibCalls.cpp
> +++ b/lib/Transforms/Utils/SimplifyLibCalls.cpp
> @@ -320,6 +320,88 @@ struct StrNCatOpt : public StrCatOpt {
>    }
>  };
>
> +struct StrChrOpt : public LibCallOptimization {
> +  virtual Value *callOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
> +    // Verify the "strchr" function prototype.
> +    FunctionType *FT = Callee->getFunctionType();
> +    if (FT->getNumParams() != 2 ||
> +        FT->getReturnType() != B.getInt8PtrTy() ||
> +        FT->getParamType(0) != FT->getReturnType() ||
> +        !FT->getParamType(1)->isIntegerTy(32))
> +      return 0;
> +
> +    Value *SrcStr = CI->getArgOperand(0);
> +
> +    // If the second operand is non-constant, see if we can compute the length
> +    // of the input string and turn this into memchr.
> +    ConstantInt *CharC = dyn_cast<ConstantInt>(CI->getArgOperand(1));
> +    if (CharC == 0) {
> +      // These optimizations require TargetData.
> +      if (!TD) return 0;
> +
> +      uint64_t Len = GetStringLength(SrcStr);
> +      if (Len == 0 || !FT->getParamType(1)->isIntegerTy(32))// memchr needs i32.
> +        return 0;
> +
> +      return EmitMemChr(SrcStr, CI->getArgOperand(1), // include nul.
> +                        ConstantInt::get(TD->getIntPtrType(*Context), Len),
> +                        B, TD, TLI);
> +    }
> +
> +    // Otherwise, the character is a constant, see if the first argument is
> +    // a string literal.  If so, we can constant fold.
> +    StringRef Str;
> +    if (!getConstantStringInfo(SrcStr, Str))
> +      return 0;
> +
> +    // Compute the offset, make sure to handle the case when we're searching for
> +    // zero (a weird way to spell strlen).
> +    size_t I = CharC->getSExtValue() == 0 ?
> +        Str.size() : Str.find(CharC->getSExtValue());
> +    if (I == StringRef::npos) // Didn't find the char.  strchr returns null.
> +      return Constant::getNullValue(CI->getType());
> +
> +    // strchr(s+n,c)  -> gep(s+n+i,c)
> +    return B.CreateGEP(SrcStr, B.getInt64(I), "strchr");
> +  }
> +};
> +
> +struct StrRChrOpt : public LibCallOptimization {
> +  virtual Value *callOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
> +    // Verify the "strrchr" function prototype.
> +    FunctionType *FT = Callee->getFunctionType();
> +    if (FT->getNumParams() != 2 ||
> +        FT->getReturnType() != B.getInt8PtrTy() ||
> +        FT->getParamType(0) != FT->getReturnType() ||
> +        !FT->getParamType(1)->isIntegerTy(32))
> +      return 0;
> +
> +    Value *SrcStr = CI->getArgOperand(0);
> +    ConstantInt *CharC = dyn_cast<ConstantInt>(CI->getArgOperand(1));
> +
> +    // Cannot fold anything if we're not looking for a constant.
> +    if (!CharC)
> +      return 0;
> +
> +    StringRef Str;
> +    if (!getConstantStringInfo(SrcStr, Str)) {
> +      // strrchr(s, 0) -> strchr(s, 0)
> +      if (TD && CharC->isZero())
> +        return EmitStrChr(SrcStr, '\0', B, TD, TLI);
> +      return 0;
> +    }
> +
> +    // Compute the offset.
> +    size_t I = CharC->getSExtValue() == 0 ?
> +        Str.size() : Str.rfind(CharC->getSExtValue());
> +    if (I == StringRef::npos) // Didn't find the char. Return null.
> +      return Constant::getNullValue(CI->getType());
> +
> +    // strrchr(s+n,c) -> gep(s+n+i,c)
> +    return B.CreateGEP(SrcStr, B.getInt64(I), "strrchr");
> +  }
> +};
> +
>  } // End anonymous namespace.
>
>  namespace llvm {
> @@ -340,6 +422,8 @@ class LibCallSimplifierImpl {
>    // String and memory library call optimizations.
>    StrCatOpt StrCat;
>    StrNCatOpt StrNCat;
> +  StrChrOpt StrChr;
> +  StrRChrOpt StrRChr;
>
>    void initOptimizations();
>  public:
> @@ -364,6 +448,8 @@ void LibCallSimplifierImpl::initOptimizations() {
>    // String and memory library call optimizations.
>    Optimizations["strcat"] = &StrCat;
>    Optimizations["strncat"] = &StrNCat;
> +  Optimizations["strchr"] = &StrChr;
> +  Optimizations["strrchr"] = &StrRChr;
>  }
>
>  Value *LibCallSimplifierImpl::optimizeCall(CallInst *CI) {
> diff --git a/test/Transforms/InstCombine/strchr-1.ll b/test/Transforms/InstCombine/strchr-1.ll
> new file mode 100644
> index 0000000..5efab9e
> --- /dev/null
> +++ b/test/Transforms/InstCombine/strchr-1.ll
> @@ -0,0 +1,54 @@
> +; Test that the strchr 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"
> +
> + at hello = constant [14 x i8] c"hello world\5Cn\00"
> + at null = constant [1 x i8] zeroinitializer
> + at chp = global i8* zeroinitializer
> +
> +declare i8* @strchr(i8*, i32)
> +
> +define void @test_simplify1() {
> +; CHECK: store i8* getelementptr inbounds ([14 x i8]* @hello, i32 0, i32 6)
> +; CHECK-NOT: call i8* @strchr
> +; CHECK: ret void
> +
> +  %str = getelementptr [14 x i8]* @hello, i32 0, i32 0
> +  %dst = call i8* @strchr(i8* %str, i32 119)
> +  store i8* %dst, i8** @chp
> +  ret void
> +}
> +
> +define void @test_simplify2() {
> +; CHECK: store i8* null, i8** @chp, align 4
> +; CHECK-NOT: call i8* @strchr
> +; CHECK: ret void
> +
> +  %str = getelementptr [1 x i8]* @null, i32 0, i32 0
> +  %dst = call i8* @strchr(i8* %str, i32 119)
> +  store i8* %dst, i8** @chp
> +  ret void
> +}
> +
> +define void @test_simplify3() {
> +; CHECK: store i8* getelementptr inbounds ([14 x i8]* @hello, i32 0, i32 13)
> +; CHECK-NOT: call i8* @strchr
> +; CHECK: ret void
> +
> +  %src = getelementptr [14 x i8]* @hello, i32 0, i32 0
> +  %dst = call i8* @strchr(i8* %src, i32 0)
> +  store i8* %dst, i8** @chp
> +  ret void
> +}
> +
> +define void @test_simplify4(i32 %chr) {
> +; CHECK: call i8* @memchr
> +; CHECK-NOT: call i8* @strchr
> +; CHECK: ret void
> +
> +  %src = getelementptr [14 x i8]* @hello, i32 0, i32 0
> +  %dst = call i8* @strchr(i8* %src, i32 %chr)
> +  store i8* %dst, i8** @chp
> +  ret void
> +}
> diff --git a/test/Transforms/InstCombine/strchr-2.ll b/test/Transforms/InstCombine/strchr-2.ll
> new file mode 100644
> index 0000000..35bbd23
> --- /dev/null
> +++ b/test/Transforms/InstCombine/strchr-2.ll
> @@ -0,0 +1,21 @@
> +; Test that the strchr libcall 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"
> +
> + at hello = constant [14 x i8] c"hello world\5Cn\00"
> + at chr = global i8 zeroinitializer
> +
> +declare i8 @strchr(i8*, i32)
> +
> +define void @test_nosimplify1() {
> +; CHECK: test_nosimplify1
> +; CHECK: call i8 @strchr
> +; CHECK: ret void
> +
> +  %str = getelementptr [14 x i8]* @hello, i32 0, i32 0
> +  %dst = call i8 @strchr(i8* %str, i32 119)
> +  store i8 %dst, i8* @chr
> +  ret void
> +}
> diff --git a/test/Transforms/InstCombine/strrchr-1.ll b/test/Transforms/InstCombine/strrchr-1.ll
> new file mode 100644
> index 0000000..854ce45
> --- /dev/null
> +++ b/test/Transforms/InstCombine/strrchr-1.ll
> @@ -0,0 +1,54 @@
> +; Test that the strrchr 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"
> +
> + at hello = constant [14 x i8] c"hello world\5Cn\00"
> + at null = constant [1 x i8] zeroinitializer
> + at chp = global i8* zeroinitializer
> +
> +declare i8* @strrchr(i8*, i32)
> +
> +define void @test_simplify1() {
> +; CHECK: store i8* getelementptr inbounds ([14 x i8]* @hello, i32 0, i32 6)
> +; CHECK-NOT: call i8* @strrchr
> +; CHECK: ret void
> +
> +  %str = getelementptr [14 x i8]* @hello, i32 0, i32 0
> +  %dst = call i8* @strrchr(i8* %str, i32 119)
> +  store i8* %dst, i8** @chp
> +  ret void
> +}
> +
> +define void @test_simplify2() {
> +; CHECK: store i8* null, i8** @chp, align 4
> +; CHECK-NOT: call i8* @strrchr
> +; CHECK: ret void
> +
> +  %str = getelementptr [1 x i8]* @null, i32 0, i32 0
> +  %dst = call i8* @strrchr(i8* %str, i32 119)
> +  store i8* %dst, i8** @chp
> +  ret void
> +}
> +
> +define void @test_simplify3() {
> +; CHECK: store i8* getelementptr inbounds ([14 x i8]* @hello, i32 0, i32 13)
> +; CHECK-NOT: call i8* @strrchr
> +; CHECK: ret void
> +
> +  %src = getelementptr [14 x i8]* @hello, i32 0, i32 0
> +  %dst = call i8* @strrchr(i8* %src, i32 0)
> +  store i8* %dst, i8** @chp
> +  ret void
> +}
> +
> +define void @test_nosimplify1(i32 %chr) {
> +; CHECK: @test_nosimplify1
> +; CHECK: call i8* @strrchr
> +; CHECK: ret void
> +
> +  %src = getelementptr [14 x i8]* @hello, i32 0, i32 0
> +  %dst = call i8* @strrchr(i8* %src, i32 %chr)
> +  store i8* %dst, i8** @chp
> +  ret void
> +}
> diff --git a/test/Transforms/InstCombine/strrchr-2.ll b/test/Transforms/InstCombine/strrchr-2.ll
> new file mode 100644
> index 0000000..1974f6c
> --- /dev/null
> +++ b/test/Transforms/InstCombine/strrchr-2.ll
> @@ -0,0 +1,21 @@
> +; Test that the strrchr libcall 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"
> +
> + at hello = constant [14 x i8] c"hello world\5Cn\00"
> + at chr = global i8 zeroinitializer
> +
> +declare i8 @strrchr(i8*, i32)
> +
> +define void @test_nosimplify1() {
> +; CHECK: test_nosimplify1
> +; CHECK: call i8 @strrchr
> +; CHECK: ret void
> +
> +  %str = getelementptr [14 x i8]* @hello, i32 0, i32 0
> +  %dst = call i8 @strrchr(i8* %str, i32 119)
> +  store i8 %dst, i8* @chr
> +  ret void
> +}
> diff --git a/test/Transforms/SimplifyLibCalls/StrChr.ll b/test/Transforms/SimplifyLibCalls/StrChr.ll
> deleted file mode 100644
> index eaabeb2..0000000
> --- a/test/Transforms/SimplifyLibCalls/StrChr.ll
> +++ /dev/null
> @@ -1,26 +0,0 @@
> -; Test that the StrChrOptimizer works correctly
> -; RUN: opt < %s -simplify-libcalls -S | FileCheck %s
> -
> -; This transformation requires the pointer size, as it assumes that size_t is
> -; the size of a pointer.
> -target datalayout = "-p:64:64:64"
> -
> - at hello = constant [14 x i8] c"hello world\5Cn\00"
> - at null = constant [1 x i8] zeroinitializer
> -
> -declare i8* @strchr(i8*, i32)
> -
> -define i32 @foo(i32 %index) {
> -       %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* @strchr(i8* %hello_p, i32 119)
> -; CHECK: getelementptr i8* %hello_p, i64 6
> -       %ignore = call i8* @strchr(i8* %null_p, i32 119)
> -; CHECK-NOT: call i8* strchr
> -       %null = call i8* @strchr(i8* %hello_p, i32 0)
> -; CHECK: getelementptr i8* %hello_p, i64 13
> -       %result = call i8* @strchr(i8* %hello_p, i32 %index)
> -; CHECK: call i8* @memchr(i8* %hello_p, i32 %index, i64 14)
> -       ret i32 %index
> -}
> -
> diff --git a/test/Transforms/SimplifyLibCalls/StrRChr.ll b/test/Transforms/SimplifyLibCalls/StrRChr.ll
> deleted file mode 100644
> index 2259fc0..0000000
> --- a/test/Transforms/SimplifyLibCalls/StrRChr.ll
> +++ /dev/null
> @@ -1,23 +0,0 @@
> -; Test that the StrRChrOptimizer works correctly
> -; RUN: opt < %s -simplify-libcalls -S | FileCheck %s
> -
> -target datalayout = "-p:64:64:64"
> -
> - at hello = constant [14 x i8] c"hello world\5Cn\00"
> - at 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
> -}
> --
> 1.7.10.2 (Apple Git-33)
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits



More information about the llvm-commits mailing list