mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-13 04:30:23 +00:00
instcombine: Migrate strcpy optimizations
This patch migrates the strcpy optimizations from the simplify-libcalls pass into the instcombine library call simplifier. Note also that StrCpyChkOpt has been updated with a few simplifications that were being done in the simplify-libcalls version of StrCpyOpt, but not in the migrated implementation of StrCpyOpt. There is no reason to overload StrCpyOpt with fortified and regular simplifications in the new model since there is already a dedicated simplifier for __strcpy_chk. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@166198 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
77ed3424e4
commit
0c41d57b09
@ -134,47 +134,6 @@ static bool IsOnlyUsedInEqualityComparison(Value *V, Value *With) {
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
//===---------------------------------------===//
|
||||
// 'strcpy' Optimizations
|
||||
|
||||
struct StrCpyOpt : public LibCallOptimization {
|
||||
bool OptChkCall; // True if it's optimizing a __strcpy_chk libcall.
|
||||
|
||||
StrCpyOpt(bool c) : OptChkCall(c) {}
|
||||
|
||||
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
||||
// Verify the "strcpy" 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;
|
||||
|
||||
Value *Dst = CI->getArgOperand(0), *Src = CI->getArgOperand(1);
|
||||
if (Dst == Src) // strcpy(x,x) -> x
|
||||
return Src;
|
||||
|
||||
// These optimizations require DataLayout.
|
||||
if (!TD) return 0;
|
||||
|
||||
// See if we can get the length of the input string.
|
||||
uint64_t Len = GetStringLength(Src);
|
||||
if (Len == 0) return 0;
|
||||
|
||||
// We have enough information to now generate the memcpy call to do the
|
||||
// concatenation for us. Make a memcpy to copy the nul byte with align = 1.
|
||||
if (!OptChkCall ||
|
||||
!EmitMemCpyChk(Dst, Src,
|
||||
ConstantInt::get(TD->getIntPtrType(*Context), Len),
|
||||
CI->getArgOperand(2), B, TD, TLI))
|
||||
B.CreateMemCpy(Dst, Src,
|
||||
ConstantInt::get(TD->getIntPtrType(*Context), Len), 1);
|
||||
return Dst;
|
||||
}
|
||||
};
|
||||
|
||||
//===---------------------------------------===//
|
||||
// 'stpcpy' Optimizations
|
||||
|
||||
@ -1275,7 +1234,6 @@ namespace {
|
||||
|
||||
StringMap<LibCallOptimization*> Optimizations;
|
||||
// String and Memory LibCall Optimizations
|
||||
StrCpyOpt StrCpy; StrCpyOpt StrCpyChk;
|
||||
StpCpyOpt StpCpy; StpCpyOpt StpCpyChk;
|
||||
StrNCpyOpt StrNCpy;
|
||||
StrLenOpt StrLen; StrPBrkOpt StrPBrk;
|
||||
@ -1295,8 +1253,7 @@ namespace {
|
||||
bool Modified; // This is only used by doInitialization.
|
||||
public:
|
||||
static char ID; // Pass identification
|
||||
SimplifyLibCalls() : FunctionPass(ID), StrCpy(false), StrCpyChk(true),
|
||||
StpCpy(false), StpCpyChk(true),
|
||||
SimplifyLibCalls() : FunctionPass(ID), StpCpy(false), StpCpyChk(true),
|
||||
UnaryDoubleFP(false), UnsafeUnaryDoubleFP(true) {
|
||||
initializeSimplifyLibCallsPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
@ -1348,7 +1305,6 @@ void SimplifyLibCalls::AddOpt(LibFunc::Func F1, LibFunc::Func F2,
|
||||
/// we know.
|
||||
void SimplifyLibCalls::InitOptimizations() {
|
||||
// String and Memory LibCall Optimizations
|
||||
Optimizations["strcpy"] = &StrCpy;
|
||||
Optimizations["strncpy"] = &StrNCpy;
|
||||
Optimizations["stpcpy"] = &StpCpy;
|
||||
Optimizations["strlen"] = &StrLen;
|
||||
@ -1369,7 +1325,6 @@ void SimplifyLibCalls::InitOptimizations() {
|
||||
AddOpt(LibFunc::memset, &MemSet);
|
||||
|
||||
// _chk variants of String and Memory LibCall Optimizations.
|
||||
Optimizations["__strcpy_chk"] = &StrCpyChk;
|
||||
Optimizations["__stpcpy_chk"] = &StpCpyChk;
|
||||
|
||||
// Math Library Optimizations
|
||||
|
@ -183,14 +183,30 @@ struct StrCpyChkOpt : public InstFortifiedLibCallOptimization {
|
||||
FT->getParamType(2) != TD->getIntPtrType(Context))
|
||||
return 0;
|
||||
|
||||
Value *Dst = CI->getArgOperand(0), *Src = CI->getArgOperand(1);
|
||||
if (Dst == Src) // __strcpy_chk(x,x) -> x
|
||||
return Src;
|
||||
|
||||
// If a) we don't have any length information, or b) we know this will
|
||||
// fit then just lower to a plain st[rp]cpy. Otherwise we'll keep our
|
||||
// st[rp]cpy_chk call which may fail at runtime if the size is too long.
|
||||
// TODO: It might be nice to get a maximum length out of the possible
|
||||
// string lengths for varying.
|
||||
if (isFoldable(2, 1, true)) {
|
||||
Value *Ret = EmitStrCpy(CI->getArgOperand(0), CI->getArgOperand(1), B, TD,
|
||||
TLI, Name.substr(2, 6));
|
||||
Value *Ret = EmitStrCpy(Dst, Src, B, TD, TLI, Name.substr(2, 6));
|
||||
return Ret;
|
||||
} else {
|
||||
// Maybe we can stil fold __strcpy_chk to __memcpy_chk.
|
||||
uint64_t Len = GetStringLength(Src);
|
||||
if (Len == 0) return 0;
|
||||
|
||||
// This optimization require DataLayout.
|
||||
if (!TD) return 0;
|
||||
|
||||
Value *Ret =
|
||||
EmitMemCpyChk(Dst, Src,
|
||||
ConstantInt::get(TD->getIntPtrType(Context), Len),
|
||||
CI->getArgOperand(2), B, TD, TLI);
|
||||
return Ret;
|
||||
}
|
||||
return 0;
|
||||
@ -497,6 +513,35 @@ struct StrNCmpOpt : public LibCallOptimization {
|
||||
}
|
||||
};
|
||||
|
||||
struct StrCpyOpt : public LibCallOptimization {
|
||||
virtual Value *callOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
||||
// Verify the "strcpy" 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;
|
||||
|
||||
Value *Dst = CI->getArgOperand(0), *Src = CI->getArgOperand(1);
|
||||
if (Dst == Src) // strcpy(x,x) -> x
|
||||
return Src;
|
||||
|
||||
// These optimizations require DataLayout.
|
||||
if (!TD) return 0;
|
||||
|
||||
// See if we can get the length of the input string.
|
||||
uint64_t Len = GetStringLength(Src);
|
||||
if (Len == 0) return 0;
|
||||
|
||||
// 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,
|
||||
ConstantInt::get(TD->getIntPtrType(*Context), Len), 1);
|
||||
return Dst;
|
||||
}
|
||||
};
|
||||
|
||||
} // End anonymous namespace.
|
||||
|
||||
namespace llvm {
|
||||
@ -520,6 +565,7 @@ class LibCallSimplifierImpl {
|
||||
StrRChrOpt StrRChr;
|
||||
StrCmpOpt StrCmp;
|
||||
StrNCmpOpt StrNCmp;
|
||||
StrCpyOpt StrCpy;
|
||||
|
||||
void initOptimizations();
|
||||
public:
|
||||
@ -548,6 +594,7 @@ void LibCallSimplifierImpl::initOptimizations() {
|
||||
Optimizations["strncat"] = &StrNCat;
|
||||
Optimizations["strchr"] = &StrChr;
|
||||
Optimizations["strrchr"] = &StrRChr;
|
||||
Optimizations["strcpy"] = &StrCpy;
|
||||
}
|
||||
|
||||
Value *LibCallSimplifierImpl::optimizeCall(CallInst *CI) {
|
||||
|
45
test/Transforms/InstCombine/strcpy-1.ll
Normal file
45
test/Transforms/InstCombine/strcpy-1.ll
Normal file
@ -0,0 +1,45 @@
|
||||
; Test that the strcpy library call simplifier works correctly.
|
||||
; rdar://6839935
|
||||
; 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* @strcpy(i8*, i8*)
|
||||
|
||||
define void @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
|
||||
|
||||
call i8* @strcpy(i8* %dst, i8* %src)
|
||||
; CHECK: @llvm.memcpy.p0i8.p0i8.i32
|
||||
ret void
|
||||
}
|
||||
|
||||
define i8* @test_simplify2() {
|
||||
; CHECK: @test_simplify2
|
||||
|
||||
%dst = getelementptr [32 x i8]* @a, i32 0, i32 0
|
||||
|
||||
%ret = call i8* @strcpy(i8* %dst, i8* %dst)
|
||||
; CHECK: ret i8* getelementptr inbounds ([32 x i8]* @a, i32 0, i32 0)
|
||||
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* @strcpy(i8* %dst, i8* %src)
|
||||
; CHECK: call i8* @strcpy
|
||||
ret i8* %ret
|
||||
}
|
22
test/Transforms/InstCombine/strcpy-2.ll
Normal file
22
test/Transforms/InstCombine/strcpy-2.ll
Normal file
@ -0,0 +1,22 @@
|
||||
; Test that the strcpy 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* @strcpy(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* @strcpy(i8* %dst, i8* %src)
|
||||
; CHECK: call i16* @strcpy
|
||||
ret void
|
||||
}
|
@ -7,16 +7,16 @@ target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f3
|
||||
|
||||
@a = common global [60 x i8] zeroinitializer, align 1
|
||||
@b = common global [60 x i8] zeroinitializer, align 1
|
||||
@.str = private constant [8 x i8] c"abcdefg\00"
|
||||
@.str = private constant [12 x i8] c"abcdefghijk\00"
|
||||
|
||||
; Check cases where slen >= strlen (src).
|
||||
|
||||
define void @test_simplify1() {
|
||||
; CHECK: @test_simplify1
|
||||
%dst = getelementptr inbounds [60 x i8]* @a, i32 0, i32 0
|
||||
%src = getelementptr inbounds [8 x i8]* @.str, i32 0, i32 0
|
||||
%src = getelementptr inbounds [12 x i8]* @.str, i32 0, i32 0
|
||||
|
||||
; CHECK-NEXT: call i8* @strcpy
|
||||
; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32
|
||||
call i8* @__strcpy_chk(i8* %dst, i8* %src, i32 60)
|
||||
ret void
|
||||
}
|
||||
@ -24,19 +24,19 @@ define void @test_simplify1() {
|
||||
define void @test_simplify2() {
|
||||
; CHECK: @test_simplify2
|
||||
%dst = getelementptr inbounds [60 x i8]* @a, i32 0, i32 0
|
||||
%src = getelementptr inbounds [8 x i8]* @.str, i32 0, i32 0
|
||||
%src = getelementptr inbounds [12 x i8]* @.str, i32 0, i32 0
|
||||
|
||||
; CHECK-NEXT: call i8* @strcpy
|
||||
call i8* @__strcpy_chk(i8* %dst, i8* %src, i32 8)
|
||||
; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32
|
||||
call i8* @__strcpy_chk(i8* %dst, i8* %src, i32 12)
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @test_simplify3() {
|
||||
; CHECK: @test_simplify3
|
||||
%dst = getelementptr inbounds [60 x i8]* @a, i32 0, i32 0
|
||||
%src = getelementptr inbounds [8 x i8]* @.str, i32 0, i32 0
|
||||
%src = getelementptr inbounds [12 x i8]* @.str, i32 0, i32 0
|
||||
|
||||
; CHECK-NEXT: call i8* @strcpy
|
||||
; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32
|
||||
call i8* @__strcpy_chk(i8* %dst, i8* %src, i32 -1)
|
||||
ret void
|
||||
}
|
||||
@ -53,6 +53,33 @@ define void @test_simplify4() {
|
||||
ret void
|
||||
}
|
||||
|
||||
; Check case where the string length is not constant.
|
||||
|
||||
define void @test_simplify5() {
|
||||
; CHECK: @test_simplify5
|
||||
%dst = getelementptr inbounds [60 x i8]* @a, i32 0, i32 0
|
||||
%src = getelementptr inbounds [12 x i8]* @.str, i32 0, i32 0
|
||||
|
||||
; CHECK: @__memcpy_chk
|
||||
%len = call i32 @llvm.objectsize.i32(i8* %dst, i1 false)
|
||||
call i8* @__strcpy_chk(i8* %dst, i8* %src, i32 %len)
|
||||
ret void
|
||||
}
|
||||
|
||||
; Check case where the source and destination are the same.
|
||||
|
||||
define i8* @test_simplify6() {
|
||||
; CHECK: @test_simplify6
|
||||
%dst = getelementptr inbounds [60 x i8]* @a, i32 0, i32 0
|
||||
|
||||
; CHECK: getelementptr inbounds ([60 x i8]* @a, i32 0, i32 0)
|
||||
%len = call i32 @llvm.objectsize.i32(i8* %dst, i1 false)
|
||||
%ret = call i8* @__strcpy_chk(i8* %dst, i8* %dst, i32 %len)
|
||||
ret i8* %ret
|
||||
}
|
||||
|
||||
; Check case where slen < strlen (src).
|
||||
|
||||
define void @test_no_simplify1() {
|
||||
; CHECK: @test_no_simplify1
|
||||
%dst = getelementptr inbounds [60 x i8]* @a, i32 0, i32 0
|
||||
@ -63,26 +90,5 @@ define void @test_no_simplify1() {
|
||||
ret void
|
||||
}
|
||||
|
||||
; Check case were slen < strlen (src).
|
||||
|
||||
define void @test_no_simplify2() {
|
||||
; CHECK: @test_no_simplify2
|
||||
%dst = getelementptr inbounds [60 x i8]* @a, i32 0, i32 0
|
||||
%src = getelementptr inbounds [8 x i8]* @.str, i32 0, i32 0
|
||||
|
||||
; CHECK-NEXT: call i8* @__strcpy_chk
|
||||
call i8* @__strcpy_chk(i8* %dst, i8* %src, i32 3)
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @test_no_simplify3() {
|
||||
; CHECK: @test_no_simplify3
|
||||
%dst = getelementptr inbounds [60 x i8]* @a, i32 0, i32 0
|
||||
%src = getelementptr inbounds [8 x i8]* @.str, i32 0, i32 0
|
||||
|
||||
; CHECK-NEXT: call i8* @__strcpy_chk
|
||||
call i8* @__strcpy_chk(i8* %dst, i8* %src, i32 0)
|
||||
ret void
|
||||
}
|
||||
|
||||
declare i8* @__strcpy_chk(i8*, i8*, i32) nounwind
|
||||
declare i32 @llvm.objectsize.i32(i8*, i1) nounwind readonly
|
||||
|
@ -1,37 +0,0 @@
|
||||
; Test that the StrCpyOptimizer 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* @strcpy(i8*, i8*)
|
||||
|
||||
declare i8* @__strcpy_chk(i8*, i8*, i32) nounwind
|
||||
|
||||
declare i32 @llvm.objectsize.i32(i8*, i1) nounwind readonly
|
||||
|
||||
; rdar://6839935
|
||||
|
||||
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* @strcpy( 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* @__strcpy_chk(i8* %arg1, i8* %arg2, i32 %tmp1)
|
||||
; CHECK: @__memcpy_chk
|
||||
ret i32 0
|
||||
}
|
Loading…
Reference in New Issue
Block a user