diff options
author | Chris Lattner <sabre@nondot.org> | 2011-04-17 00:40:24 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2011-04-17 00:40:24 +0000 |
commit | a5e5e0f41e1dcee4603244ccea3d3956c55c23ac (patch) | |
tree | a5e450a8f3a27ad181a0656084c3b89cf6a197b9 | |
parent | c6bea67efc38b075c401ebdb6ae97afa08cbb51d (diff) |
fold memcpy/set/move_chk to llvm.memcpy/set/move when the sizes
are trivial. This exposes opportunities earlier, and allows fastisel
to do good things with these at -O0.
This addresses rdar://9289468 - clang doesn't fold memset_chk at -O0
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@129651 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/CodeGen/CGBuiltin.cpp | 51 | ||||
-rw-r--r-- | test/CodeGen/builtin-memfns.c | 29 | ||||
-rw-r--r-- | test/CodeGen/builtinmemcpy.c | 3 |
3 files changed, 78 insertions, 5 deletions
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index 97b93d5030..51d9eebaba 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -543,6 +543,22 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, return RValue::get(Address); } + case Builtin::BI__builtin___memcpy_chk: { + // fold __builtin_memcpy_chk(x, y, cst1, cst2) to memset iff cst1<=cst2. + if (!E->getArg(2)->isEvaluatable(CGM.getContext()) || + !E->getArg(3)->isEvaluatable(CGM.getContext())) + break; + llvm::APSInt Size = E->getArg(2)->EvaluateAsInt(CGM.getContext()); + llvm::APSInt DstSize = E->getArg(3)->EvaluateAsInt(CGM.getContext()); + if (Size.ugt(DstSize)) + break; + Value *Dest = EmitScalarExpr(E->getArg(0)); + Value *Src = EmitScalarExpr(E->getArg(1)); + Value *SizeVal = llvm::ConstantInt::get(Builder.getContext(), Size); + Builder.CreateMemCpy(Dest, Src, SizeVal, 1, false); + return RValue::get(0); + } + case Builtin::BI__builtin_objc_memmove_collectable: { Value *Address = EmitScalarExpr(E->getArg(0)); Value *SrcAddr = EmitScalarExpr(E->getArg(1)); @@ -551,7 +567,23 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Address, SrcAddr, SizeVal); return RValue::get(Address); } - + + case Builtin::BI__builtin___memmove_chk: { + // fold __builtin_memmove_chk(x, y, cst1, cst2) to memset iff cst1<=cst2. + if (!E->getArg(2)->isEvaluatable(CGM.getContext()) || + !E->getArg(3)->isEvaluatable(CGM.getContext())) + break; + llvm::APSInt Size = E->getArg(2)->EvaluateAsInt(CGM.getContext()); + llvm::APSInt DstSize = E->getArg(3)->EvaluateAsInt(CGM.getContext()); + if (Size.ugt(DstSize)) + break; + Value *Dest = EmitScalarExpr(E->getArg(0)); + Value *Src = EmitScalarExpr(E->getArg(1)); + Value *SizeVal = llvm::ConstantInt::get(Builder.getContext(), Size); + Builder.CreateMemMove(Dest, Src, SizeVal, 1, false); + return RValue::get(0); + } + case Builtin::BImemmove: case Builtin::BI__builtin_memmove: { Value *Address = EmitScalarExpr(E->getArg(0)); @@ -569,6 +601,23 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Builder.CreateMemSet(Address, ByteVal, SizeVal, 1, false); return RValue::get(Address); } + case Builtin::BI__builtin___memset_chk: { + // fold __builtin_memset_chk(x, y, cst1, cst2) to memset iff cst1<=cst2. + if (!E->getArg(2)->isEvaluatable(CGM.getContext()) || + !E->getArg(3)->isEvaluatable(CGM.getContext())) + break; + llvm::APSInt Size = E->getArg(2)->EvaluateAsInt(CGM.getContext()); + llvm::APSInt DstSize = E->getArg(3)->EvaluateAsInt(CGM.getContext()); + if (Size.ugt(DstSize)) + break; + Value *Address = EmitScalarExpr(E->getArg(0)); + Value *ByteVal = Builder.CreateTrunc(EmitScalarExpr(E->getArg(1)), + Builder.getInt8Ty()); + Value *SizeVal = llvm::ConstantInt::get(Builder.getContext(), Size); + Builder.CreateMemSet(Address, ByteVal, SizeVal, 1, false); + + return RValue::get(0); + } case Builtin::BI__builtin_dwarf_cfa: { // The offset in bytes from the first argument to the CFA. // diff --git a/test/CodeGen/builtin-memfns.c b/test/CodeGen/builtin-memfns.c index e8c407fd6f..2ea6793654 100644 --- a/test/CodeGen/builtin-memfns.c +++ b/test/CodeGen/builtin-memfns.c @@ -1,12 +1,13 @@ // RUN: %clang_cc1 -triple i386-pc-linux-gnu -emit-llvm < %s| FileCheck %s +// CHECK: @test1 // CHECK: call void @llvm.memset.p0i8.i32 // CHECK: call void @llvm.memset.p0i8.i32 // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32 // CHECK: call void @llvm.memmove.p0i8.p0i8.i32 // CHECK-NOT: __builtin // CHECK: ret -int main(int argc, char **argv) { +int test1(int argc, char **argv) { unsigned char a = 0x11223344; unsigned char b = 0x11223344; __builtin_bzero(&a, sizeof(a)); @@ -15,3 +16,29 @@ int main(int argc, char **argv) { __builtin_memmove(&a, &b, sizeof(a)); return 0; } + +// rdar://9289468 + +// CHECK: @test2 +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32 +char* test2(char* a, char* b) { + return __builtin_memcpy(a, b, 4); +} + +// CHECK: @test3 +// CHECK: call void @llvm.memset +void test3(char *P) { + __builtin___memset_chk(P, 42, 128, 128); +} + +// CHECK: @test4 +// CHECK: call void @llvm.memcpy +void test4(char *P, char *Q) { + __builtin___memcpy_chk(P, Q, 128, 128); +} + +// CHECK: @test5 +// CHECK: call void @llvm.memmove +void test5(char *P, char *Q) { + __builtin___memmove_chk(P, Q, 128, 128); +} diff --git a/test/CodeGen/builtinmemcpy.c b/test/CodeGen/builtinmemcpy.c deleted file mode 100644 index 93253c5a8a..0000000000 --- a/test/CodeGen/builtinmemcpy.c +++ /dev/null @@ -1,3 +0,0 @@ -// RUN: %clang_cc1 -emit-llvm < %s -o - | grep "llvm.memcpy" - -char* x(char* a, char* b) {return __builtin_memcpy(a, b, 4);} |