r208458 - MS ABI: Pass 'sret' as the second parameter of instance methods

Reid Kleckner reid at kleckner.net
Fri May 9 15:46:16 PDT 2014


Author: rnk
Date: Fri May  9 17:46:15 2014
New Revision: 208458

URL: http://llvm.org/viewvc/llvm-project?rev=208458&view=rev
Log:
MS ABI: Pass 'sret' as the second parameter of instance methods

Summary:
MSVC always passes 'sret' after 'this', unlike GCC.  This required
changing a number of places in Clang that assumed the sret parameter was
always first in LLVM IR.

This fixes win64 MSVC ABI compatibility for methods returning structs.

Reviewers: rsmith, majnemer

Subscribers: cfe-commits

Differential Revision: http://reviews.llvm.org/D3618

Modified:
    cfe/trunk/include/clang/CodeGen/CGFunctionInfo.h
    cfe/trunk/lib/CodeGen/CGCXXABI.h
    cfe/trunk/lib/CodeGen/CGCall.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
    cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
    cfe/trunk/lib/CodeGen/TargetInfo.cpp
    cfe/trunk/test/CodeGenCXX/microsoft-abi-cdecl-method-sret.cpp
    cfe/trunk/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp
    cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-member-pointers.cpp

Modified: cfe/trunk/include/clang/CodeGen/CGFunctionInfo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/CodeGen/CGFunctionInfo.h?rev=208458&r1=208457&r2=208458&view=diff
==============================================================================
--- cfe/trunk/include/clang/CodeGen/CGFunctionInfo.h (original)
+++ cfe/trunk/include/clang/CodeGen/CGFunctionInfo.h Fri May  9 17:46:15 2014
@@ -82,9 +82,10 @@ private:
   };
   Kind TheKind;
   bool PaddingInReg : 1;
-  bool InAllocaSRet : 1;    // isInAlloca
+  bool InAllocaSRet : 1;    // isInAlloca()
   bool IndirectByVal : 1;   // isIndirect()
   bool IndirectRealign : 1; // isIndirect()
+  bool SRetAfterThis : 1;   // isIndirect()
   bool InReg : 1;           // isDirect() || isExtend() || isIndirect()
 
   ABIArgInfo(Kind K)
@@ -129,6 +130,7 @@ public:
     AI.setIndirectAlign(Alignment);
     AI.setIndirectByVal(ByVal);
     AI.setIndirectRealign(Realign);
+    AI.setSRetAfterThis(false);
     AI.setPaddingType(Padding);
     return AI;
   }
@@ -233,6 +235,15 @@ public:
     IndirectRealign = IR;
   }
 
