diff --git a/llvm/lib/Transforms/Scalar/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Scalar/SimplifyLibCalls.cpp index 7d652dea48ed..370b81849df9 100644 --- a/llvm/lib/Transforms/Scalar/SimplifyLibCalls.cpp +++ b/llvm/lib/Transforms/Scalar/SimplifyLibCalls.cpp @@ -118,41 +118,6 @@ static bool IsOnlyUsedInEqualityComparison(Value *V, Value *With) { //===----------------------------------------------------------------------===// namespace { -//===---------------------------------------===// -// 'strcspn' Optimizations - -struct StrCSpnOpt : 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()->isIntegerTy()) - return 0; - - StringRef S1, S2; - bool HasS1 = getConstantStringInfo(CI->getArgOperand(0), S1); - bool HasS2 = getConstantStringInfo(CI->getArgOperand(1), S2); - - // strcspn("", s) -> 0 - if (HasS1 && S1.empty()) - return Constant::getNullValue(CI->getType()); - - // Constant folding. - if (HasS1 && HasS2) { - size_t Pos = S1.find_first_of(S2); - if (Pos == StringRef::npos) Pos = S1.size(); - return ConstantInt::get(CI->getType(), Pos); - } - - // strcspn(s, "") -> strlen(s) - if (TD && HasS2 && S2.empty()) - return EmitStrLen(CI->getArgOperand(0), B, TD, TLI); - - return 0; - } -}; - //===---------------------------------------===// // 'strstr' Optimizations @@ -1005,7 +970,7 @@ namespace { StringMap Optimizations; // String and Memory LibCall Optimizations - StrCSpnOpt StrCSpn; StrStrOpt StrStr; + StrStrOpt StrStr; MemCmpOpt MemCmp; MemCpyOpt MemCpy; MemMoveOpt MemMove; MemSetOpt MemSet; // Math Library Optimizations CosOpt Cos; PowOpt Pow; Exp2Opt Exp2; @@ -1073,7 +1038,6 @@ void SimplifyLibCalls::AddOpt(LibFunc::Func F1, LibFunc::Func F2, /// we know. void SimplifyLibCalls::InitOptimizations() { // String and Memory LibCall Optimizations - Optimizations["strcspn"] = &StrCSpn; Optimizations["strstr"] = &StrStr; Optimizations["memcmp"] = &MemCmp; AddOpt(LibFunc::memcpy, &MemCpy); diff --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp index f0d5491f9031..74d4e22fa446 100644 --- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -801,6 +801,38 @@ struct StrSpnOpt : public LibCallOptimization { } }; +struct StrCSpnOpt : 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()->isIntegerTy()) + return 0; + + StringRef S1, S2; + bool HasS1 = getConstantStringInfo(CI->getArgOperand(0), S1); + bool HasS2 = getConstantStringInfo(CI->getArgOperand(1), S2); + + // strcspn("", s) -> 0 + if (HasS1 && S1.empty()) + return Constant::getNullValue(CI->getType()); + + // Constant folding. + if (HasS1 && HasS2) { + size_t Pos = S1.find_first_of(S2); + if (Pos == StringRef::npos) Pos = S1.size(); + return ConstantInt::get(CI->getType(), Pos); + } + + // strcspn(s, "") -> strlen(s) + if (TD && HasS2 && S2.empty()) + return EmitStrLen(CI->getArgOperand(0), B, TD, TLI); + + return 0; + } +}; + } // End anonymous namespace. namespace llvm { @@ -832,6 +864,7 @@ class LibCallSimplifierImpl { StrPBrkOpt StrPBrk; StrToOpt StrTo; StrSpnOpt StrSpn; + StrCSpnOpt StrCSpn; void initOptimizations(); void addOpt(LibFunc::Func F, LibCallOptimization* Opt); @@ -874,6 +907,7 @@ void LibCallSimplifierImpl::initOptimizations() { addOpt(LibFunc::strtold, &StrTo); addOpt(LibFunc::strtoull, &StrTo); addOpt(LibFunc::strspn, &StrSpn); + addOpt(LibFunc::strcspn, &StrCSpn); } Value *LibCallSimplifierImpl::optimizeCall(CallInst *CI) { diff --git a/llvm/test/Transforms/InstCombine/disable-simplify-libcalls.ll b/llvm/test/Transforms/InstCombine/disable-simplify-libcalls.ll index 155c97c0104c..d81e9ae5bd73 100644 --- a/llvm/test/Transforms/InstCombine/disable-simplify-libcalls.ll +++ b/llvm/test/Transforms/InstCombine/disable-simplify-libcalls.ll @@ -36,6 +36,7 @@ declare i64 @strtol(i8*, i8**, i32) declare i64 @strtoll(i8*, i8**, i32) declare i64 @strtoul(i8*, i8**, i32) declare i64 @strtoull(i8*, i8**, i32) +declare i64 @strcspn(i8*, i8*) define double @t1(double %x) { ; CHECK: @t1 @@ -225,3 +226,11 @@ define i64 @t24(i8** %y) { ret i64 %ret ; CHECK: call i64 @strtoull } + +define i64 @t25(i8* %y) { +; CHECK: @t25 + %x = getelementptr [1 x i8]* @empty, i32 0, i32 0 + %ret = call i64 @strcspn(i8* %x, i8* %y) + ret i64 %ret +; CHECK: call i64 @strcspn +} diff --git a/llvm/test/Transforms/InstCombine/strcspn-1.ll b/llvm/test/Transforms/InstCombine/strcspn-1.ll new file mode 100644 index 000000000000..60fad897b2c8 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/strcspn-1.ll @@ -0,0 +1,57 @@ +; Test that the strcspn library call simplifier works correctly. +; +; RUN: opt < %s -instcombine -S | FileCheck %s + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" + +@abcba = constant [6 x i8] c"abcba\00" +@abc = constant [4 x i8] c"abc\00" +@null = constant [1 x i8] zeroinitializer + +declare i64 @strcspn(i8*, i8*) + +; Check strcspn(s, "") -> strlen(s). + +define i64 @test_simplify1(i8* %str) { +; CHECK: @test_simplify1 + %pat = getelementptr [1 x i8]* @null, i32 0, i32 0 + + %ret = call i64 @strcspn(i8* %str, i8* %pat) +; CHECK-NEXT: [[VAR:%[a-z]+]] = call i64 @strlen(i8* %str) + ret i64 %ret +; CHECK-NEXT: ret i64 [[VAR]] +} + +; Check strcspn("", s) -> 0. + +define i64 @test_simplify2(i8* %pat) { +; CHECK: @test_simplify2 + %str = getelementptr [1 x i8]* @null, i32 0, i32 0 + + %ret = call i64 @strcspn(i8* %str, i8* %pat) + ret i64 %ret +; CHECK-NEXT: ret i64 0 +} + +; Check strcspn(s1, s2), where s1 and s2 are constants. + +define i64 @test_simplify3() { +; CHECK: @test_simplify3 + %str = getelementptr [6 x i8]* @abcba, i32 0, i32 0 + %pat = getelementptr [4 x i8]* @abc, i32 0, i32 0 + + %ret = call i64 @strcspn(i8* %str, i8* %pat) + ret i64 %ret +; CHECK-NEXT: ret i64 0 +} + +; Check cases that shouldn't be simplified. + +define i64 @test_no_simplify1(i8* %str, i8* %pat) { +; CHECK: @test_no_simplify1 + + %ret = call i64 @strcspn(i8* %str, i8* %pat) +; CHECK-NEXT: %ret = call i64 @strcspn(i8* %str, i8* %pat) + ret i64 %ret +; CHECK-NEXT: ret i64 %ret +} diff --git a/llvm/test/Transforms/InstCombine/strcspn-2.ll b/llvm/test/Transforms/InstCombine/strcspn-2.ll new file mode 100644 index 000000000000..4e2393686c7d --- /dev/null +++ b/llvm/test/Transforms/InstCombine/strcspn-2.ll @@ -0,0 +1,21 @@ +; Test that the strcspn library call simplifier works correctly. +; +; RUN: opt < %s -instcombine -S | FileCheck %s + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" + +@null = constant [1 x i8] zeroinitializer + +declare double @strcspn(i8*, i8*) + +; Check that strcspn functions with the wrong prototype aren't simplified. + +define double @test_no_simplify1(i8* %pat) { +; CHECK: @test_no_simplify1 + %str = getelementptr [1 x i8]* @null, i32 0, i32 0 + + %ret = call double @strcspn(i8* %str, i8* %pat) +; CHECK-NEXT: call double @strcspn + ret double %ret +; CHECK-NEXT: ret double %ret +} diff --git a/llvm/test/Transforms/SimplifyLibCalls/StrSpn.ll b/llvm/test/Transforms/SimplifyLibCalls/StrSpn.ll deleted file mode 100644 index 2660ee9800a6..000000000000 --- a/llvm/test/Transforms/SimplifyLibCalls/StrSpn.ll +++ /dev/null @@ -1,25 +0,0 @@ -; RUN: opt < %s -simplify-libcalls -S | FileCheck %s - -target datalayout = "-p:64:64:64" - -@abcba = constant [6 x i8] c"abcba\00" -@abc = constant [4 x i8] c"abc\00" -@null = constant [1 x i8] zeroinitializer - -declare i64 @strcspn(i8*, i8*) - -define i64 @testcspn(i8* %s1, i8* %s2) { - %abcba_p = getelementptr [6 x i8]* @abcba, i32 0, i32 0 - %abc_p = getelementptr [4 x i8]* @abc, i32 0, i32 0 - %null_p = getelementptr [1 x i8]* @null, i32 0, i32 0 - %test1 = call i64 @strcspn(i8* %s1, i8* %null_p) -; CHECK: call i64 @strlen(i8* %s1) - %test2 = call i64 @strcspn(i8* %null_p, i8* %s2) - %test3 = call i64 @strcspn(i8* %abcba_p, i8* %abc_p) -; CHECK-NOT: call i64 @strcspn - %test4 = call i64 @strcspn(i8* %s1, i8* %s2) -; CHECK: call i64 @strcspn(i8* %s1, i8* %s2) - %add0 = add i64 %test1, %test3 -; CHECK: add i64 %{{.+}}, 0 - ret i64 %add0 -}