]> granicus.if.org Git - clang/commitdiff
Apply the same fundamental fix for PR14048 as was applied for PR11905.
authorChandler Carruth <chandlerc@gmail.com>
Wed, 10 Oct 2012 11:29:08 +0000 (11:29 +0000)
committerChandler Carruth <chandlerc@gmail.com>
Wed, 10 Oct 2012 11:29:08 +0000 (11:29 +0000)
The issue arises when coercing to/from types of different sizes. We need
to be certain that the allocation on either end has sufficient room for
the coerced type. When it doesn't, we need to make room, copy across,
and then proceed. PR11905 handled the case of storing function arguments
back into allocas in the function prolog, this patch handles the case of
setting up the function arguments in a call expression.

This is actually significantly simpler than the fix for PR11905. It ends
up being a trivial change to create a temporary alloca when the source
is too small and memcpy across. This should preserve the compile-time
fast-isel benefits of doing gep+load sequences and avoiding FCAs.

Reviewed by Benjamin and Evgeniy (who fixed PR11905).

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@165615 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGCall.cpp
test/CodeGen/arm-arguments.c

index 562c17ded393dd8692bcd6d760adb7376893c445..e8d99e2f5a01964f3e9173954181b702befdb6ac 100644 (file)
@@ -2073,8 +2073,25 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
       // and the optimizer generally likes scalar values better than FCAs.
       if (llvm::StructType *STy =
             dyn_cast<llvm::StructType>(ArgInfo.getCoerceToType())) {
-        SrcPtr = Builder.CreateBitCast(SrcPtr,
-                                       llvm::PointerType::getUnqual(STy));
+        llvm::Type *SrcTy =
+          cast<llvm::PointerType>(SrcPtr->getType())->getElementType();
+        uint64_t SrcSize = CGM.getDataLayout().getTypeAllocSize(SrcTy);
+        uint64_t DstSize = CGM.getDataLayout().getTypeAllocSize(STy);
+
+        // If the source type is smaller than the destination type of the
+        // coerce-to logic, copy the source value into a temp alloca the size
+        // of the destination type to allow loading all of it. The bits past
+        // the source value are left undef.
+        if (SrcSize < DstSize) {
+          llvm::AllocaInst *TempAlloca
+            = CreateTempAlloca(STy, SrcPtr->getName() + ".coerce");
+          Builder.CreateMemCpy(TempAlloca, SrcPtr, SrcSize, 0);
+          SrcPtr = TempAlloca;
+        } else {
+          SrcPtr = Builder.CreateBitCast(SrcPtr,
+                                         llvm::PointerType::getUnqual(STy));
+        }
+
         for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
           llvm::Value *EltPtr = Builder.CreateConstGEP2_32(SrcPtr, 0, i);
           llvm::LoadInst *LI = Builder.CreateLoad(EltPtr);
index 2ec729eb9b3dbfcecc9e1c2d579f78cca120fcdc..8aa33f696d72678df2b7fa64053ce3fa2526903b 100644 (file)
@@ -178,3 +178,16 @@ struct s33 { char buf[32*32]; };
 void f33(struct s33 s) { }
 // APCS-GNU: define void @f33(%struct.s33* byval %s)
 // AAPCS: define arm_aapcscc void @f33(%struct.s33* byval %s)
+
+// PR14048
+struct s34 { char c; };
+void f34(struct s34 s);
+void g34(struct s34 *s) { f34(*s); }
+// APCS-GNU: @g34(%struct.s34* %s)
+// APCS-GNU: %[[a:.*]] = alloca { [1 x i32] }
+// APCS-GNU: %[[gep:.*]] = getelementptr { [1 x i32] }* %[[a]], i32 0, i32 0
+// APCS-GNU: load [1 x i32]* %[[gep]]
+// AAPCS: @g34(%struct.s34* %s)
+// AAPCS: %[[a:.*]] = alloca { [1 x i32] }
+// AAPCS: %[[gep:.*]] = getelementptr { [1 x i32] }* %[[a]], i32 0, i32 0
+// AAPCS: load [1 x i32]* %[[gep]]