+  bool isSRetAfterThis() const {
+    assert(isIndirect() && "Invalid kind!");
+    return SRetAfterThis;
+  }
+  void setSRetAfterThis(bool AfterThis) {
+    assert(isIndirect() && "Invalid kind!");
+    SRetAfterThis = AfterThis;
+  }
+
   unsigned getInAllocaFieldIndex() const {
     assert(isInAlloca() && "Invalid kind!");
     return AllocaFieldIndex;

Modified: cfe/trunk/lib/CodeGen/CGCXXABI.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.h?rev=208458&r1=208457&r2=208458&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXXABI.h (original)
+++ cfe/trunk/lib/CodeGen/CGCXXABI.h Fri May  9 17:46:15 2014
@@ -114,6 +114,10 @@ public:
   /// Returns how an argument of the given record type should be passed.
   virtual RecordArgABI getRecordArgABI(const CXXRecordDecl *RD) const = 0;
 
+  /// Returns true if the implicit 'sret' parameter comes after the implicit
+  /// 'this' parameter of C++ instance methods.
+  virtual bool isSRetParameterAfterThis() const { return false; }
+
   /// Find the LLVM type used to represent the given member pointer
   /// type.
   virtual llvm::Type *

Modified: cfe/trunk/lib/CodeGen/CGCall.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCall.cpp?rev=208458&r1=208457&r2=208458&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCall.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCall.cpp Fri May  9 17:46:15 2014
@@ -940,6 +940,7 @@ CodeGenTypes::GetFunctionType(const CGFu
   bool Inserted = FunctionsBeingProcessed.insert(&FI); (void)Inserted;
   assert(Inserted && "Recursively being processed?");
   
+  bool SwapThisWithSRet = false;
   SmallVector<llvm::Type*, 8> argTypes;
   llvm::Type *resultType = 0;
 
@@ -973,6 +974,8 @@ CodeGenTypes::GetFunctionType(const CGFu
     llvm::Type *ty = ConvertType(ret);
     unsigned addressSpace = Context.getTargetAddressSpace(ret);
     argTypes.push_back(llvm::PointerType::get(ty, addressSpace));
+
+    SwapThisWithSRet = retAI.isSRetAfterThis();
     break;
   }
 
@@ -1035,6 +1038,9 @@ CodeGenTypes::GetFunctionType(const CGFu
   if (llvm::StructType *ArgStruct = FI.getArgStruct())
     argTypes.push_back(ArgStruct->getPointerTo());
 
+  if (SwapThisWithSRet)
+    std::swap(argTypes[0], argTypes[1]);
+
   bool Erased = FunctionsBeingProcessed.erase(&FI); (void)Erased;
   assert(Erased && "Not in set?");
   
@@ -1149,6 +1155,7 @@ void CodeGenModule::ConstructAttributeLi
 
   QualType RetTy = FI.getReturnType();
   unsigned Index = 1;
+  bool SwapThisWithSRet = false;
   const ABIArgInfo &RetAI = FI.getReturnInfo();
   switch (RetAI.getKind()) {
   case ABIArgInfo::Extend:
@@ -1176,10 +1183,12 @@ void CodeGenModule::ConstructAttributeLi
     SRETAttrs.addAttribute(llvm::Attribute::StructRet);
     if (RetAI.getInReg())
       SRETAttrs.addAttribute(llvm::Attribute::InReg);
-    PAL.push_back(llvm::
-                  AttributeSet::get(getLLVMContext(), Index, SRETAttrs));
+    SwapThisWithSRet = RetAI.isSRetAfterThis();
+    PAL.push_back(llvm::AttributeSet::get(
+        getLLVMContext(), SwapThisWithSRet ? 2 : Index, SRETAttrs));
 
-    ++Index;
+    if (!SwapThisWithSRet)
+      ++Index;
     // sret disables readnone and readonly
     FuncAttrs.removeAttribute(llvm::Attribute::ReadOnly)
       .removeAttribute(llvm::Attribute::ReadNone);
@@ -1201,6 +1210,11 @@ void CodeGenModule::ConstructAttributeLi
     const ABIArgInfo &AI = I.info;
     llvm::AttrBuilder Attrs;
 
+    // Skip over the sret parameter when it comes second.  We already handled it
+    // above.
+    if (Index == 2 && SwapThisWithSRet)
+      ++Index;
+
     if (AI.getPaddingType()) {
       if (AI.getPaddingInReg())
         PAL.push_back(llvm::AttributeSet::get(getLLVMContext(), Index,
@@ -1344,13 +1358,20 @@ void CodeGenFunction::EmitFunctionProlog
     assert(ArgStruct->getType() == FI.getArgStruct()->getPointerTo());
   }
 
-  // Name the struct return argument.
-  if (CGM.ReturnTypeUsesSRet(FI)) {
+  // Name the struct return parameter, which can come first or second.
+  const ABIArgInfo &RetAI = FI.getReturnInfo();
+  bool SwapThisWithSRet = false;
+  if (RetAI.isIndirect()) {
+    SwapThisWithSRet = RetAI.isSRetAfterThis();
+    if (SwapThisWithSRet)
+      ++AI;
     AI->setName("agg.result");
-    AI->addAttr(llvm::AttributeSet::get(getLLVMContext(),
-                                        AI->getArgNo() + 1,
+    AI->addAttr(llvm::AttributeSet::get(getLLVMContext(), AI->getArgNo() + 1,
                                         llvm::Attribute::NoAlias));
-    ++AI;
+    if (SwapThisWithSRet)
+      --AI;  // Go back to the beginning for 'this'.
+    else
+      ++AI;  // Skip the sret parameter.
   }
 
   // Track if we received the parameter as a pointer (indirect, byval, or
@@ -1580,6 +1601,9 @@ void CodeGenFunction::EmitFunctionProlog
     }
 
     ++AI;
+
+    if (ArgNo == 1 && SwapThisWithSRet)
+      ++AI;  // Skip the sret parameter.
   }
 
   if (FI.usesInAlloca())
@@ -1822,13 +1846,15 @@ void CodeGenFunction::EmitFunctionEpilog
     break;
 
   case ABIArgInfo::Indirect: {
+    auto AI = CurFn->arg_begin();
+    if (RetAI.isSRetAfterThis())
+      ++AI;
     switch (getEvaluationKind(RetTy)) {
     case TEK_Complex: {
       ComplexPairTy RT =
         EmitLoadOfComplex(MakeNaturalAlignAddrLValue(ReturnValue, RetTy),
                           EndLoc);
-      EmitStoreOfComplex(RT,
-                       MakeNaturalAlignAddrLValue(CurFn->arg_begin(), RetTy),
+      EmitStoreOfComplex(RT, MakeNaturalAlignAddrLValue(AI, RetTy),
                          /*isInit*/ true);
       break;
     }
@@ -1837,7 +1863,7 @@ void CodeGenFunction::EmitFunctionEpilog
       break;
     case TEK_Scalar:
       EmitStoreOfScalar(Builder.CreateLoad(ReturnValue),
-                        MakeNaturalAlignAddrLValue(CurFn->arg_begin(), RetTy),
+                        MakeNaturalAlignAddrLValue(AI, RetTy),
                         /*isInit*/ true);
       break;
     }
@@ -2600,13 +2626,19 @@ RValue CodeGenFunction::EmitCall(const C
   // If the call returns a temporary with struct return, create a temporary
   // alloca to hold the result, unless one is given to us.
   llvm::Value *SRetPtr = 0;
-  if (CGM.ReturnTypeUsesSRet(CallInfo) || RetAI.isInAlloca()) {
+  bool SwapThisWithSRet = false;
+  if (RetAI.isIndirect() || RetAI.isInAlloca()) {
     SRetPtr = ReturnValue.getValue();
     if (!SRetPtr)
       SRetPtr = CreateMemTemp(RetTy);
-    if (CGM.ReturnTypeUsesSRet(CallInfo)) {
+    if (RetAI.isIndirect()) {
       Args.push_back(SRetPtr);
+      SwapThisWithSRet = RetAI.isSRetAfterThis();
+      if (SwapThisWithSRet)
+        IRArgNo = 1;
       checkArgMatches(SRetPtr, IRArgNo, IRFuncTy);
+      if (SwapThisWithSRet)
+        IRArgNo = 0;
     } else {
       llvm::Value *Addr =
           Builder.CreateStructGEP(ArgMemory, RetAI.getInAllocaFieldIndex());
@@ -2622,6 +2654,10 @@ RValue CodeGenFunction::EmitCall(const C
     const ABIArgInfo &ArgInfo = info_it->info;
     RValue RV = I->RV;
 
+    // Skip 'sret' if it came second.
+    if (IRArgNo == 1 && SwapThisWithSRet)
+      ++IRArgNo;
+
     CharUnits TypeAlign = getContext().getTypeAlignInChars(I->Ty);
 
     // Insert a padding argument to ensure proper alignment.
@@ -2811,6 +2847,9 @@ RValue CodeGenFunction::EmitCall(const C
     }
   }
 
+  if (SwapThisWithSRet)
+    std::swap(Args[0], Args[1]);
+
   if (ArgMemory) {
     llvm::Value *Arg = ArgMemory;
     llvm::Type *LastParamTy =

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.cpp?rev=208458&r1=208457&r2=208458&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.cpp Fri May  9 17:46:15 2014
@@ -622,7 +622,10 @@ void CodeGenFunction::StartFunction(Glob
              !hasScalarEvaluationKind(CurFnInfo->getReturnType())) {
     // Indirect aggregate return; emit returned value directly into sret slot.
     // This reduces code size, and affects correctness in C++.
-    ReturnValue = CurFn->arg_begin();
+    auto AI = CurFn->arg_begin();
+    if (CurFnInfo->getReturnInfo().isSRetAfterThis())
+      ++AI;
+    ReturnValue = AI;
   } else if (CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::InAlloca &&
              !hasScalarEvaluationKind(CurFnInfo->getReturnType())) {
     // Load the sret pointer from the argument struct and return into that.

Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=208458&r1=208457&r2=208458&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Fri May  9 17:46:15 2014
@@ -46,6 +46,8 @@ public:
 
   RecordArgABI getRecordArgABI(const CXXRecordDecl *RD) const override;
 
+  bool isSRetParameterAfterThis() const override { return true; }
+
   StringRef GetPureVirtualCallName() override { return "_purecall"; }
   // No known support for deleted functions in MSVC yet, so this choice is
   // arbitrary.

Modified: cfe/trunk/lib/CodeGen/TargetInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/TargetInfo.cpp?rev=208458&r1=208457&r2=208458&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/TargetInfo.cpp (original)
+++ cfe/trunk/lib/CodeGen/TargetInfo.cpp Fri May  9 17:46:15 2014
@@ -992,13 +992,13 @@ void X86_32ABIInfo::computeInfo(CGFuncti
   FI.getReturnInfo() =
       classifyReturnType(FI.getReturnType(), State, FI.isInstanceMethod());
 
-  // On win32, use the x86_cdeclmethodcc convention for cdecl methods that use
-  // sret.  This convention swaps the order of the first two parameters behind
-  // the scenes to match MSVC.
+  // On win32, swap the order of the first two parameters for instance methods
+  // which are sret behind the scenes to match MSVC.
   if (IsWin32StructABI && FI.isInstanceMethod() &&
-      FI.getCallingConvention() == llvm::CallingConv::C &&
-      FI.getReturnInfo().isIndirect())
-    FI.setEffectiveCallingConvention(llvm::CallingConv::X86_CDeclMethod);
+      FI.getReturnInfo().isIndirect()) {
+    assert(FI.arg_size() >= 1 && "instance method should have this");
+    FI.getReturnInfo().setSRetAfterThis(true);
+  }
 
   bool UsedInAlloca = false;
   for (auto &I : FI.arguments()) {
@@ -2768,6 +2768,14 @@ void WinX86_64ABIInfo::computeInfo(CGFun
   QualType RetTy = FI.getReturnType();
   FI.getReturnInfo() = classify(RetTy, true);
 
+  // On win64, swap the order of the first two parameters for instance methods
+  // which are sret behind the scenes to match MSVC.
+  if (FI.getReturnInfo().isIndirect() && FI.isInstanceMethod() &&
+      getCXXABI().isSRetParameterAfterThis()) {
+    assert(FI.arg_size() >= 1 && "instance method should have this");
+    FI.getReturnInfo().setSRetAfterThis(true);
+  }
+
   for (auto &I : FI.arguments())
     I.info = classify(I.type, false);
 }

Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-cdecl-method-sret.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-cdecl-method-sret.cpp?rev=208458&r1=208457&r2=208458&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-cdecl-method-sret.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-cdecl-method-sret.cpp Fri May  9 17:46:15 2014
@@ -19,9 +19,9 @@ S C::variadic_sret(const char *f, ...) {
 S C::cdecl_sret() { return S(); }
 S C::byval_and_sret(S a) { return S(); }
 
-// CHECK: define x86_cdeclmethodcc void @"\01?variadic_sret at C@@QAA?AUS@@PBDZZ"(%struct.S* noalias sret %agg.result, %struct.C* %this, i8* %f, ...)
-// CHECK: define x86_cdeclmethodcc void @"\01?cdecl_sret at C@@QAA?AUS@@XZ"(%struct.S* noalias sret %agg.result, %struct.C* %this)
-// CHECK: define x86_cdeclmethodcc void @"\01?byval_and_sret at C@@QAA?AUS@@U2@@Z"(%struct.S* noalias sret %agg.result, %struct.C* %this, %struct.S* byval align 4 %a)
+// CHECK: define void @"\01?variadic_sret at C@@QAA?AUS@@PBDZZ"(%struct.C* %this, %struct.S* noalias sret %agg.result, i8* %f, ...)
+// CHECK: define void @"\01?cdecl_sret at C@@QAA?AUS@@XZ"(%struct.C* %this, %struct.S* noalias sret %agg.result)
+// CHECK: define void @"\01?byval_and_sret at C@@QAA?AUS@@U2@@Z"(%struct.C* %this, %struct.S* noalias sret %agg.result, %struct.S* byval align 4 %a)
 
 int main() {
   C c;
@@ -30,6 +30,6 @@ int main() {
   c.byval_and_sret(S());
 }
 // CHECK-LABEL: define i32 @main()
-// CHECK: call x86_cdeclmethodcc void {{.*}} @"\01?variadic_sret at C@@QAA?AUS@@PBDZZ"
-// CHECK: call x86_cdeclmethodcc void @"\01?cdecl_sret at C@@QAA?AUS@@XZ"
-// CHECK: call x86_cdeclmethodcc void @"\01?byval_and_sret at C@@QAA?AUS@@U2@@Z"
+// CHECK: call void {{.*}} @"\01?variadic_sret at C@@QAA?AUS@@PBDZZ"
+// CHECK: call void @"\01?cdecl_sret at C@@QAA?AUS@@XZ"
+// CHECK: call void @"\01?byval_and_sret at C@@QAA?AUS@@U2@@Z"

Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp?rev=208458&r1=208457&r2=208458&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp Fri May  9 17:46:15 2014
@@ -201,19 +201,19 @@ class Class {
  public:
   Small thiscall_method_small() { return Small(); }
   // LINUX: define {{.*}} void @_ZN5Class21thiscall_method_smallEv(%struct.Small* noalias sret %agg.result, %class.Class* %this)
-  // WIN32: define {{.*}} x86_thiscallcc void @"\01?thiscall_method_small at Class@@QAE?AUSmall@@XZ"(%struct.Small* noalias sret %agg.result, %class.Class* %this)
+  // WIN32: define {{.*}} x86_thiscallcc void @"\01?thiscall_method_small at Class@@QAE?AUSmall@@XZ"(%class.Class* %this, %struct.Small* noalias sret %agg.result)
 
   SmallWithCtor thiscall_method_small_with_ctor() { return SmallWithCtor(); }
   // LINUX: define {{.*}} void @_ZN5Class31thiscall_method_small_with_ctorEv(%struct.SmallWithCtor* noalias sret %agg.result, %class.Class* %this)
-  // WIN32: define {{.*}} x86_thiscallcc void @"\01?thiscall_method_small_with_ctor at Class@@QAE?AUSmallWithCtor@@XZ"(%struct.SmallWithCtor* noalias sret %agg.result, %class.Class* %this)
+  // WIN32: define {{.*}} x86_thiscallcc void @"\01?thiscall_method_small_with_ctor at Class@@QAE?AUSmallWithCtor@@XZ"(%class.Class* %this, %struct.SmallWithCtor* noalias sret %agg.result)
 
   Small __cdecl cdecl_method_small() { return Small(); }
   // LINUX: define {{.*}} void @_ZN5Class18cdecl_method_smallEv(%struct.Small* noalias sret %agg.result, %class.Class* %this)
-  // WIN32: define {{.*}} void @"\01?cdecl_method_small at Class@@QAA?AUSmall@@XZ"(%struct.Small* noalias sret %agg.result, %class.Class* %this)
+  // WIN32: define {{.*}} void @"\01?cdecl_method_small at Class@@QAA?AUSmall@@XZ"(%class.Class* %this, %struct.Small* noalias sret %agg.result)
 
   Big __cdecl cdecl_method_big() { return Big(); }
   // LINUX: define {{.*}} void @_ZN5Class16cdecl_method_bigEv(%struct.Big* noalias sret %agg.result, %class.Class* %this)
-  // WIN32: define {{.*}} void @"\01?cdecl_method_big at Class@@QAA?AUBig@@XZ"(%struct.Big* noalias sret %agg.result, %class.Class* %this)
+  // WIN32: define {{.*}} void @"\01?cdecl_method_big at Class@@QAA?AUBig@@XZ"(%class.Class* %this, %struct.Big* noalias sret %agg.result)
 
   void thiscall_method_arg(Empty s) {}
   // LINUX: define {{.*}} void @_ZN5Class19thiscall_method_argE5Empty(%class.Class* %this)

Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-member-pointers.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-member-pointers.cpp?rev=208458&r1=208457&r2=208458&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-member-pointers.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-member-pointers.cpp Fri May  9 17:46:15 2014
@@ -34,14 +34,14 @@ void f() {
 // CHECK32-LABEL: define void @"\01?f@@YAXXZ"()
 // CHECK32: store i8* bitcast (void (%struct.C*)* @"\01??_9C@@$BA at AE" to i8*), i8** %ptr
 // CHECK32: store i8* bitcast (i32 (%struct.C*, i32, double)* @"\01??_9C@@$B3AE" to i8*), i8** %ptr2
-// CHECK32: store i8* bitcast (void (%struct.S*, %struct.C*, i32)* @"\01??_9C@@$B7AE" to i8*), i8** %ptr3
+// CHECK32: store i8* bitcast (void (%struct.C*, %struct.S*, i32)* @"\01??_9C@@$B7AE" to i8*), i8** %ptr3
 // CHECK32: store i8* bitcast (void (%"struct.(anonymous namespace)::D"*)* @"\01??_9D@?A@@$BA at AE" to i8*), i8** %ptr4
 // CHECK32: }
 //
 // CHECK64-LABEL: define void @"\01?f@@YAXXZ"()
 // CHECK64: store i8* bitcast (void (%struct.C*)* @"\01??_9C@@$BA at AA" to i8*), i8** %ptr
 // CHECK64: store i8* bitcast (i32 (%struct.C*, i32, double)* @"\01??_9C@@$B7AA" to i8*), i8** %ptr2
-// CHECK64: store i8* bitcast (void (%struct.S*, %struct.C*, i32)* @"\01??_9C@@$BBA at AA" to i8*), i8** %ptr3
+// CHECK64: store i8* bitcast (void (%struct.C*, %struct.S*, i32)* @"\01??_9C@@$BBA at AA" to i8*), i8** %ptr3
 // CHECK64: store i8* bitcast (void (%"struct.(anonymous namespace)::D"*)* @"\01??_9D@?A@@$BA at AA" to i8*), i8** %ptr
 // CHECK64: }
 }
@@ -78,17 +78,17 @@ void f() {
 // CHECK64: }
 
 // Thunk for calling the 3rd virtual function in C, taking an int parameter, returning a struct.
-// CHECK32-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@@$B7AE"(%struct.S* noalias sret %agg.result, %struct.C* %this, i32) unnamed_addr
-// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.S*, %struct.C*, i32)** %{{.*}}, i64 2
-// CHECK32: [[CALLEE:%.*]] = load void (%struct.S*, %struct.C*, i32)** [[VPTR]]
-// CHECK32: call x86_thiscallcc void [[CALLEE]](%struct.S* sret %agg.result, %struct.C* %{{.*}}, i32 %{{.*}})
+// CHECK32-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@@$B7AE"(%struct.C* %this, %struct.S* noalias sret %agg.result, i32) unnamed_addr
+// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, %struct.S*, i32)** %{{.*}}, i64 2
+// CHECK32: [[CALLEE:%.*]] = load void (%struct.C*, %struct.S*, i32)** [[VPTR]]
+// CHECK32: call x86_thiscallcc void [[CALLEE]](%struct.C* %{{.*}}, %struct.S* sret %agg.result, i32 %{{.*}})
 // CHECK32: ret void
 // CHECK32: }
 //
-// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BBA at AA"(%struct.S* noalias sret %agg.result, %struct.C* %this, i32) unnamed_addr
-// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.S*, %struct.C*, i32)** %{{.*}}, i64 2
-// CHECK64: [[CALLEE:%.*]] = load void (%struct.S*, %struct.C*, i32)** [[VPTR]]
-// CHECK64: call void [[CALLEE]](%struct.S* sret %agg.result, %struct.C* %{{.*}}, i32 %{{.*}})
+// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BBA at AA"(%struct.C* %this, %struct.S* noalias sret %agg.result, i32) unnamed_addr
+// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, %struct.S*, i32)** %{{.*}}, i64 2
+// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*, %struct.S*, i32)** [[VPTR]]
+// CHECK64: call void [[CALLEE]](%struct.C* %{{.*}}, %struct.S* sret %agg.result, i32 %{{.*}})
 // CHECK64: ret void
 // CHECK64: }
 





More information about the cfe-commits mailing list