r216782 - Make all virtual member pointers use variadic musttail calls

Reid Kleckner reid at kleckner.net
Fri Aug 29 14:43:29 PDT 2014


Author: rnk
Date: Fri Aug 29 16:43:29 2014
New Revision: 216782

URL: http://llvm.org/viewvc/llvm-project?rev=216782&view=rev
Log:
Make all virtual member pointers use variadic musttail calls

This avoids encoding information about the function prototype into the
thunk at the cost of some function prototype bitcast gymnastics.

Fixes PR20653.

Added:
    cfe/trunk/test/CodeGenCXX/microsoft-abi-vmemptr-conflicts.cpp
    cfe/trunk/test/CodeGenCXX/microsoft-abi-vmemptr-fastcall.cpp
Modified:
    cfe/trunk/lib/CodeGen/CGCall.cpp
    cfe/trunk/lib/CodeGen/CodeGenTypes.h
    cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
    cfe/trunk/test/CodeGenCXX/microsoft-abi-member-pointers.cpp
    cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-member-pointers.cpp

Modified: cfe/trunk/lib/CodeGen/CGCall.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCall.cpp?rev=216782&r1=216781&r2=216782&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCall.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCall.cpp Fri Aug 29 16:43:29 2014
@@ -332,6 +332,20 @@ CodeGenTypes::arrangeGlobalDeclaration(G
   return arrangeFunctionDeclaration(FD);
 }
 
+/// Arrange a thunk that takes 'this' as the first parameter followed by
+/// varargs.  Return a void pointer, regardless of the actual return type.
+/// The body of the thunk will end in a musttail call to a function of the
+/// correct type, and the caller will bitcast the function to the correct
+/// prototype.
+const CGFunctionInfo &
+CodeGenTypes::arrangeMSMemberPointerThunk(const CXXMethodDecl *MD) {
+  assert(MD->isVirtual() && "only virtual memptrs have thunks");
+  CanQual<FunctionProtoType> FTP = GetFormalType(MD);
+  CanQualType ArgTys[] = { GetThisType(Context, MD->getParent()) };
+  return arrangeLLVMFunctionInfo(Context.VoidTy, false, ArgTys,
+                                 FTP->getExtInfo(), RequiredArgs(1));
+}
+
 /// Arrange a call as unto a free function, except possibly with an
 /// additional number of formal parameters considered required.
 static const CGFunctionInfo &

Modified: cfe/trunk/lib/CodeGen/CodeGenTypes.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenTypes.h?rev=216782&r1=216781&r2=216782&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenTypes.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenTypes.h Fri Aug 29 16:43:29 2014
@@ -207,6 +207,7 @@ public:
   const CGFunctionInfo &arrangeCXXMethodCall(const CallArgList &args,
                                              const FunctionProtoType *type,
                                              RequiredArgs required);
