aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/CodeGen/CGCall.cpp24
-rw-r--r--test/CodeGen/x86_64-arguments.c20
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;
+}