diff options
-rw-r--r-- | lib/CodeGen/CGCall.cpp | 24 | ||||
-rw-r--r-- | test/CodeGen/x86_64-arguments.c | 20 |
2 files changed, 32 insertions, 12 deletions
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index c470918dde..ab933c52b4 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -692,12 +692,12 @@ static llvm::Value *CreateCoercedLoad(llvm::Value *SrcPtr, // Otherwise do coercion through memory. This is stupid, but // simple. llvm::Value *Tmp = CGF.CreateTempAlloca(Ty); - llvm::Value *Casted = - CGF.Builder.CreateBitCast(Tmp, llvm::PointerType::getUnqual(SrcTy)); - llvm::StoreInst *Store = - CGF.Builder.CreateStore(CGF.Builder.CreateLoad(SrcPtr), Casted); - // FIXME: Use better alignment / avoid requiring aligned store. - Store->setAlignment(1); + llvm::Type *I8PtrTy = CGF.Builder.getInt8PtrTy(); + llvm::Value *Casted = CGF.Builder.CreateBitCast(Tmp, I8PtrTy); + llvm::Value *SrcCasted = CGF.Builder.CreateBitCast(SrcPtr, I8PtrTy); + CGF.Builder.CreateMemCpy(Casted, SrcCasted, + llvm::ConstantInt::get(CGF.IntPtrTy, SrcSize), + 1, false); return CGF.Builder.CreateLoad(Tmp); } @@ -779,12 +779,12 @@ static void CreateCoercedStore(llvm::Value *Src, // to that information. llvm::Value *Tmp = CGF.CreateTempAlloca(SrcTy); CGF.Builder.CreateStore(Src, Tmp); - llvm::Value *Casted = - CGF.Builder.CreateBitCast(Tmp, llvm::PointerType::getUnqual(DstTy)); - llvm::LoadInst *Load = CGF.Builder.CreateLoad(Casted); - // FIXME: Use better alignment / avoid requiring aligned load. - Load->setAlignment(1); - CGF.Builder.CreateStore(Load, DstPtr, DstIsVolatile); + llvm::Type *I8PtrTy = CGF.Builder.getInt8PtrTy(); + llvm::Value *Casted = CGF.Builder.CreateBitCast(Tmp, I8PtrTy); + llvm::Value *DstCasted = CGF.Builder.CreateBitCast(DstPtr, I8PtrTy); + CGF.Builder.CreateMemCpy(DstCasted, Casted, + llvm::ConstantInt::get(CGF.IntPtrTy, DstSize), + 1, false); } } diff --git a/test/CodeGen/x86_64-arguments.c b/test/CodeGen/x86_64-arguments.c index f73e1f026a..b39fa1d349 100644 --- a/test/CodeGen/x86_64-arguments.c +++ b/test/CodeGen/x86_64-arguments.c @@ -354,3 +354,23 @@ void test46() { v46 x = {1,2}; f46(x,x,x,x,x,x,x,x,x,x); } struct s47 { unsigned a; }; void f47(int,int,int,int,int,int,struct s47); void test47(int a, struct s47 b) { f47(a, a, a, a, a, a, b); } + +// rdar://12723368 +// In the following example, there are holes in T4 at the 3rd byte and the 4th +// byte, however, T2 does not have those holes. T4 is chosen to be the +// representing type for union T1, but we can't use load or store of T4 since +// it will skip the 3rd byte and the 4th byte. +// In general, Since we don't accurately represent the data fields of a union, +// do not use load or store of the representing llvm type for the union. +typedef _Complex int T2; +typedef _Complex char T5; +typedef _Complex int T7; +typedef struct T4 { T5 field0; T7 field1; } T4; +typedef union T1 { T2 field0; T4 field1; } T1; +extern T1 T1_retval; +T1 test48(void) { +// CHECK: @test48 +// CHECK-NOT: load %struct.T4* %{{.*}} +// CHECK-NOT: store %struct.T4 %{{.*}}, %struct.T4* %{{.*}} + return T1_retval; +} |