+  const CGFunctionInfo &arrangeMSMemberPointerThunk(const CXXMethodDecl *MD);
 
   const CGFunctionInfo &arrangeFreeFunctionType(CanQual<FunctionProtoType> Ty);
   const CGFunctionInfo &arrangeFreeFunctionType(CanQual<FunctionNoProtoType> Ty);

Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=216782&r1=216781&r2=216782&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Fri Aug 29 16:43:29 2014
@@ -1434,6 +1434,9 @@ MicrosoftCXXABI::enumerateVBTables(const
 llvm::Function *MicrosoftCXXABI::EmitVirtualMemPtrThunk(
     const CXXMethodDecl *MD,
     const MicrosoftVTableContext::MethodVFTableLocation &ML) {
+  assert(!isa<CXXConstructorDecl>(MD) && !isa<CXXDestructorDecl>(MD) &&
+         "can't form pointers to ctors or virtual dtors");
+
   // Calculate the mangled name.
   SmallString<256> ThunkName;
   llvm::raw_svector_ostream Out(ThunkName);
@@ -1445,7 +1448,7 @@ llvm::Function *MicrosoftCXXABI::EmitVir
     return cast<llvm::Function>(GV);
 
   // Create the llvm::Function.
-  const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeGlobalDeclaration(MD);
+  const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeMSMemberPointerThunk(MD);
   llvm::FunctionType *ThunkTy = CGM.getTypes().GetFunctionType(FnInfo);
   llvm::Function *ThunkFn =
       llvm::Function::Create(ThunkTy, llvm::Function::ExternalLinkage,
@@ -1464,18 +1467,28 @@ llvm::Function *MicrosoftCXXABI::EmitVir
 
   // Start codegen.
   CodeGenFunction CGF(CGM);
-  CGF.StartThunk(ThunkFn, MD, FnInfo);
+  CGF.CurGD = GlobalDecl(MD);
+  CGF.CurFuncIsThunk = true;
+
+  // Build FunctionArgs, but only include the implicit 'this' parameter
+  // declaration.
+  FunctionArgList FunctionArgs;
+  buildThisParam(CGF, FunctionArgs);
+
+  // Start defining the function.
+  CGF.StartFunction(GlobalDecl(), FnInfo.getReturnType(), ThunkFn, FnInfo,
+                    FunctionArgs, MD->getLocation(), SourceLocation());
+  EmitThisParam(CGF);
 
   // Load the vfptr and then callee from the vftable.  The callee should have
   // adjusted 'this' so that the vfptr is at offset zero.
-  llvm::Value *This = CGF.LoadCXXThis();
-  llvm::Value *VTable =
-      CGF.GetVTablePtr(This, ThunkTy->getPointerTo()->getPointerTo());
+  llvm::Value *VTable = CGF.GetVTablePtr(
+      getThisValue(CGF), ThunkTy->getPointerTo()->getPointerTo());
   llvm::Value *VFuncPtr =
       CGF.Builder.CreateConstInBoundsGEP1_64(VTable, ML.Index, "vfn");
   llvm::Value *Callee = CGF.Builder.CreateLoad(VFuncPtr);
 
-  CGF.EmitCallAndReturnForThunk(Callee, 0);
+  CGF.EmitMustTailThunk(MD, getThisValue(CGF), Callee);
 
   return ThunkFn;
 }
@@ -1935,8 +1948,8 @@ MicrosoftCXXABI::BuildMemberPointer(cons
   CodeGenTypes &Types = CGM.getTypes();
 
   llvm::Constant *FirstField;
+  const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
   if (!MD->isVirtual()) {
-    const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
     llvm::Type *Ty;
     // Check whether the function has a computable LLVM signature.
     if (Types.isFuncTypeConvertible(FPT)) {
@@ -1952,14 +1965,14 @@ MicrosoftCXXABI::BuildMemberPointer(cons
   } else {
     MicrosoftVTableContext::MethodVFTableLocation ML =
         CGM.getMicrosoftVTableContext().getMethodVFTableLocation(MD);
-    if (MD->isVariadic()) {
-      CGM.ErrorUnsupported(MD, "pointer to variadic virtual member function");
-      FirstField = llvm::Constant::getNullValue(CGM.VoidPtrTy);
-    } else if (!CGM.getTypes().isFuncTypeConvertible(
-                    MD->getType()->castAs<FunctionType>())) {
+    if (!CGM.getTypes().isFuncTypeConvertible(
+            MD->getType()->castAs<FunctionType>())) {
       CGM.ErrorUnsupported(MD, "pointer to virtual member function with "
                                "incomplete return or parameter type");
       FirstField = llvm::Constant::getNullValue(CGM.VoidPtrTy);
+    } else if (FPT->getCallConv() == CC_X86FastCall) {
+      CGM.ErrorUnsupported(MD, "pointer to fastcall virtual member function");
+      FirstField = llvm::Constant::getNullValue(CGM.VoidPtrTy);
     } else if (ML.VBase) {
       CGM.ErrorUnsupported(MD, "pointer to virtual member function overriding "
                                "member function in virtual base class");

Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-member-pointers.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-member-pointers.cpp?rev=216782&r1=216781&r2=216782&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-member-pointers.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-member-pointers.cpp Fri Aug 29 16:43:29 2014
@@ -595,15 +595,15 @@ void (C::*getmp())() {
   return &C::g;
 }
 // CHECK-LABEL: define i64 @"\01?getmp at Test4@@YAP8C at 1@AEXXZXZ"()
-// CHECK: store { i8*, i32 } { i8* bitcast (void (i8*)* @"\01??_9C at Test4@@$BA at AE" to i8*), i32 4 }, { i8*, i32 }* %{{.*}}
+// CHECK: store { i8*, i32 } { i8* bitcast (void (%"struct.Test4::C"*, ...)* @"\01??_9C at Test4@@$BA at AE" to i8*), i32 4 }, { i8*, i32 }* %{{.*}}
 //
 
-// CHECK-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C at Test4@@$BA at AE"(i8*)
+// CHECK-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C at Test4@@$BA at AE"(%"struct.Test4::C"* %this, ...)
 // CHECK-NOT:  getelementptr
-// CHECK:  load void (i8*)*** %{{.*}}
-// CHECK:  getelementptr inbounds void (i8*)** %{{.*}}, i64 0
+// CHECK:  load void (%"struct.Test4::C"*, ...)*** %{{.*}}
+// CHECK:  getelementptr inbounds void (%"struct.Test4::C"*, ...)** %{{.*}}, i64 0
 // CHECK-NOT:  getelementptr
-// CHECK:  call x86_thiscallcc void %
+// CHECK:  musttail call x86_thiscallcc void (%"struct.Test4::C"*, ...)* %
 
 }
 

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=216782&r1=216781&r2=216782&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-member-pointers.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-member-pointers.cpp Fri Aug 29 16:43:29 2014
@@ -49,111 +49,111 @@ 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.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: store i8* bitcast (void (%struct.C*, ...)* @"\01??_9C@@$BA at AE" to i8*), i8** %ptr
+// CHECK32: store i8* bitcast (void (%struct.C*, ...)* @"\01??_9C@@$B3AE" to i8*), i8** %ptr2
+// CHECK32: store i8* bitcast (void (%struct.C*, ...)* @"\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.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: store i8* bitcast (void (%struct.C*, ...)* @"\01??_9C@@$BA at AA" to i8*), i8** %ptr
+// CHECK64: store i8* bitcast (void (%struct.C*, ...)* @"\01??_9C@@$B7AA" to i8*), i8** %ptr2
+// CHECK64: store i8* bitcast (void (%struct.C*, ...)* @"\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: }
 }
 
 
 // Thunk for calling the 1st virtual function in C with no parameters.
-// CHECK32-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@@$BA at AE"(%struct.C* %this)
-// CHECK32-NOT:         unnamed_addr
-// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*)** %{{.*}}, i64 0
-// CHECK32: [[CALLEE:%.*]] = load void (%struct.C*)** [[VPTR]]
-// CHECK32: call x86_thiscallcc void [[CALLEE]](%struct.C* %{{.*}})
-// CHECK32: ret void
+// CHECK32-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@@$BA at AE"(%struct.C* %this, ...)
+// CHECK32:             unnamed_addr
+// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)** %{{.*}}, i64 0
+// CHECK32: [[CALLEE:%.*]] = load void (%struct.C*, ...)** [[VPTR]]
+// CHECK32: musttail call x86_thiscallcc void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)
+// CHECK32-NEXT: ret void
 // CHECK32: }
 //
-// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BA at AA"(%struct.C* %this)
-// CHECK64-NOT:         unnamed_addr
-// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*)** %{{.*}}, i64 0
-// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*)** [[VPTR]]
-// CHECK64: call void [[CALLEE]](%struct.C* %{{.*}})
-// CHECK64: ret void
+// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BA at AA"(%struct.C* %this, ...)
+// CHECK64:             unnamed_addr
+// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)** %{{.*}}, i64 0
+// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*, ...)** [[VPTR]]
+// CHECK64: musttail call void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)
+// CHECK64-NEXT: ret void
 // CHECK64: }
 
 // Thunk for calling the 2nd virtual function in C, taking int and double as parameters, returning int.
-// CHECK32-LABEL: define linkonce_odr x86_thiscallcc i32 @"\01??_9C@@$B3AE"(%struct.C* %this, i32, double)
-// CHECK32: [[VPTR:%.*]] = getelementptr inbounds i32 (%struct.C*, i32, double)** %{{.*}}, i64 1
-// CHECK32: [[CALLEE:%.*]] = load i32 (%struct.C*, i32, double)** [[VPTR]]
-// CHECK32: [[CALL:%.*]] = call x86_thiscallcc i32 [[CALLEE]](%struct.C* %{{.*}}, i32 %{{.*}}, double %{{.*}})
-// CHECK32: ret i32 [[CALL]]
+// CHECK32-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@@$B3AE"(%struct.C* %this, ...)
+// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)** %{{.*}}, i64 1
+// CHECK32: [[CALLEE:%.*]] = load void (%struct.C*, ...)** [[VPTR]]
+// CHECK32: musttail call x86_thiscallcc void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)
+// CHECK32-NEXT: ret void
 // CHECK32: }
 //
-// CHECK64-LABEL: define linkonce_odr i32 @"\01??_9C@@$B7AA"(%struct.C* %this, i32, double)
-// CHECK64: [[VPTR:%.*]] = getelementptr inbounds i32 (%struct.C*, i32, double)** %{{.*}}, i64 1
-// CHECK64: [[CALLEE:%.*]] = load i32 (%struct.C*, i32, double)** [[VPTR]]
-// CHECK64: [[CALL:%.*]] = call i32 [[CALLEE]](%struct.C* %{{.*}}, i32 %{{.*}}, double %{{.*}})
-// CHECK64: ret i32 [[CALL]]
+// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$B7AA"(%struct.C* %this, ...)
+// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)** %{{.*}}, i64 1
+// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*, ...)** [[VPTR]]
+// CHECK64: musttail call void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)
+// CHECK64-NEXT: ret void
 // 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.C* %this, %struct.S* noalias sret %agg.result, i32)
-// 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-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@@$B7AE"(%struct.C* %this, ...)
+// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)** %{{.*}}, i64 2
+// CHECK32: [[CALLEE:%.*]] = load void (%struct.C*, ...)** [[VPTR]]
+// CHECK32: musttail call x86_thiscallcc void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)
+// CHECK32-NEXT: ret void
 // CHECK32: }
 //
-// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BBA at AA"(%struct.C* %this, %struct.S* noalias sret %agg.result, i32)
-// 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-LABEL: define linkonce_odr void @"\01??_9C@@$BBA at AA"(%struct.C* %this, ...)
+// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)** %{{.*}}, i64 2
+// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*, ...)** [[VPTR]]
+// CHECK64: musttail call void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)
+// CHECK64-NEXT: ret void
 // CHECK64: }
 
 // Thunk for calling the virtual function in internal class D.
-// CHECK32-LABEL: define internal x86_thiscallcc void @"\01??_9D@?A@@$BA at AE"(%"struct.(anonymous namespace)::D"* %this)
-// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%"struct.(anonymous namespace)::D"*)** %{{.*}}, i64 0
-// CHECK32: [[CALLEE:%.*]] = load void (%"struct.(anonymous namespace)::D"*)** [[VPTR]]
-// CHECK32: call x86_thiscallcc void [[CALLEE]](%"struct.(anonymous namespace)::D"* %{{.*}})
-// CHECK32: ret void
+// CHECK32-LABEL: define internal x86_thiscallcc void @"\01??_9D@?A@@$BA at AE"(%"struct.(anonymous namespace)::D"* %this, ...)
+// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%"struct.(anonymous namespace)::D"*, ...)** %{{.*}}, i64 0
+// CHECK32: [[CALLEE:%.*]] = load void (%"struct.(anonymous namespace)::D"*, ...)** [[VPTR]]
+// CHECK32: musttail call x86_thiscallcc void (%"struct.(anonymous namespace)::D"*, ...)* [[CALLEE]](%"struct.(anonymous namespace)::D"* %{{.*}}, ...)
+// CHECK32-NEXT: ret void
 // CHECK32: }
 //
-// CHECK64-LABEL: define internal void @"\01??_9D@?A@@$BA at AA"(%"struct.(anonymous namespace)::D"* %this)
-// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%"struct.(anonymous namespace)::D"*)** %{{.*}}, i64 0
-// CHECK64: [[CALLEE:%.*]] = load void (%"struct.(anonymous namespace)::D"*)** [[VPTR]]
-// CHECK64: call void [[CALLEE]](%"struct.(anonymous namespace)::D"* %{{.*}})
-// CHECK64: ret void
+// CHECK64-LABEL: define internal void @"\01??_9D@?A@@$BA at AA"(%"struct.(anonymous namespace)::D"* %this, ...)
+// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%"struct.(anonymous namespace)::D"*, ...)** %{{.*}}, i64 0
+// CHECK64: [[CALLEE:%.*]] = load void (%"struct.(anonymous namespace)::D"*, ...)** [[VPTR]]
+// CHECK64: musttail call void (%"struct.(anonymous namespace)::D"*, ...)* [[CALLEE]](%"struct.(anonymous namespace)::D"* %{{.*}}, ...)
+// CHECK64-NEXT: ret void
 // CHECK64: }
 
 // Thunk for calling the fourth virtual function in C, taking a struct parameter
 // and returning a struct.
-// CHECK32-LABEL: define linkonce_odr x86_thiscallcc %struct.S* @"\01??_9C@@$BM at AE"(%struct.C* %this, <{ %struct.S*, %struct.U }>* inalloca)
-// CHECK32: [[VPTR:%.*]] = getelementptr inbounds %struct.S* (%struct.C*, <{ %struct.S*, %struct.U }>*)** %{{.*}}, i64 3
-// CHECK32: [[CALLEE:%.*]] = load %struct.S* (%struct.C*, <{ %struct.S*, %struct.U }>*)** [[VPTR]]
-// CHECK32: [[CALL:%.*]] = musttail call x86_thiscallcc %struct.S* [[CALLEE]](%struct.C* %{{.*}}, <{ %struct.S*, %struct.U }>* inalloca %{{.*}})
-// CHECK32-NEXT: ret %struct.S* [[CALL]]
+// CHECK32-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@@$BM at AE"(%struct.C* %this, ...)
+// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)** %{{.*}}, i64 3
+// CHECK32: [[CALLEE:%.*]] = load void (%struct.C*, ...)** [[VPTR]]
+// CHECK32: musttail call x86_thiscallcc void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)
+// CHECK32-NEXT: ret void
 // CHECK32: }
 //
-// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BBI at AA"(%struct.C* %this, %struct.S* noalias sret %agg.result, %struct.U*)
-// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, %struct.S*, %struct.U*)** %{{.*}}, i64 3
-// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*, %struct.S*, %struct.U*)** [[VPTR]]
-// CHECK64: call void [[CALLEE]](%struct.C* %{{.*}}, %struct.S* sret %agg.result, %struct.U* %{{.*}})
+// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BBI at AA"(%struct.C* %this, ...)
+// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)** %{{.*}}, i64 3
+// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*, ...)** [[VPTR]]
+// CHECK64: musttail call void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)
 // CHECK64: ret void
 // CHECK64: }
 
 // Thunk for calling the fifth virtual function in C, taking a struct parameter
 // and returning a struct.
-// CHECK32-LABEL: define linkonce_odr x86_fastcallcc void @"\01??_9C@@$BBA at AE"(%struct.C* inreg %this, %struct.S* inreg noalias sret %agg.result, <{ %struct.U }>* inalloca)
-// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, %struct.S*, <{ %struct.U }>*)** %{{.*}}, i64 4
-// CHECK32: [[CALLEE:%.*]] = load void (%struct.C*, %struct.S*, <{ %struct.U }>*)** [[VPTR]]
-// CHECK32: musttail call x86_fastcallcc void [[CALLEE]](%struct.C* inreg %{{.*}}, %struct.S* inreg sret %{{.*}}, <{ %struct.U }>* inalloca %{{.*}})
+// CHECK32-LABEL: define linkonce_odr x86_fastcallcc void @"\01??_9C@@$BBA at AE"(%struct.C* inreg %this, ...)
+// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)** %{{.*}}, i64 4
+// CHECK32: [[CALLEE:%.*]] = load void (%struct.C*, ...)** [[VPTR]]
+// CHECK32: musttail call x86_fastcallcc void (%struct.C*, ...)* [[CALLEE]](%struct.C* inreg %{{.*}}, ...)
 // CHECK32-NEXT: ret void
 // CHECK32: }
 //
-// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BCA at AA"(%struct.C* %this, %struct.S* noalias sret %agg.result, %struct.U*)
-// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, %struct.S*, %struct.U*)** %{{.*}}, i64 4
-// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*, %struct.S*, %struct.U*)** [[VPTR]]
-// CHECK64: call void [[CALLEE]](%struct.C* %{{.*}}, %struct.S* sret %agg.result, %struct.U* %{{.*}})
+// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BCA at AA"(%struct.C* %this, ...)
+// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)** %{{.*}}, i64 4
+// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*, ...)** [[VPTR]]
+// CHECK64: musttail call void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)
 // CHECK64: ret void
 // CHECK64: }

Added: cfe/trunk/test/CodeGenCXX/microsoft-abi-vmemptr-conflicts.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-vmemptr-conflicts.cpp?rev=216782&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-vmemptr-conflicts.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-vmemptr-conflicts.cpp Fri Aug 29 16:43:29 2014
@@ -0,0 +1,101 @@
+// RUN: %clang_cc1 -fno-rtti -emit-llvm -triple=i386-pc-win32 %s -o - | FileCheck %s
+
+// In each test case, we have two member pointers whose thunks have the same
+// vtable offset and same mangling, but their prototypes conflict.  The
+// arguments and return type may differ.  Therefore, we have to bitcast the
+// function prototype.  Unfortunately, if the return types differ, LLVM's
+// optimizers can get upset.
+
+namespace num_params {
+struct A { virtual void a(int); };
+struct B { virtual void b(int, int); };
+struct C : A, B {
+  virtual void a(int);
+  virtual void b(int, int);
+};
+void f(C *c) {
+  (c->*(&C::a))(0);
+  (c->*(&C::b))(0, 0);
+}
+}
+
+// CHECK-LABEL: define void @"\01?f at num_params@@YAXPAUC at 1@@Z"(%"struct.num_params::C"* %c)
+// CHECK: call x86_thiscallcc void bitcast (void (%"struct.num_params::C"*, ...)* @"\01??_9C at num_params@@$BA at AE" to void (%"struct.num_params::C"*, i32)*)(%"struct.num_params::C"* %{{.*}}, i32 0)
+// CHECK: call x86_thiscallcc void bitcast (void (%"struct.num_params::C"*, ...)* @"\01??_9C at num_params@@$BA at AE" to void (%"struct.num_params::C"*, i32, i32)*)(%"struct.num_params::C"* %{{.*}}, i32 0, i32 0)
+
+// CHECK-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C at num_params@@$BA at AE"(%"struct.num_params::C"* %this, ...)
+// CHECK: musttail call x86_thiscallcc void (%"struct.num_params::C"*, ...)* %{{.*}}(%"struct.num_params::C"* %{{.*}}, ...)
+// CHECK-NEXT: ret void
+
+namespace i64_return {
+struct A { virtual int a(); };
+struct B { virtual long long b(); };
+struct C : A, B {
+  virtual int a();
+  virtual long long b();
+};
+long long f(C *c) {
+  int x = (c->*(&C::a))();
+  long long y = (c->*(&C::b))();
+  return x + y;
+}
+}
+
+// CHECK-LABEL: define i64 @"\01?f at i64_return@@YA_JPAUC at 1@@Z"(%"struct.i64_return::C"* %c)
+// CHECK: call x86_thiscallcc i32 bitcast (void (%"struct.i64_return::C"*, ...)* @"\01??_9C at i64_return@@$BA at AE" to i32 (%"struct.i64_return::C"*)*)(%"struct.i64_return::C"* %{{.*}})
+// CHECK: call x86_thiscallcc i64 bitcast (void (%"struct.i64_return::C"*, ...)* @"\01??_9C at i64_return@@$BA at AE" to i64 (%"struct.i64_return::C"*)*)(%"struct.i64_return::C"* %{{.*}})
+
+// CHECK-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C at i64_return@@$BA at AE"(%"struct.i64_return::C"* %this, ...)
+// CHECK: musttail call x86_thiscallcc void (%"struct.i64_return::C"*, ...)* %{{.*}}(%"struct.i64_return::C"* %{{.*}}, ...)
+// CHECK-NEXT: ret void
+
+namespace sret {
+struct Big { int big[32]; };
+struct A { virtual int a(); };
+struct B { virtual Big b(); };
+struct C : A, B {
+  virtual int a();
+  virtual Big b();
+};
+void f(C *c) {
+  (c->*(&C::a))();
+  Big b((c->*(&C::b))());
+}
+}
+
+// CHECK-LABEL: define void @"\01?f at sret@@YAXPAUC at 1@@Z"(%"struct.sret::C"* %c)
+// CHECK: call x86_thiscallcc i32 bitcast (void (%"struct.sret::C"*, ...)* @"\01??_9C at sret@@$BA at AE" to i32 (%"struct.sret::C"*)*)(%"struct.sret::C"* %{{.*}})
+// CHECK: call x86_thiscallcc void bitcast (void (%"struct.sret::C"*, ...)* @"\01??_9C at sret@@$BA at AE" to void (%"struct.sret::C"*, %"struct.sret::Big"*)*)(%"struct.sret::C"* %{{.*}}, %"struct.sret::Big"* sret %{{.*}})
+
+// CHECK-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C at sret@@$BA at AE"(%"struct.sret::C"* %this, ...)
+// CHECK: musttail call x86_thiscallcc void (%"struct.sret::C"*, ...)* %{{.*}}(%"struct.sret::C"* %{{.*}}, ...)
+// CHECK-NEXT: ret void
+
+namespace cdecl_inalloca {
+// Fairly evil, since now we end up doing an inalloca-style call through a
+// thunk that doesn't use inalloca.  Hopefully the stacks line up?
+struct Big {
+  Big();
+  ~Big();
+  int big[32];
+};
+struct A { virtual void __cdecl a(); };
+struct B { virtual void __cdecl b(Big); };
+struct C : A, B {
+  virtual void __cdecl a();
+  virtual void __cdecl b(Big);
+};
+void f(C *c) {
+  Big b;
+  (c->*(&C::a))();
+  ((c->*(&C::b))(b));
+}
+}
+
+// CHECK-LABEL: define void @"\01?f at cdecl_inalloca@@YAXPAUC at 1@@Z"(%"struct.cdecl_inalloca::C"* %c)
+// CHECK: call void bitcast (void (%"struct.cdecl_inalloca::C"*, ...)* @"\01??_9C at cdecl_inalloca@@$BA at AE" to void (%"struct.cdecl_inalloca::C"*)*)(%"struct.cdecl_inalloca::C"* %{{.*}})
+// CHECK: call void bitcast (void (%"struct.cdecl_inalloca::C"*, ...)* @"\01??_9C at cdecl_inalloca@@$BA at AE" to void (<{ %"struct.cdecl_inalloca::C"*, %"struct.cdecl_inalloca::Big" }>*)*)(<{ %"struct.cdecl_inalloca::C"*, %"struct.cdecl_inalloca::Big" }>* inalloca %{{.*}})
+
+// CHECK-LABEL: define linkonce_odr void @"\01??_9C at cdecl_inalloca@@$BA at AE"(%"struct.cdecl_inalloca::C"* %this, ...)
+// CHECK: musttail call void (%"struct.cdecl_inalloca::C"*, ...)* %{{.*}}(%"struct.cdecl_inalloca::C"* %{{.*}}, ...)
+// CHECK-NEXT: ret void

Added: cfe/trunk/test/CodeGenCXX/microsoft-abi-vmemptr-fastcall.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-vmemptr-fastcall.cpp?rev=216782&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-vmemptr-fastcall.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-vmemptr-fastcall.cpp Fri Aug 29 16:43:29 2014
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -triple i686-pc-windows-msvc %s -emit-llvm-only -verify
+
+// We reject this because LLVM doesn't forward the second regparm through the
+// thunk.
+
+struct A {
+  virtual void __fastcall f(int a, int b);
+};
+void (__fastcall A::*doit())(int, int) {
+  return &A::f; // expected-error {{cannot compile this pointer to fastcall virtual member function yet}}
+}





More information about the cfe-commits mailing list