aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/CodeGen/CGCall.cpp49
-rw-r--r--test/CodeGen/x86_64-arguments.c3
2 files changed, 50 insertions, 2 deletions
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index 7835505dcf..6151fa2ed4 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -378,6 +378,38 @@ EnterStructPointerForCoercedAccess(llvm::Value *SrcPtr,
return SrcPtr;
}
+/// CoerceIntOrPtrToIntOrPtr - Convert a value Val to the specific Ty where both
+/// are either integers or pointers. This does a truncation of the value if it
+/// is too large or a zero extension if it is too small.
+static llvm::Value *CoerceIntOrPtrToIntOrPtr(llvm::Value *Val,
+ const llvm::Type *Ty,
+ CodeGenFunction &CGF) {
+ if (Val->getType() == Ty)
+ return Val;
+
+ if (isa<llvm::PointerType>(Val->getType())) {
+ // If this is Pointer->Pointer avoid conversion to and from int.
+ if (isa<llvm::PointerType>(Ty))
+ return CGF.Builder.CreateBitCast(Val, Ty, "coerce.val");
+
+ // Convert the pointer to an integer so we can play with its width.
+ const llvm::Type *IntPtrTy = llvm::IntegerType::get(Ty->getContext(),
+ CGF.LLVMPointerWidth);
+ Val = CGF.Builder.CreatePtrToInt(Val, IntPtrTy, "coerce.val.pi");
+ }
+
+ const llvm::Type *DestIntTy = Ty;
+ if (isa<llvm::PointerType>(DestIntTy))
+ DestIntTy = llvm::IntegerType::get(Ty->getContext(), CGF.LLVMPointerWidth);
+
+ if (Val->getType() != DestIntTy)
+ Val = CGF.Builder.CreateIntCast(Val, DestIntTy, false, "coerce.val.ii");
+
+ if (isa<llvm::PointerType>(Ty))
+ Val = CGF.Builder.CreateIntToPtr(Val, Ty, "coerce.val.ip");
+ return Val;
+}
+
/// CreateCoercedLoad - Create a load from \arg SrcPtr interpreted as
@@ -400,6 +432,14 @@ static llvm::Value *CreateCoercedLoad(llvm::Value *SrcPtr,
uint64_t SrcSize = CGF.CGM.getTargetData().getTypeAllocSize(SrcTy);
+ // If the source and destination are integer or pointer types, just do an
+ // extension or truncation to the desired type.
+ if ((isa<llvm::IntegerType>(Ty) || isa<llvm::PointerType>(Ty)) &&
+ (isa<llvm::IntegerType>(SrcTy) || isa<llvm::PointerType>(SrcTy))) {
+ llvm::LoadInst *Load = CGF.Builder.CreateLoad(SrcPtr);
+ return CoerceIntOrPtrToIntOrPtr(Load, Ty, CGF);
+ }
+
// If load is legal, just bitcast the src pointer.
if (SrcSize >= DstSize) {
// Generally SrcSize is never greater than DstSize, since this means we are
@@ -448,6 +488,15 @@ static void CreateCoercedStore(llvm::Value *Src,
DstTy = cast<llvm::PointerType>(DstPtr->getType())->getElementType();
}
+ // If the source and destination are integer or pointer types, just do an
+ // extension or truncation to the desired type.
+ if ((isa<llvm::IntegerType>(SrcTy) || isa<llvm::PointerType>(SrcTy)) &&
+ (isa<llvm::IntegerType>(DstTy) || isa<llvm::PointerType>(DstTy))) {
+ Src = CoerceIntOrPtrToIntOrPtr(Src, DstTy, CGF);
+ CGF.Builder.CreateStore(Src, DstPtr, DstIsVolatile);
+ return;
+ }
+
uint64_t DstSize = CGF.CGM.getTargetData().getTypeAllocSize(DstTy);
// If store is legal, just bitcast the src pointer.
diff --git a/test/CodeGen/x86_64-arguments.c b/test/CodeGen/x86_64-arguments.c
index b53dfdf93d..d182aa25d9 100644
--- a/test/CodeGen/x86_64-arguments.c
+++ b/test/CodeGen/x86_64-arguments.c
@@ -93,8 +93,7 @@ void f17(float a, float b, float c, float d, float e, float f, float g, float h,
long double X) {}
// Check for valid coercion.
-// CHECK: [[f18_t0:%.*]] = bitcast i64* {{.*}} to i32*
-// CHECK: [[f18_t1:%.*]] = load i32* [[f18_t0]], align 1
+// CHECK: [[f18_t1:%.*]] = trunc i64 {{.*}} to i32
// CHECK: store i32 [[f18_t1]], i32*
struct f18_s0 { int f0; };
void f18(int a, struct f18_s0 f18_arg1) { while (1) {} }