diff options
| -rw-r--r-- | llvm/lib/Transforms/Scalar/SimplifyLibCalls.cpp | 45 | ||||
| -rw-r--r-- | llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp | 44 | ||||
| -rw-r--r-- | llvm/test/Transforms/InstCombine/strlen-1.ll | 97 | ||||
| -rw-r--r-- | llvm/test/Transforms/InstCombine/strlen-2.ll | 18 | ||||
| -rw-r--r-- | llvm/test/Transforms/SimplifyLibCalls/StrLen.ll | 62 | 
5 files changed, 160 insertions, 106 deletions
diff --git a/llvm/lib/Transforms/Scalar/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Scalar/SimplifyLibCalls.cpp index 4251e60a916..a0235c15b61 100644 --- a/llvm/lib/Transforms/Scalar/SimplifyLibCalls.cpp +++ b/llvm/lib/Transforms/Scalar/SimplifyLibCalls.cpp @@ -90,22 +90,6 @@ public:  // Helper Functions  //===----------------------------------------------------------------------===// -/// IsOnlyUsedInZeroEqualityComparison - Return true if it only matters that the -/// value is equal or not-equal to zero. -static bool IsOnlyUsedInZeroEqualityComparison(Value *V) { -  for (Value::use_iterator UI = V->use_begin(), E = V->use_end(); -       UI != E; ++UI) { -    if (ICmpInst *IC = dyn_cast<ICmpInst>(*UI)) -      if (IC->isEquality()) -        if (Constant *C = dyn_cast<Constant>(IC->getOperand(1))) -          if (C->isNullValue()) -            continue; -    // Unknown instruction. -    return false; -  } -  return true; -} -  static bool CallHasFloatingPointArgument(const CallInst *CI) {    for (CallInst::const_op_iterator it = CI->op_begin(), e = CI->op_end();         it != e; ++it) { @@ -135,32 +119,6 @@ static bool IsOnlyUsedInEqualityComparison(Value *V, Value *With) {  namespace {  //===---------------------------------------===// -// 'strlen' Optimizations - -struct StrLenOpt : public LibCallOptimization { -  virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) { -    FunctionType *FT = Callee->getFunctionType(); -    if (FT->getNumParams() != 1 || -        FT->getParamType(0) != B.getInt8PtrTy() || -        !FT->getReturnType()->isIntegerTy()) -      return 0; - -    Value *Src = CI->getArgOperand(0); - -    // Constant folding: strlen("xyz") -> 3 -    if (uint64_t Len = GetStringLength(Src)) -      return ConstantInt::get(CI->getType(), Len-1); - -    // strlen(x) != 0 --> *x != 0 -    // strlen(x) == 0 --> *x == 0 -    if (IsOnlyUsedInZeroEqualityComparison(CI)) -      return B.CreateZExt(B.CreateLoad(Src, "strlenfirst"), CI->getType()); -    return 0; -  } -}; - - -//===---------------------------------------===//  // 'strpbrk' Optimizations  struct StrPBrkOpt : public LibCallOptimization { @@ -1146,7 +1104,7 @@ namespace {      StringMap<LibCallOptimization*> Optimizations;      // String and Memory LibCall Optimizations -    StrLenOpt StrLen; StrPBrkOpt StrPBrk; +    StrPBrkOpt StrPBrk;      StrToOpt StrTo; StrSpnOpt StrSpn; StrCSpnOpt StrCSpn; StrStrOpt StrStr;      MemCmpOpt MemCmp; MemCpyOpt MemCpy; MemMoveOpt MemMove; MemSetOpt MemSet;      // Math Library Optimizations @@ -1215,7 +1173,6 @@ void SimplifyLibCalls::AddOpt(LibFunc::Func F1, LibFunc::Func F2,  /// we know.  void SimplifyLibCalls::InitOptimizations() {    // String and Memory LibCall Optimizations -  Optimizations["strlen"] = &StrLen;    Optimizations["strpbrk"] = &StrPBrk;    Optimizations["strtol"] = &StrTo;    Optimizations["strtod"] = &StrTo; diff --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp index cc03573326e..658e7c34287 100644 --- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -64,6 +64,26 @@ public:  };  //===----------------------------------------------------------------------===// +// Helper Functions +//===----------------------------------------------------------------------===// + +/// isOnlyUsedInZeroEqualityComparison - Return true if it only matters that the +/// value is equal or not-equal to zero. +static bool isOnlyUsedInZeroEqualityComparison(Value *V) { +  for (Value::use_iterator UI = V->use_begin(), E = V->use_end(); +       UI != E; ++UI) { +    if (ICmpInst *IC = dyn_cast<ICmpInst>(*UI)) +      if (IC->isEquality()) +        if (Constant *C = dyn_cast<Constant>(IC->getOperand(1))) +          if (C->isNullValue()) +            continue; +    // Unknown instruction. +    return false; +  } +  return true; +} + +//===----------------------------------------------------------------------===//  // Fortified Library Call Optimizations  //===----------------------------------------------------------------------===// @@ -675,6 +695,28 @@ struct StrNCpyOpt : public LibCallOptimization {    }  }; +struct StrLenOpt : public LibCallOptimization { +  virtual Value *callOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) { +    FunctionType *FT = Callee->getFunctionType(); +    if (FT->getNumParams() != 1 || +        FT->getParamType(0) != B.getInt8PtrTy() || +        !FT->getReturnType()->isIntegerTy()) +      return 0; + +    Value *Src = CI->getArgOperand(0); + +    // Constant folding: strlen("xyz") -> 3 +    if (uint64_t Len = GetStringLength(Src)) +      return ConstantInt::get(CI->getType(), Len-1); + +    // strlen(x) != 0 --> *x != 0 +    // strlen(x) == 0 --> *x == 0 +    if (isOnlyUsedInZeroEqualityComparison(CI)) +      return B.CreateZExt(B.CreateLoad(Src, "strlenfirst"), CI->getType()); +    return 0; +  } +}; +  } // End anonymous namespace.  namespace llvm { @@ -702,6 +744,7 @@ class LibCallSimplifierImpl {    StrCpyOpt StrCpy;    StpCpyOpt StpCpy;    StrNCpyOpt StrNCpy; +  StrLenOpt StrLen;    void initOptimizations();  public: @@ -733,6 +776,7 @@ void LibCallSimplifierImpl::initOptimizations() {    Optimizations["strcpy"] = &StrCpy;    Optimizations["stpcpy"] = &StpCpy;    Optimizations["strncpy"] = &StrNCpy; +  Optimizations["strlen"] = &StrLen;  }  Value *LibCallSimplifierImpl::optimizeCall(CallInst *CI) { diff --git a/llvm/test/Transforms/InstCombine/strlen-1.ll b/llvm/test/Transforms/InstCombine/strlen-1.ll new file mode 100644 index 00000000000..6d7464a4cc8 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/strlen-1.ll @@ -0,0 +1,97 @@ +; Test that the strlen 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" +@null = constant [1 x i8] zeroinitializer +@null_hello = constant [7 x i8] c"\00hello\00" +@nullstring = constant i8 0 +@a = common global [32 x i8] zeroinitializer, align 1 + +declare i32 @strlen(i8*) + +; Check strlen(string constant) -> integer constant. + +define i32 @test_simplify1() { +; CHECK: @test_simplify1 +  %hello_p = getelementptr [6 x i8]* @hello, i32 0, i32 0 +  %hello_l = call i32 @strlen(i8* %hello_p) +  ret i32 %hello_l +; CHECK-NEXT: ret i32 5 +} + +define i32 @test_simplify2() { +; CHECK: @test_simplify2 +  %null_p = getelementptr [1 x i8]* @null, i32 0, i32 0 +  %null_l = call i32 @strlen(i8* %null_p) +  ret i32 %null_l +; CHECK-NEXT: ret i32 0 +} + +define i32 @test_simplify3() { +; CHECK: @test_simplify3 +  %null_hello_p = getelementptr [7 x i8]* @null_hello, i32 0, i32 0 +  %null_hello_l = call i32 @strlen(i8* %null_hello_p) +  ret i32 %null_hello_l +; CHECK-NEXT: ret i32 0 +} + +define i32 @test_simplify4() { +; CHECK: @test_simplify4 +  %len = tail call i32 @strlen(i8* @nullstring) nounwind +  ret i32 %len +; CHECK-NEXT: ret i32 0 +} + +; Check strlen(x) == 0 --> *x == 0. + +define i1 @test_simplify5() { +; CHECK: @test_simplify5 +  %hello_p = getelementptr [6 x i8]* @hello, i32 0, i32 0 +  %hello_l = call i32 @strlen(i8* %hello_p) +  %eq_hello = icmp eq i32 %hello_l, 0 +  ret i1 %eq_hello +; CHECK-NEXT: ret i1 false +} + +define i1 @test_simplify6() { +; CHECK: @test_simplify6 +  %null_p = getelementptr [1 x i8]* @null, i32 0, i32 0 +  %null_l = call i32 @strlen(i8* %null_p) +  %eq_null = icmp eq i32 %null_l, 0 +  ret i1 %eq_null +; CHECK-NEXT: ret i1 true +} + +; Check strlen(x) != 0 --> *x != 0. + +define i1 @test_simplify7() { +; CHECK: @test_simplify7 +  %hello_p = getelementptr [6 x i8]* @hello, i32 0, i32 0 +  %hello_l = call i32 @strlen(i8* %hello_p) +  %ne_hello = icmp ne i32 %hello_l, 0 +  ret i1 %ne_hello +; CHECK-NEXT: ret i1 true +} + +define i1 @test_simplify8() { +; CHECK: @test_simplify8 +  %null_p = getelementptr [1 x i8]* @null, i32 0, i32 0 +  %null_l = call i32 @strlen(i8* %null_p) +  %ne_null = icmp ne i32 %null_l, 0 +  ret i1 %ne_null +; CHECK-NEXT: ret i1 false +} + +; Check cases that shouldn't be simplified. + +define i32 @test_no_simplify1() { +; CHECK: @test_no_simplify1 +  %a_p = getelementptr [32 x i8]* @a, i32 0, i32 0 +  %a_l = call i32 @strlen(i8* %a_p) +; CHECK-NEXT: %a_l = call i32 @strlen +  ret i32 %a_l +; CHECK-NEXT: ret i32 %a_l +} diff --git a/llvm/test/Transforms/InstCombine/strlen-2.ll b/llvm/test/Transforms/InstCombine/strlen-2.ll new file mode 100644 index 00000000000..c4fd54c06db --- /dev/null +++ b/llvm/test/Transforms/InstCombine/strlen-2.ll @@ -0,0 +1,18 @@ +; Test that the strlen 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" + +declare i32 @strlen(i8*, i32) + +define i32 @test_no_simplify1() { +; CHECK: @test_no_simplify1 +  %hello_p = getelementptr [6 x i8]* @hello, i32 0, i32 0 +  %hello_l = call i32 @strlen(i8* %hello_p, i32 187) +; CHECK-NEXT: %hello_l = call i32 @strlen +  ret i32 %hello_l +; CHECK-NEXT: ret i32 %hello_l +} diff --git a/llvm/test/Transforms/SimplifyLibCalls/StrLen.ll b/llvm/test/Transforms/SimplifyLibCalls/StrLen.ll deleted file mode 100644 index 4a20bbd2ce8..00000000000 --- a/llvm/test/Transforms/SimplifyLibCalls/StrLen.ll +++ /dev/null @@ -1,62 +0,0 @@ -; Test that the StrCatOptimizer works correctly -; RUN: opt < %s -simplify-libcalls -S | \ -; RUN:    not grep "call.*strlen" - -target datalayout = "e-p:32:32" -@hello = constant [6 x i8] c"hello\00"		; <[6 x i8]*> [#uses=3] -@null = constant [1 x i8] zeroinitializer		; <[1 x i8]*> [#uses=3] -@null_hello = constant [7 x i8] c"\00hello\00"		; <[7 x i8]*> [#uses=1] -@nullstring = constant i8 0 - -declare i32 @strlen(i8*) - -define i32 @test1() { -	%hello_p = getelementptr [6 x i8]* @hello, i32 0, i32 0		; <i8*> [#uses=1] -	%hello_l = call i32 @strlen( i8* %hello_p )		; <i32> [#uses=1] -	ret i32 %hello_l -} - -define i32 @test2() { -	%null_p = getelementptr [1 x i8]* @null, i32 0, i32 0		; <i8*> [#uses=1] -	%null_l = call i32 @strlen( i8* %null_p )		; <i32> [#uses=1] -	ret i32 %null_l -} - -define i32 @test3() { -	%null_hello_p = getelementptr [7 x i8]* @null_hello, i32 0, i32 0		; <i8*> [#uses=1] -	%null_hello_l = call i32 @strlen( i8* %null_hello_p )		; <i32> [#uses=1] -	ret i32 %null_hello_l -} - -define i1 @test4() { -	%hello_p = getelementptr [6 x i8]* @hello, i32 0, i32 0		; <i8*> [#uses=1] -	%hello_l = call i32 @strlen( i8* %hello_p )		; <i32> [#uses=1] -	%eq_hello = icmp eq i32 %hello_l, 0		; <i1> [#uses=1] -	ret i1 %eq_hello -} - -define i1 @test5() { -	%null_p = getelementptr [1 x i8]* @null, i32 0, i32 0		; <i8*> [#uses=1] -	%null_l = call i32 @strlen( i8* %null_p )		; <i32> [#uses=1] -	%eq_null = icmp eq i32 %null_l, 0		; <i1> [#uses=1] -	ret i1 %eq_null -} - -define i1 @test6() { -	%hello_p = getelementptr [6 x i8]* @hello, i32 0, i32 0		; <i8*> [#uses=1] -	%hello_l = call i32 @strlen( i8* %hello_p )		; <i32> [#uses=1] -	%ne_hello = icmp ne i32 %hello_l, 0		; <i1> [#uses=1] -	ret i1 %ne_hello -} - -define i1 @test7() { -	%null_p = getelementptr [1 x i8]* @null, i32 0, i32 0		; <i8*> [#uses=1] -	%null_l = call i32 @strlen( i8* %null_p )		; <i32> [#uses=1] -	%ne_null = icmp ne i32 %null_l, 0		; <i1> [#uses=1] -	ret i1 %ne_null -} - -define i32 @test8() { -	%len = tail call i32 @strlen(i8* @nullstring) nounwind -	ret i32 %len -}  | 

