]> granicus.if.org Git - clang/commitdiff
MS ABI: Use the proper type for inalloca args
authorDavid Majnemer <david.majnemer@gmail.com>
Mon, 31 Mar 2014 16:12:47 +0000 (16:12 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Mon, 31 Mar 2014 16:12:47 +0000 (16:12 +0000)
Summary:
The definition of a type later in a translation unit may change it's
type from {}* to (%struct.foo*)*.  Earlier function definitions may use
the former while more recent definitions might use the later.  This is
fine until they interact with one another (like one calling the other).
In these cases, a bitcast is needed because the inalloca must match the
function call but the store to the lvalue which initializes the argument
slot has to match the rvalue's type.

This technique is along the same lines with what the other,
non-inalloca, codepaths perform.

This fixes PR19287.

Reviewers: rnk

CC: cfe-commits
Differential Revision: http://llvm-reviews.chandlerc.com/D3224

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

lib/CodeGen/CGCall.cpp
test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp

index 6bef76934e601d8a944e568a56e64f9fcca220c0..e26d6b2d0efb34a1608952713946a96cec3ce004 100644 (file)
@@ -2603,6 +2603,13 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
         // Store the RValue into the argument struct.
         llvm::Value *Addr =
             Builder.CreateStructGEP(ArgMemory, ArgInfo.getInAllocaFieldIndex());
+        unsigned AS = Addr->getType()->getPointerAddressSpace();
+        llvm::Type *MemType = ConvertTypeForMem(I->Ty)->getPointerTo(AS);
+        // There are some cases where a trivial bitcast is not avoidable.  The
+        // definition of a type later in a translation unit may change it's type
+        // from {}* to (%struct.foo*)*.
+        if (Addr->getType() != MemType)
+          Addr = Builder.CreateBitCast(Addr, MemType);
         LValue argLV = MakeAddrLValue(Addr, I->Ty, TypeAlign);
         EmitInitStoreOfNonAggregate(*this, RV, argLV);
       }
index 67cd98a34b12eedf0e6698d9f117f5a8c31bb956..216c6f28c24e6aa47c29e33d108bd0ee4a7bfd07 100644 (file)
@@ -263,3 +263,23 @@ void bar() {
 // WIN32: }
 
 }
+
+// We would crash here because the later definition of ForwardDeclare1 results
+// in a different IR type for the value we want to store.  However, the alloca's
+// type will use the argument type selected by fn1.
+struct ForwardDeclare1;
+
+typedef void (*FnPtr1)(ForwardDeclare1);
+void fn1(FnPtr1, SmallWithDtor) {}
+
+struct ForwardDeclare1 {};
+
+void fn2() { fn1(0, SmallWithDtor()); };
+// WIN32-LABEL: define void @"\01?fn2@@YAXXZ"
+// WIN32:   %[[argmem:[^ ]*]] = alloca inalloca [[argmem_ty:<{ {}\*, %struct.SmallWithDtor }>]]
+// WIN32:   getelementptr inbounds [[argmem_ty]]* %[[argmem]], i32 0, i32 1
+// WIN32:   call x86_thiscallcc %struct.SmallWithDtor* @"\01??0SmallWithDtor@@QAE@XZ"(%struct.SmallWithDtor* %0)
+// WIN32:   getelementptr inbounds [[argmem_ty]]* %[[argmem]], i32 0, i32 0
+// WIN32:   %[[addr:[^ ]*]] = bitcast {}** %1 to void [[dst_ty:\(%struct.ForwardDeclare1\*\)\*]]*
+// WIN32:   store void [[dst_ty]] null, void [[dst_ty]]* %[[addr]], align 4
+// WIN32:   call void @"\01?fn1@@YAXP6AXUForwardDeclare1@@@ZUSmallWithDtor@@@Z"([[argmem_ty]]* inalloca %[[argmem]])