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@Test4@@YAP8C@1@AEXXZXZ"()
-// CHECK: store { i8*, i32 } { i8* bitcast (void (i8*)* 
@"\01??_9C@Test4@@$BA@AE" to i8*), i32 4 }, { i8*, i32 }* %{{.*}}
+// CHECK: store { i8*, i32 } { i8* bitcast (void (%"struct.Test4::C"*, ...)* 
@"\01??_9C@Test4@@$BA@AE" to i8*), i32 4 }, { i8*, i32 }* %{{.*}}
 //
 
-// CHECK-LABEL: define linkonce_odr x86_thiscallcc void 
@"\01??_9C@Test4@@$BA@AE"(i8*)
+// CHECK-LABEL: define linkonce_odr x86_thiscallcc void 
@"\01??_9C@Test4@@$BA@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@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@AE" to i8*), i8** %ptr4
+// CHECK32: store i8* bitcast (void (%struct.C*, ...)* @"\01??_9C@@$BA@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@AE" to i8*), i8** %ptr4
 // CHECK32: }
 //
 // CHECK64-LABEL: define void @"\01?f@@YAXXZ"()
-// CHECK64: store i8* bitcast (void (%struct.C*)* @"\01??_9C@@$BA@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@AA" to i8*), i8** %ptr3
-// CHECK64: store i8* bitcast (void (%"struct.(anonymous namespace)::D"*)* 
@"\01??_9D@?A@@$BA@AA" to i8*), i8** %ptr
+// CHECK64: store i8* bitcast (void (%struct.C*, ...)* @"\01??_9C@@$BA@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@AA" to 
i8*), i8** %ptr3
+// CHECK64: store i8* bitcast (void (%"struct.(anonymous namespace)::D"*, 
...)* @"\01??_9D@?A@@$BA@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@num_params@@YAXPAUC@1@@Z"(%"struct.num_params::C"* %c)
+// CHECK: call x86_thiscallcc void bitcast (void (%"struct.num_params::C"*, 
...)* @"\01??_9C@num_params@@$BA@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@num_params@@$BA@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@num_params@@$BA@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@i64_return@@YA_JPAUC@1@@Z"(%"struct.i64_return::C"* %c)
+// CHECK: call x86_thiscallcc i32 bitcast (void (%"struct.i64_return::C"*, 
...)* @"\01??_9C@i64_return@@$BA@AE" to i32 
(%"struct.i64_return::C"*)*)(%"struct.i64_return::C"* %{{.*}})
+// CHECK: call x86_thiscallcc i64 bitcast (void (%"struct.i64_return::C"*, 
...)* @"\01??_9C@i64_return@@$BA@AE" to i64 
(%"struct.i64_return::C"*)*)(%"struct.i64_return::C"* %{{.*}})
+
+// CHECK-LABEL: define linkonce_odr x86_thiscallcc void 
@"\01??_9C@i64_return@@$BA@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@sret@@YAXPAUC@1@@Z"(%"struct.sret::C"* %c)
+// CHECK: call x86_thiscallcc i32 bitcast (void (%"struct.sret::C"*, ...)* 
@"\01??_9C@sret@@$BA@AE" to i32 (%"struct.sret::C"*)*)(%"struct.sret::C"* 
%{{.*}})
+// CHECK: call x86_thiscallcc void bitcast (void (%"struct.sret::C"*, ...)* 
@"\01??_9C@sret@@$BA@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@sret@@$BA@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@cdecl_inalloca@@YAXPAUC@1@@Z"(%"struct.cdecl_inalloca::C"* %c)
+// CHECK: call void bitcast (void (%"struct.cdecl_inalloca::C"*, ...)* 
@"\01??_9C@cdecl_inalloca@@$BA@AE" to void 
(%"struct.cdecl_inalloca::C"*)*)(%"struct.cdecl_inalloca::C"* %{{.*}})
+// CHECK: call void bitcast (void (%"struct.cdecl_inalloca::C"*, ...)* 
@"\01??_9C@cdecl_inalloca@@$BA@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@cdecl_inalloca@@$BA@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}}
+}


_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to