From: Meador Inge Date: Wed, 31 Oct 2012 00:20:56 +0000 (+0000) Subject: instcombine: Migrate stpcpy optimizations X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=commitdiff_plain;h=e6d781fd3cf9aa30d1c533308d1fdb6738e4f89f instcombine: Migrate stpcpy optimizations This patch migrates the stpcpy optimizations from the simplify-libcalls pass into the instcombine library call simplifier. Note that the __stpcpy_chk simplifications were migrated in a previous commit. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@167083 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Transforms/Scalar/SimplifyLibCalls.cpp b/lib/Transforms/Scalar/SimplifyLibCalls.cpp index f3448bcd871..f7593e7ea89 100644 --- a/lib/Transforms/Scalar/SimplifyLibCalls.cpp +++ b/lib/Transforms/Scalar/SimplifyLibCalls.cpp @@ -134,52 +134,6 @@ static bool IsOnlyUsedInEqualityComparison(Value *V, Value *With) { //===----------------------------------------------------------------------===// namespace { -//===---------------------------------------===// -// 'stpcpy' Optimizations - -struct StpCpyOpt: public LibCallOptimization { - bool OptChkCall; // True if it's optimizing a __stpcpy_chk libcall. - - StpCpyOpt(bool c) : OptChkCall(c) {} - - virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) { - // Verify the "stpcpy" function prototype. - unsigned NumParams = OptChkCall ? 3 : 2; - FunctionType *FT = Callee->getFunctionType(); - if (FT->getNumParams() != NumParams || - FT->getReturnType() != FT->getParamType(0) || - FT->getParamType(0) != FT->getParamType(1) || - FT->getParamType(0) != B.getInt8PtrTy()) - return 0; - - // These optimizations require DataLayout. - if (!TD) return 0; - - Value *Dst = CI->getArgOperand(0), *Src = CI->getArgOperand(1); - if (Dst == Src) { // stpcpy(x,x) -> x+strlen(x) - Value *StrLen = EmitStrLen(Src, B, TD, TLI); - return StrLen ? B.CreateInBoundsGEP(Dst, StrLen) : 0; - } - - // See if we can get the length of the input string. - uint64_t Len = GetStringLength(Src); - if (Len == 0) return 0; - - Type *PT = FT->getParamType(0); - Value *LenV = ConstantInt::get(TD->getIntPtrType(PT), Len); - Value *DstEnd = B.CreateGEP(Dst, - ConstantInt::get(TD->getIntPtrType(PT), - Len - 1)); - - // We have enough information to now generate the memcpy call to do the - // copy for us. Make a memcpy to copy the nul byte with align = 1. - if (!OptChkCall || !EmitMemCpyChk(Dst, Src, LenV, CI->getArgOperand(2), B, - TD, TLI)) - B.CreateMemCpy(Dst, Src, LenV, 1); - return DstEnd; - } -}; - //===---------------------------------------===// // 'strncpy' Optimizations @@ -1242,7 +1196,6 @@ namespace { StringMap Optimizations; // String and Memory LibCall Optimizations - StpCpyOpt StpCpy; StpCpyOpt StpCpyChk; StrNCpyOpt StrNCpy; StrLenOpt StrLen; StrPBrkOpt StrPBrk; StrToOpt StrTo; StrSpnOpt StrSpn; StrCSpnOpt StrCSpn; StrStrOpt StrStr; @@ -1261,8 +1214,8 @@ namespace { bool Modified; // This is only used by doInitialization. public: static char ID; // Pass identification - SimplifyLibCalls() : FunctionPass(ID), StpCpy(false), StpCpyChk(true), - UnaryDoubleFP(false), UnsafeUnaryDoubleFP(true) { + SimplifyLibCalls() : FunctionPass(ID), UnaryDoubleFP(false), + UnsafeUnaryDoubleFP(true) { initializeSimplifyLibCallsPass(*PassRegistry::getPassRegistry()); } void AddOpt(LibFunc::Func F, LibCallOptimization* Opt); @@ -1314,7 +1267,6 @@ void SimplifyLibCalls::AddOpt(LibFunc::Func F1, LibFunc::Func F2, void SimplifyLibCalls::InitOptimizations() { // String and Memory LibCall Optimizations Optimizations["strncpy"] = &StrNCpy; - Optimizations["stpcpy"] = &StpCpy; Optimizations["strlen"] = &StrLen; Optimizations["strpbrk"] = &StrPBrk; Optimizations["strtol"] = &StrTo; @@ -1332,9 +1284,6 @@ void SimplifyLibCalls::InitOptimizations() { Optimizations["memmove"] = &MemMove; AddOpt(LibFunc::memset, &MemSet); - // _chk variants of String and Memory LibCall Optimizations. - Optimizations["__stpcpy_chk"] = &StpCpyChk; - // Math Library Optimizations Optimizations["cosf"] = &Cos; Optimizations["cos"] = &Cos; diff --git a/lib/Transforms/Utils/SimplifyLibCalls.cpp b/lib/Transforms/Utils/SimplifyLibCalls.cpp index 5984a96cd0f..bc360010de4 100644 --- a/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ b/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -592,6 +592,42 @@ struct StrCpyOpt : public LibCallOptimization { } }; +struct StpCpyOpt: public LibCallOptimization { + virtual Value *callOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) { + // Verify the "stpcpy" function prototype. + FunctionType *FT = Callee->getFunctionType(); + if (FT->getNumParams() != 2 || + FT->getReturnType() != FT->getParamType(0) || + FT->getParamType(0) != FT->getParamType(1) || + FT->getParamType(0) != B.getInt8PtrTy()) + return 0; + + // These optimizations require DataLayout. + if (!TD) return 0; + + Value *Dst = CI->getArgOperand(0), *Src = CI->getArgOperand(1); + if (Dst == Src) { // stpcpy(x,x) -> x+strlen(x) + Value *StrLen = EmitStrLen(Src, B, TD, TLI); + return StrLen ? B.CreateInBoundsGEP(Dst, StrLen) : 0; + } + + // See if we can get the length of the input string. + uint64_t Len = GetStringLength(Src); + if (Len == 0) return 0; + + Type *PT = FT->getParamType(0); + Value *LenV = ConstantInt::get(TD->getIntPtrType(PT), Len); + Value *DstEnd = B.CreateGEP(Dst, + ConstantInt::get(TD->getIntPtrType(PT), + Len - 1)); + + // We have enough information to now generate the memcpy call to do the + // copy for us. Make a memcpy to copy the nul byte with align = 1. + B.CreateMemCpy(Dst, Src, LenV, 1); + return DstEnd; + } +}; + } // End anonymous namespace. namespace llvm { @@ -617,6 +653,7 @@ class LibCallSimplifierImpl { StrCmpOpt StrCmp; StrNCmpOpt StrNCmp; StrCpyOpt StrCpy; + StpCpyOpt StpCpy; void initOptimizations(); public: @@ -646,6 +683,7 @@ void LibCallSimplifierImpl::initOptimizations() { Optimizations["strcmp"] = &StrCmp; Optimizations["strncmp"] = &StrNCmp; Optimizations["strcpy"] = &StrCpy; + Optimizations["stpcpy"] = &StpCpy; } Value *LibCallSimplifierImpl::optimizeCall(CallInst *CI) { diff --git a/test/Transforms/InstCombine/stpcpy-1.ll b/test/Transforms/InstCombine/stpcpy-1.ll new file mode 100644 index 00000000000..8b6bb0e0d50 --- /dev/null +++ b/test/Transforms/InstCombine/stpcpy-1.ll @@ -0,0 +1,46 @@ +; Test that the stpcpy library call simplifier works correctly. +; RUN: opt < %s -instcombine -S | FileCheck %s +; +; This transformation requires the pointer size, as it assumes that size_t is +; the size of a pointer. +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-n8:16:32" + +@hello = constant [6 x i8] c"hello\00" +@a = common global [32 x i8] zeroinitializer, align 1 +@b = common global [32 x i8] zeroinitializer, align 1 + +declare i8* @stpcpy(i8*, i8*) + +define i8* @test_simplify1() { +; CHECK: @test_simplify1 + + %dst = getelementptr [32 x i8]* @a, i32 0, i32 0 + %src = getelementptr [6 x i8]* @hello, i32 0, i32 0 + + %ret = call i8* @stpcpy(i8* %dst, i8* %src) +; CHECK: @llvm.memcpy.p0i8.p0i8.i32 +; CHECK-NEXT: getelementptr inbounds ([32 x i8]* @a, i32 0, i32 5) + ret i8* %ret +} + +define i8* @test_simplify2() { +; CHECK: @test_simplify2 + + %dst = getelementptr [32 x i8]* @a, i32 0, i32 0 + + %ret = call i8* @stpcpy(i8* %dst, i8* %dst) +; CHECK: [[LEN:%[a-z]+]] = call i32 @strlen +; CHECK-NEXT: getelementptr inbounds [32 x i8]* @a, i32 0, i32 [[LEN]] + ret i8* %ret +} + +define i8* @test_no_simplify1() { +; CHECK: @test_no_simplify1 + + %dst = getelementptr [32 x i8]* @a, i32 0, i32 0 + %src = getelementptr [32 x i8]* @b, i32 0, i32 0 + + %ret = call i8* @stpcpy(i8* %dst, i8* %src) +; CHECK: call i8* @stpcpy + ret i8* %ret +} diff --git a/test/Transforms/InstCombine/stpcpy-2.ll b/test/Transforms/InstCombine/stpcpy-2.ll new file mode 100644 index 00000000000..2e92c0895ed --- /dev/null +++ b/test/Transforms/InstCombine/stpcpy-2.ll @@ -0,0 +1,22 @@ +; Test that the stpcpy library call simplifier works correctly. +; RUN: opt < %s -instcombine -S | FileCheck %s +; +; This transformation requires the pointer size, as it assumes that size_t is +; the size of a pointer. +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-n8:16:32" + +@hello = constant [6 x i8] c"hello\00" +@a = common global [32 x i8] zeroinitializer, align 1 + +declare i16* @stpcpy(i8*, i8*) + +define void @test_no_simplify1() { +; CHECK: @test_no_simplify1 + + %dst = getelementptr [32 x i8]* @a, i32 0, i32 0 + %src = getelementptr [6 x i8]* @hello, i32 0, i32 0 + + call i16* @stpcpy(i8* %dst, i8* %src) +; CHECK: call i16* @stpcpy + ret void +} diff --git a/test/Transforms/InstCombine/stpcpy_chk-1.ll b/test/Transforms/InstCombine/stpcpy_chk-1.ll index d06b3286f51..05603918c64 100644 --- a/test/Transforms/InstCombine/stpcpy_chk-1.ll +++ b/test/Transforms/InstCombine/stpcpy_chk-1.ll @@ -16,7 +16,7 @@ define void @test_simplify1() { %dst = getelementptr inbounds [60 x i8]* @a, i32 0, i32 0 %src = getelementptr inbounds [12 x i8]* @.str, i32 0, i32 0 -; CHECK-NEXT: call i8* @stpcpy +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32 call i8* @__stpcpy_chk(i8* %dst, i8* %src, i32 60) ret void } @@ -26,7 +26,7 @@ define void @test_simplify2() { %dst = getelementptr inbounds [60 x i8]* @a, i32 0, i32 0 %src = getelementptr inbounds [12 x i8]* @.str, i32 0, i32 0 -; CHECK-NEXT: call i8* @stpcpy +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32 call i8* @__stpcpy_chk(i8* %dst, i8* %src, i32 12) ret void } @@ -36,7 +36,7 @@ define void @test_simplify3() { %dst = getelementptr inbounds [60 x i8]* @a, i32 0, i32 0 %src = getelementptr inbounds [12 x i8]* @.str, i32 0, i32 0 -; CHECK-NEXT: call i8* @stpcpy +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32 call i8* @__stpcpy_chk(i8* %dst, i8* %src, i32 -1) ret void } diff --git a/test/Transforms/SimplifyLibCalls/StpCpy.ll b/test/Transforms/SimplifyLibCalls/StpCpy.ll deleted file mode 100644 index 914b0955bc9..00000000000 --- a/test/Transforms/SimplifyLibCalls/StpCpy.ll +++ /dev/null @@ -1,43 +0,0 @@ -; Test that the StpCpyOptimizer 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 = "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-n8:16:32" - -@hello = constant [6 x i8] c"hello\00" - -declare i8* @stpcpy(i8*, i8*) - -declare i8* @__stpcpy_chk(i8*, i8*, i32) nounwind - -declare i32 @llvm.objectsize.i32(i8*, i1) nounwind readonly - -define i32 @t1() { -; CHECK: @t1 - %target = alloca [1024 x i8] - %arg1 = getelementptr [1024 x i8]* %target, i32 0, i32 0 - %arg2 = getelementptr [6 x i8]* @hello, i32 0, i32 0 - %rslt1 = call i8* @stpcpy( i8* %arg1, i8* %arg2 ) -; CHECK: @llvm.memcpy.p0i8.p0i8.i32 - ret i32 0 -} - -define i32 @t2() { -; CHECK: @t2 - %target = alloca [1024 x i8] - %arg1 = getelementptr [1024 x i8]* %target, i32 0, i32 0 - %arg2 = getelementptr [6 x i8]* @hello, i32 0, i32 0 - %tmp1 = call i32 @llvm.objectsize.i32(i8* %arg1, i1 false) - %rslt1 = call i8* @__stpcpy_chk(i8* %arg1, i8* %arg2, i32 %tmp1) -; CHECK: @__memcpy_chk - ret i32 0 -} - -define i8* @t3(i8* %arg) { -; CHECK: @t3 - %stpcpy = tail call i8* @stpcpy(i8* %arg, i8* %arg) -; CHECK: [[LEN:%[a-z]+]] = call i32 @strlen(i8* %arg) -; CHECK-NEXT: getelementptr inbounds i8* %arg, i32 [[LEN]] - ret i8* %stpcpy -}