<div dir="ltr">I think this revision has introduced a bug, see PR20944 for details.<br></div><br><div class="gmail_quote">On Sat Aug 30 2014 at 1:58:28 AM Reid Kleckner <<a href="mailto:reid@kleckner.net">reid@kleckner.net</a>> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: rnk<br>
Date: Fri Aug 29 16:43:29 2014<br>
New Revision: 216782<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=216782&view=rev" target="_blank">http://llvm.org/viewvc/llvm-<u></u>project?rev=216782&view=rev</a><br>
Log:<br>
Make all virtual member pointers use variadic musttail calls<br>
<br>
This avoids encoding information about the function prototype into the<br>
thunk at the cost of some function prototype bitcast gymnastics.<br>
<br>
Fixes PR20653.<br>
<br>
Added:<br>
cfe/trunk/test/CodeGenCXX/<u></u>microsoft-abi-vmemptr-<u></u>conflicts.cpp<br>
cfe/trunk/test/CodeGenCXX/<u></u>microsoft-abi-vmemptr-<u></u>fastcall.cpp<br>
Modified:<br>
cfe/trunk/lib/CodeGen/CGCall.<u></u>cpp<br>
cfe/trunk/lib/CodeGen/<u></u>CodeGenTypes.h<br>
cfe/trunk/lib/CodeGen/<u></u>MicrosoftCXXABI.cpp<br>
cfe/trunk/test/CodeGenCXX/<u></u>microsoft-abi-member-pointers.<u></u>cpp<br>
cfe/trunk/test/CodeGenCXX/<u></u>microsoft-abi-virtual-member-<u></u>pointers.cpp<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CGCall.<u></u>cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCall.cpp?rev=216782&r1=216781&r2=216782&view=diff" target="_blank">http://llvm.org/viewvc/llvm-<u></u>project/cfe/trunk/lib/CodeGen/<u></u>CGCall.cpp?rev=216782&r1=<u></u>216781&r2=216782&view=diff</a><br>
==============================<u></u>==============================<u></u>==================<br>
--- cfe/trunk/lib/CodeGen/CGCall.<u></u>cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/CGCall.<u></u>cpp Fri Aug 29 16:43:29 2014<br>
@@ -332,6 +332,20 @@ CodeGenTypes::<u></u>arrangeGlobalDeclaration(G<br>
return arrangeFunctionDeclaration(FD)<u></u>;<br>
}<br>
<br>
+/// Arrange a thunk that takes 'this' as the first parameter followed by<br>
+/// varargs. Return a void pointer, regardless of the actual return type.<br>
+/// The body of the thunk will end in a musttail call to a function of the<br>
+/// correct type, and the caller will bitcast the function to the correct<br>
+/// prototype.<br>
+const CGFunctionInfo &<br>
+CodeGenTypes::<u></u>arrangeMSMemberPointerThunk(<u></u>const CXXMethodDecl *MD) {<br>
+ assert(MD->isVirtual() && "only virtual memptrs have thunks");<br>
+ CanQual<FunctionProtoType> FTP = GetFormalType(MD);<br>
+ CanQualType ArgTys[] = { GetThisType(Context, MD->getParent()) };<br>
+ return arrangeLLVMFunctionInfo(<u></u>Context.VoidTy, false, ArgTys,<br>
+ FTP->getExtInfo(), RequiredArgs(1));<br>
+}<br>
+<br>
/// Arrange a call as unto a free function, except possibly with an<br>
/// additional number of formal parameters considered required.<br>
static const CGFunctionInfo &<br>
<br>
Modified: cfe/trunk/lib/CodeGen/<u></u>CodeGenTypes.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenTypes.h?rev=216782&r1=216781&r2=216782&view=diff" target="_blank">http://llvm.org/viewvc/llvm-<u></u>project/cfe/trunk/lib/CodeGen/<u></u>CodeGenTypes.h?rev=216782&r1=<u></u>216781&r2=216782&view=diff</a><br>
==============================<u></u>==============================<u></u>==================<br>
--- cfe/trunk/lib/CodeGen/<u></u>CodeGenTypes.h (original)<br>
+++ cfe/trunk/lib/CodeGen/<u></u>CodeGenTypes.h Fri Aug 29 16:43:29 2014<br>
@@ -207,6 +207,7 @@ public:<br>
const CGFunctionInfo &arrangeCXXMethodCall(const CallArgList &args,<br>
const FunctionProtoType *type,<br>
RequiredArgs required);<br>
+ const CGFunctionInfo &arrangeMSMemberPointerThunk(<u></u>const CXXMethodDecl *MD);<br>
<br>
const CGFunctionInfo &arrangeFreeFunctionType(<u></u>CanQual<FunctionProtoType> Ty);<br>
const CGFunctionInfo &arrangeFreeFunctionType(<u></u>CanQual<FunctionNoProtoType> Ty);<br>
<br>
Modified: cfe/trunk/lib/CodeGen/<u></u>MicrosoftCXXABI.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=216782&r1=216781&r2=216782&view=diff" target="_blank">http://llvm.org/viewvc/llvm-<u></u>project/cfe/trunk/lib/CodeGen/<u></u>MicrosoftCXXABI.cpp?rev=<u></u>216782&r1=216781&r2=216782&<u></u>view=diff</a><br>
==============================<u></u>==============================<u></u>==================<br>
--- cfe/trunk/lib/CodeGen/<u></u>MicrosoftCXXABI.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/<u></u>MicrosoftCXXABI.cpp Fri Aug 29 16:43:29 2014<br>
@@ -1434,6 +1434,9 @@ MicrosoftCXXABI::<u></u>enumerateVBTables(const<br>
llvm::Function *MicrosoftCXXABI::<u></u>EmitVirtualMemPtrThunk(<br>
const CXXMethodDecl *MD,<br>
const MicrosoftVTableContext::<u></u>MethodVFTableLocation &ML) {<br>
+ assert(!isa<<u></u>CXXConstructorDecl>(MD) && !isa<CXXDestructorDecl>(MD) &&<br>
+ "can't form pointers to ctors or virtual dtors");<br>
+<br>
// Calculate the mangled name.<br>
SmallString<256> ThunkName;<br>
llvm::raw_svector_ostream Out(ThunkName);<br>
@@ -1445,7 +1448,7 @@ llvm::Function *MicrosoftCXXABI::EmitVir<br>
return cast<llvm::Function>(GV);<br>
<br>
// Create the llvm::Function.<br>
- const CGFunctionInfo &FnInfo = CGM.getTypes().<u></u>arrangeGlobalDeclaration(MD);<br>
+ const CGFunctionInfo &FnInfo = CGM.getTypes().<u></u>arrangeMSMemberPointerThunk(<u></u>MD);<br>
llvm::FunctionType *ThunkTy = CGM.getTypes().<u></u>GetFunctionType(FnInfo);<br>
llvm::Function *ThunkFn =<br>
llvm::Function::Create(<u></u>ThunkTy, llvm::Function::<u></u>ExternalLinkage,<br>
@@ -1464,18 +1467,28 @@ llvm::Function *MicrosoftCXXABI::EmitVir<br>
<br>
// Start codegen.<br>
CodeGenFunction CGF(CGM);<br>
- CGF.StartThunk(ThunkFn, MD, FnInfo);<br>
+ CGF.CurGD = GlobalDecl(MD);<br>
+ CGF.CurFuncIsThunk = true;<br>
+<br>
+ // Build FunctionArgs, but only include the implicit 'this' parameter<br>
+ // declaration.<br>
+ FunctionArgList FunctionArgs;<br>
+ buildThisParam(CGF, FunctionArgs);<br>
+<br>
+ // Start defining the function.<br>
+ CGF.StartFunction(GlobalDecl()<u></u>, FnInfo.getReturnType(), ThunkFn, FnInfo,<br>
+ FunctionArgs, MD->getLocation(), SourceLocation());<br>
+ EmitThisParam(CGF);<br>
<br>
// Load the vfptr and then callee from the vftable. The callee should have<br>
// adjusted 'this' so that the vfptr is at offset zero.<br>
- llvm::Value *This = CGF.LoadCXXThis();<br>
- llvm::Value *VTable =<br>
- CGF.GetVTablePtr(This, ThunkTy->getPointerTo()-><u></u>getPointerTo());<br>
+ llvm::Value *VTable = CGF.GetVTablePtr(<br>
+ getThisValue(CGF), ThunkTy->getPointerTo()-><u></u>getPointerTo());<br>
llvm::Value *VFuncPtr =<br>
CGF.Builder.<u></u>CreateConstInBoundsGEP1_64(<u></u>VTable, ML.Index, "vfn");<br>
llvm::Value *Callee = CGF.Builder.CreateLoad(<u></u>VFuncPtr);<br>
<br>
- CGF.EmitCallAndReturnForThunk(<u></u>Callee, 0);<br>
+ CGF.EmitMustTailThunk(MD, getThisValue(CGF), Callee);<br>
<br>
return ThunkFn;<br>
}<br>
@@ -1935,8 +1948,8 @@ MicrosoftCXXABI::<u></u>BuildMemberPointer(cons<br>
CodeGenTypes &Types = CGM.getTypes();<br>
<br>
llvm::Constant *FirstField;<br>
+ const FunctionProtoType *FPT = MD->getType()->castAs<<u></u>FunctionProtoType>();<br>
if (!MD->isVirtual()) {<br>
- const FunctionProtoType *FPT = MD->getType()->castAs<<u></u>FunctionProtoType>();<br>
llvm::Type *Ty;<br>
// Check whether the function has a computable LLVM signature.<br>
if (Types.isFuncTypeConvertible(<u></u>FPT)) {<br>
@@ -1952,14 +1965,14 @@ MicrosoftCXXABI::<u></u>BuildMemberPointer(cons<br>
} else {<br>
MicrosoftVTableContext::<u></u>MethodVFTableLocation ML =<br>
CGM.getMicrosoftVTableContext(<u></u>).getMethodVFTableLocation(MD)<u></u>;<br>
- if (MD->isVariadic()) {<br>
- CGM.ErrorUnsupported(MD, "pointer to variadic virtual member function");<br>
- FirstField = llvm::Constant::getNullValue(<u></u>CGM.VoidPtrTy);<br>
- } else if (!CGM.getTypes().<u></u>isFuncTypeConvertible(<br>
- MD->getType()->castAs<<u></u>FunctionType>())) {<br>
+ if (!CGM.getTypes().<u></u>isFuncTypeConvertible(<br>
+ MD->getType()->castAs<<u></u>FunctionType>())) {<br>
CGM.ErrorUnsupported(MD, "pointer to virtual member function with "<br>
"incomplete return or parameter type");<br>
FirstField = llvm::Constant::getNullValue(<u></u>CGM.VoidPtrTy);<br>
+ } else if (FPT->getCallConv() == CC_X86FastCall) {<br>
+ CGM.ErrorUnsupported(MD, "pointer to fastcall virtual member function");<br>
+ FirstField = llvm::Constant::getNullValue(<u></u>CGM.VoidPtrTy);<br>
} else if (ML.VBase) {<br>
CGM.ErrorUnsupported(MD, "pointer to virtual member function overriding "<br>
"member function in virtual base class");<br>
<br>
Modified: cfe/trunk/test/CodeGenCXX/<u></u>microsoft-abi-member-pointers.<u></u>cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-member-pointers.cpp?rev=216782&r1=216781&r2=216782&view=diff" target="_blank">http://llvm.org/viewvc/llvm-<u></u>project/cfe/trunk/test/<u></u>CodeGenCXX/microsoft-abi-<u></u>member-pointers.cpp?rev=<u></u>216782&r1=216781&r2=216782&<u></u>view=diff</a><br>
==============================<u></u>==============================<u></u>==================<br>
--- cfe/trunk/test/CodeGenCXX/<u></u>microsoft-abi-member-pointers.<u></u>cpp (original)<br>
+++ cfe/trunk/test/CodeGenCXX/<u></u>microsoft-abi-member-pointers.<u></u>cpp Fri Aug 29 16:43:29 2014<br>
@@ -595,15 +595,15 @@ void (C::*getmp())() {<br>
return &C::g;<br>
}<br>
// CHECK-LABEL: define i64 @"\01?getmp@Test4@@YAP8C@1@<u></u>AEXXZXZ"()<br>
-// CHECK: store { i8*, i32 } { i8* bitcast (void (i8*)* @"\01??_9C@Test4@@$BA@AE" to i8*), i32 4 }, { i8*, i32 }* %{{.*}}<br>
+// CHECK: store { i8*, i32 } { i8* bitcast (void (%"struct.Test4::C"*, ...)* @"\01??_9C@Test4@@$BA@AE" to i8*), i32 4 }, { i8*, i32 }* %{{.*}}<br>
//<br>
<br>
-// CHECK-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@Test4@@$BA@AE"(i8*)<br>
+// CHECK-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@Test4@@$BA@AE"(%"<u></u>struct.Test4::C"* %this, ...)<br>
// CHECK-NOT: getelementptr<br>
-// CHECK: load void (i8*)*** %{{.*}}<br>
-// CHECK: getelementptr inbounds void (i8*)** %{{.*}}, i64 0<br>
+// CHECK: load void (%"struct.Test4::C"*, ...)*** %{{.*}}<br>
+// CHECK: getelementptr inbounds void (%"struct.Test4::C"*, ...)** %{{.*}}, i64 0<br>
// CHECK-NOT: getelementptr<br>
-// CHECK: call x86_thiscallcc void %<br>
+// CHECK: musttail call x86_thiscallcc void (%"struct.Test4::C"*, ...)* %<br>
<br>
}<br>
<br>
<br>
Modified: cfe/trunk/test/CodeGenCXX/<u></u>microsoft-abi-virtual-member-<u></u>pointers.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-member-pointers.cpp?rev=216782&r1=216781&r2=216782&view=diff" target="_blank">http://llvm.org/viewvc/llvm-<u></u>project/cfe/trunk/test/<u></u>CodeGenCXX/microsoft-abi-<u></u>virtual-member-pointers.cpp?<u></u>rev=216782&r1=216781&r2=<u></u>216782&view=diff</a><br>
==============================<u></u>==============================<u></u>==================<br>
--- cfe/trunk/test/CodeGenCXX/<u></u>microsoft-abi-virtual-member-<u></u>pointers.cpp (original)<br>
+++ cfe/trunk/test/CodeGenCXX/<u></u>microsoft-abi-virtual-member-<u></u>pointers.cpp Fri Aug 29 16:43:29 2014<br>
@@ -49,111 +49,111 @@ void f() {<br>
<br>
<br>
// CHECK32-LABEL: define void @"\01?f@@YAXXZ"()<br>
-// CHECK32: store i8* bitcast (void (%struct.C*)* @"\01??_9C@@$BA@AE" to i8*), i8** %ptr<br>
-// CHECK32: store i8* bitcast (i32 (%struct.C*, i32, double)* @"\01??_9C@@$B3AE" to i8*), i8** %ptr2<br>
-// CHECK32: store i8* bitcast (void (%struct.C*, %struct.S*, i32)* @"\01??_9C@@$B7AE" to i8*), i8** %ptr3<br>
-// CHECK32: store i8* bitcast (void (%"struct.(anonymous namespace)::D"*)* @"\01??_9D@?A@@$BA@AE" to i8*), i8** %ptr4<br>
+// CHECK32: store i8* bitcast (void (%struct.C*, ...)* @"\01??_9C@@$BA@AE" to i8*), i8** %ptr<br>
+// CHECK32: store i8* bitcast (void (%struct.C*, ...)* @"\01??_9C@@$B3AE" to i8*), i8** %ptr2<br>
+// CHECK32: store i8* bitcast (void (%struct.C*, ...)* @"\01??_9C@@$B7AE" to i8*), i8** %ptr3<br>
+// CHECK32: store i8* bitcast (void (%"struct.(anonymous namespace)::D"*, ...)* @"\01??_9D@?A@@$BA@AE" to i8*), i8** %ptr4<br>
// CHECK32: }<br>
//<br>
// CHECK64-LABEL: define void @"\01?f@@YAXXZ"()<br>
-// CHECK64: store i8* bitcast (void (%struct.C*)* @"\01??_9C@@$BA@AA" to i8*), i8** %ptr<br>
-// CHECK64: store i8* bitcast (i32 (%struct.C*, i32, double)* @"\01??_9C@@$B7AA" to i8*), i8** %ptr2<br>
-// CHECK64: store i8* bitcast (void (%struct.C*, %struct.S*, i32)* @"\01??_9C@@$BBA@AA" to i8*), i8** %ptr3<br>
-// CHECK64: store i8* bitcast (void (%"struct.(anonymous namespace)::D"*)* @"\01??_9D@?A@@$BA@AA" to i8*), i8** %ptr<br>
+// CHECK64: store i8* bitcast (void (%struct.C*, ...)* @"\01??_9C@@$BA@AA" to i8*), i8** %ptr<br>
+// CHECK64: store i8* bitcast (void (%struct.C*, ...)* @"\01??_9C@@$B7AA" to i8*), i8** %ptr2<br>
+// CHECK64: store i8* bitcast (void (%struct.C*, ...)* @"\01??_9C@@$BBA@AA" to i8*), i8** %ptr3<br>
+// CHECK64: store i8* bitcast (void (%"struct.(anonymous namespace)::D"*, ...)* @"\01??_9D@?A@@$BA@AA" to i8*), i8** %ptr<br>
// CHECK64: }<br>
}<br>
<br>
<br>
// Thunk for calling the 1st virtual function in C with no parameters.<br>
-// CHECK32-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@@$BA@AE"(%struct.C* %this)<br>
-// CHECK32-NOT: unnamed_addr<br>
-// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*)** %{{.*}}, i64 0<br>
-// CHECK32: [[CALLEE:%.*]] = load void (%struct.C*)** [[VPTR]]<br>
-// CHECK32: call x86_thiscallcc void [[CALLEE]](%struct.C* %{{.*}})<br>
-// CHECK32: ret void<br>
+// CHECK32-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@@$BA@AE"(%struct.C* %this, ...)<br>
+// CHECK32: unnamed_addr<br>
+// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)** %{{.*}}, i64 0<br>
+// CHECK32: [[CALLEE:%.*]] = load void (%struct.C*, ...)** [[VPTR]]<br>
+// CHECK32: musttail call x86_thiscallcc void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)<br>
+// CHECK32-NEXT: ret void<br>
// CHECK32: }<br>
//<br>
-// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BA@AA"(%struct.C* %this)<br>
-// CHECK64-NOT: unnamed_addr<br>
-// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*)** %{{.*}}, i64 0<br>
-// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*)** [[VPTR]]<br>
-// CHECK64: call void [[CALLEE]](%struct.C* %{{.*}})<br>
-// CHECK64: ret void<br>
+// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BA@AA"(%struct.C* %this, ...)<br>
+// CHECK64: unnamed_addr<br>
+// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)** %{{.*}}, i64 0<br>
+// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*, ...)** [[VPTR]]<br>
+// CHECK64: musttail call void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)<br>
+// CHECK64-NEXT: ret void<br>
// CHECK64: }<br>
<br>
// Thunk for calling the 2nd virtual function in C, taking int and double as parameters, returning int.<br>
-// CHECK32-LABEL: define linkonce_odr x86_thiscallcc i32 @"\01??_9C@@$B3AE"(%struct.C* %this, i32, double)<br>
-// CHECK32: [[VPTR:%.*]] = getelementptr inbounds i32 (%struct.C*, i32, double)** %{{.*}}, i64 1<br>
-// CHECK32: [[CALLEE:%.*]] = load i32 (%struct.C*, i32, double)** [[VPTR]]<br>
-// CHECK32: [[CALL:%.*]] = call x86_thiscallcc i32 [[CALLEE]](%struct.C* %{{.*}}, i32 %{{.*}}, double %{{.*}})<br>
-// CHECK32: ret i32 [[CALL]]<br>
+// CHECK32-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@@$B3AE"(%struct.C* %this, ...)<br>
+// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)** %{{.*}}, i64 1<br>
+// CHECK32: [[CALLEE:%.*]] = load void (%struct.C*, ...)** [[VPTR]]<br>
+// CHECK32: musttail call x86_thiscallcc void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)<br>
+// CHECK32-NEXT: ret void<br>
// CHECK32: }<br>
//<br>
-// CHECK64-LABEL: define linkonce_odr i32 @"\01??_9C@@$B7AA"(%struct.C* %this, i32, double)<br>
-// CHECK64: [[VPTR:%.*]] = getelementptr inbounds i32 (%struct.C*, i32, double)** %{{.*}}, i64 1<br>
-// CHECK64: [[CALLEE:%.*]] = load i32 (%struct.C*, i32, double)** [[VPTR]]<br>
-// CHECK64: [[CALL:%.*]] = call i32 [[CALLEE]](%struct.C* %{{.*}}, i32 %{{.*}}, double %{{.*}})<br>
-// CHECK64: ret i32 [[CALL]]<br>
+// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$B7AA"(%struct.C* %this, ...)<br>
+// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)** %{{.*}}, i64 1<br>
+// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*, ...)** [[VPTR]]<br>
+// CHECK64: musttail call void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)<br>
+// CHECK64-NEXT: ret void<br>
// CHECK64: }<br>
<br>
// Thunk for calling the 3rd virtual function in C, taking an int parameter, returning a struct.<br>
-// CHECK32-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@@$B7AE"(%struct.C* %this, %struct.S* noalias sret %agg.result, i32)<br>
-// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, %struct.S*, i32)** %{{.*}}, i64 2<br>
-// CHECK32: [[CALLEE:%.*]] = load void (%struct.C*, %struct.S*, i32)** [[VPTR]]<br>
-// CHECK32: call x86_thiscallcc void [[CALLEE]](%struct.C* %{{.*}}, %struct.S* sret %agg.result, i32 %{{.*}})<br>
-// CHECK32: ret void<br>
+// CHECK32-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@@$B7AE"(%struct.C* %this, ...)<br>
+// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)** %{{.*}}, i64 2<br>
+// CHECK32: [[CALLEE:%.*]] = load void (%struct.C*, ...)** [[VPTR]]<br>
+// CHECK32: musttail call x86_thiscallcc void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)<br>
+// CHECK32-NEXT: ret void<br>
// CHECK32: }<br>
//<br>
-// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BBA@AA"(%struct.<u></u>C* %this, %struct.S* noalias sret %agg.result, i32)<br>
-// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, %struct.S*, i32)** %{{.*}}, i64 2<br>
-// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*, %struct.S*, i32)** [[VPTR]]<br>
-// CHECK64: call void [[CALLEE]](%struct.C* %{{.*}}, %struct.S* sret %agg.result, i32 %{{.*}})<br>
-// CHECK64: ret void<br>
+// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BBA@AA"(%struct.<u></u>C* %this, ...)<br>
+// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)** %{{.*}}, i64 2<br>
+// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*, ...)** [[VPTR]]<br>
+// CHECK64: musttail call void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)<br>
+// CHECK64-NEXT: ret void<br>
// CHECK64: }<br>
<br>
// Thunk for calling the virtual function in internal class D.<br>
-// CHECK32-LABEL: define internal x86_thiscallcc void @"\01??_9D@?A@@$BA@AE"(%"<u></u>struct.(anonymous namespace)::D"* %this)<br>
-// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%"struct.(anonymous namespace)::D"*)** %{{.*}}, i64 0<br>
-// CHECK32: [[CALLEE:%.*]] = load void (%"struct.(anonymous namespace)::D"*)** [[VPTR]]<br>
-// CHECK32: call x86_thiscallcc void [[CALLEE]](%"struct.(anonymous namespace)::D"* %{{.*}})<br>
-// CHECK32: ret void<br>
+// CHECK32-LABEL: define internal x86_thiscallcc void @"\01??_9D@?A@@$BA@AE"(%"<u></u>struct.(anonymous namespace)::D"* %this, ...)<br>
+// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%"struct.(anonymous namespace)::D"*, ...)** %{{.*}}, i64 0<br>
+// CHECK32: [[CALLEE:%.*]] = load void (%"struct.(anonymous namespace)::D"*, ...)** [[VPTR]]<br>
+// CHECK32: musttail call x86_thiscallcc void (%"struct.(anonymous namespace)::D"*, ...)* [[CALLEE]](%"struct.(anonymous namespace)::D"* %{{.*}}, ...)<br>
+// CHECK32-NEXT: ret void<br>
// CHECK32: }<br>
//<br>
-// CHECK64-LABEL: define internal void @"\01??_9D@?A@@$BA@AA"(%"<u></u>struct.(anonymous namespace)::D"* %this)<br>
-// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%"struct.(anonymous namespace)::D"*)** %{{.*}}, i64 0<br>
-// CHECK64: [[CALLEE:%.*]] = load void (%"struct.(anonymous namespace)::D"*)** [[VPTR]]<br>
-// CHECK64: call void [[CALLEE]](%"struct.(anonymous namespace)::D"* %{{.*}})<br>
-// CHECK64: ret void<br>
+// CHECK64-LABEL: define internal void @"\01??_9D@?A@@$BA@AA"(%"<u></u>struct.(anonymous namespace)::D"* %this, ...)<br>
+// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%"struct.(anonymous namespace)::D"*, ...)** %{{.*}}, i64 0<br>
+// CHECK64: [[CALLEE:%.*]] = load void (%"struct.(anonymous namespace)::D"*, ...)** [[VPTR]]<br>
+// CHECK64: musttail call void (%"struct.(anonymous namespace)::D"*, ...)* [[CALLEE]](%"struct.(anonymous namespace)::D"* %{{.*}}, ...)<br>
+// CHECK64-NEXT: ret void<br>
// CHECK64: }<br>
<br>
// Thunk for calling the fourth virtual function in C, taking a struct parameter<br>
// and returning a struct.<br>
-// CHECK32-LABEL: define linkonce_odr x86_thiscallcc %struct.S* @"\01??_9C@@$BM@AE"(%struct.C* %this, <{ %struct.S*, %struct.U }>* inalloca)<br>
-// CHECK32: [[VPTR:%.*]] = getelementptr inbounds %struct.S* (%struct.C*, <{ %struct.S*, %struct.U }>*)** %{{.*}}, i64 3<br>
-// CHECK32: [[CALLEE:%.*]] = load %struct.S* (%struct.C*, <{ %struct.S*, %struct.U }>*)** [[VPTR]]<br>
-// CHECK32: [[CALL:%.*]] = musttail call x86_thiscallcc %struct.S* [[CALLEE]](%struct.C* %{{.*}}, <{ %struct.S*, %struct.U }>* inalloca %{{.*}})<br>
-// CHECK32-NEXT: ret %struct.S* [[CALL]]<br>
+// CHECK32-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@@$BM@AE"(%struct.C* %this, ...)<br>
+// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)** %{{.*}}, i64 3<br>
+// CHECK32: [[CALLEE:%.*]] = load void (%struct.C*, ...)** [[VPTR]]<br>
+// CHECK32: musttail call x86_thiscallcc void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)<br>
+// CHECK32-NEXT: ret void<br>
// CHECK32: }<br>
//<br>
-// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BBI@AA"(%struct.<u></u>C* %this, %struct.S* noalias sret %agg.result, %struct.U*)<br>
-// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, %struct.S*, %struct.U*)** %{{.*}}, i64 3<br>
-// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*, %struct.S*, %struct.U*)** [[VPTR]]<br>
-// CHECK64: call void [[CALLEE]](%struct.C* %{{.*}}, %struct.S* sret %agg.result, %struct.U* %{{.*}})<br>
+// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BBI@AA"(%struct.<u></u>C* %this, ...)<br>
+// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)** %{{.*}}, i64 3<br>
+// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*, ...)** [[VPTR]]<br>
+// CHECK64: musttail call void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)<br>
// CHECK64: ret void<br>
// CHECK64: }<br>
<br>
// Thunk for calling the fifth virtual function in C, taking a struct parameter<br>
// and returning a struct.<br>
-// CHECK32-LABEL: define linkonce_odr x86_fastcallcc void @"\01??_9C@@$BBA@AE"(%struct.<u></u>C* inreg %this, %struct.S* inreg noalias sret %agg.result, <{ %struct.U }>* inalloca)<br>
-// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, %struct.S*, <{ %struct.U }>*)** %{{.*}}, i64 4<br>
-// CHECK32: [[CALLEE:%.*]] = load void (%struct.C*, %struct.S*, <{ %struct.U }>*)** [[VPTR]]<br>
-// CHECK32: musttail call x86_fastcallcc void [[CALLEE]](%struct.C* inreg %{{.*}}, %struct.S* inreg sret %{{.*}}, <{ %struct.U }>* inalloca %{{.*}})<br>
+// CHECK32-LABEL: define linkonce_odr x86_fastcallcc void @"\01??_9C@@$BBA@AE"(%struct.<u></u>C* inreg %this, ...)<br>
+// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)** %{{.*}}, i64 4<br>
+// CHECK32: [[CALLEE:%.*]] = load void (%struct.C*, ...)** [[VPTR]]<br>
+// CHECK32: musttail call x86_fastcallcc void (%struct.C*, ...)* [[CALLEE]](%struct.C* inreg %{{.*}}, ...)<br>
// CHECK32-NEXT: ret void<br>
// CHECK32: }<br>
//<br>
-// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BCA@AA"(%struct.<u></u>C* %this, %struct.S* noalias sret %agg.result, %struct.U*)<br>
-// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, %struct.S*, %struct.U*)** %{{.*}}, i64 4<br>
-// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*, %struct.S*, %struct.U*)** [[VPTR]]<br>
-// CHECK64: call void [[CALLEE]](%struct.C* %{{.*}}, %struct.S* sret %agg.result, %struct.U* %{{.*}})<br>
+// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BCA@AA"(%struct.<u></u>C* %this, ...)<br>
+// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)** %{{.*}}, i64 4<br>
+// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*, ...)** [[VPTR]]<br>
+// CHECK64: musttail call void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)<br>
// CHECK64: ret void<br>
// CHECK64: }<br>
<br>
Added: cfe/trunk/test/CodeGenCXX/<u></u>microsoft-abi-vmemptr-<u></u>conflicts.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-vmemptr-conflicts.cpp?rev=216782&view=auto" target="_blank">http://llvm.org/viewvc/llvm-<u></u>project/cfe/trunk/test/<u></u>CodeGenCXX/microsoft-abi-<u></u>vmemptr-conflicts.cpp?rev=<u></u>216782&view=auto</a><br>
==============================<u></u>==============================<u></u>==================<br>
--- cfe/trunk/test/CodeGenCXX/<u></u>microsoft-abi-vmemptr-<u></u>conflicts.cpp (added)<br>
+++ cfe/trunk/test/CodeGenCXX/<u></u>microsoft-abi-vmemptr-<u></u>conflicts.cpp Fri Aug 29 16:43:29 2014<br>
@@ -0,0 +1,101 @@<br>
+// RUN: %clang_cc1 -fno-rtti -emit-llvm -triple=i386-pc-win32 %s -o - | FileCheck %s<br>
+<br>
+// In each test case, we have two member pointers whose thunks have the same<br>
+// vtable offset and same mangling, but their prototypes conflict. The<br>
+// arguments and return type may differ. Therefore, we have to bitcast the<br>
+// function prototype. Unfortunately, if the return types differ, LLVM's<br>
+// optimizers can get upset.<br>
+<br>
+namespace num_params {<br>
+struct A { virtual void a(int); };<br>
+struct B { virtual void b(int, int); };<br>
+struct C : A, B {<br>
+ virtual void a(int);<br>
+ virtual void b(int, int);<br>
+};<br>
+void f(C *c) {<br>
+ (c->*(&C::a))(0);<br>
+ (c->*(&C::b))(0, 0);<br>
+}<br>
+}<br>
+<br>
+// CHECK-LABEL: define void @"\01?f@num_params@@YAXPAUC@1@<u></u>@Z"(%"struct.num_params::C"* %c)<br>
+// 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"<u></u>* %{{.*}}, i32 0)<br>
+// 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"<u></u>* %{{.*}}, i32 0, i32 0)<br>
+<br>
+// CHECK-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@num_params@@$BA@AE"<u></u>(%"struct.num_params::C"* %this, ...)<br>
+// CHECK: musttail call x86_thiscallcc void (%"struct.num_params::C"*, ...)* %{{.*}}(%"struct.num_params::<u></u>C"* %{{.*}}, ...)<br>
+// CHECK-NEXT: ret void<br>
+<br>
+namespace i64_return {<br>
+struct A { virtual int a(); };<br>
+struct B { virtual long long b(); };<br>
+struct C : A, B {<br>
+ virtual int a();<br>
+ virtual long long b();<br>
+};<br>
+long long f(C *c) {<br>
+ int x = (c->*(&C::a))();<br>
+ long long y = (c->*(&C::b))();<br>
+ return x + y;<br>
+}<br>
+}<br>
+<br>
+// CHECK-LABEL: define i64 @"\01?f@i64_return@@YA_JPAUC@1<u></u>@@Z"(%"struct.i64_return::C"* %c)<br>
+// CHECK: call x86_thiscallcc i32 bitcast (void (%"struct.i64_return::C"*, ...)* @"\01??_9C@i64_return@@$BA@AE" to i32 (%"struct.i64_return::C"*)*)(%<u></u>"struct.i64_return::C"* %{{.*}})<br>
+// CHECK: call x86_thiscallcc i64 bitcast (void (%"struct.i64_return::C"*, ...)* @"\01??_9C@i64_return@@$BA@AE" to i64 (%"struct.i64_return::C"*)*)(%<u></u>"struct.i64_return::C"* %{{.*}})<br>
+<br>
+// CHECK-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@i64_return@@$BA@AE"<u></u>(%"struct.i64_return::C"* %this, ...)<br>
+// CHECK: musttail call x86_thiscallcc void (%"struct.i64_return::C"*, ...)* %{{.*}}(%"struct.i64_return::<u></u>C"* %{{.*}}, ...)<br>
+// CHECK-NEXT: ret void<br>
+<br>
+namespace sret {<br>
+struct Big { int big[32]; };<br>
+struct A { virtual int a(); };<br>
+struct B { virtual Big b(); };<br>
+struct C : A, B {<br>
+ virtual int a();<br>
+ virtual Big b();<br>
+};<br>
+void f(C *c) {<br>
+ (c->*(&C::a))();<br>
+ Big b((c->*(&C::b))());<br>
+}<br>
+}<br>
+<br>
+// CHECK-LABEL: define void @"\01?f@sret@@YAXPAUC@1@@Z"(%"<u></u>struct.sret::C"* %c)<br>
+// CHECK: call x86_thiscallcc i32 bitcast (void (%"struct.sret::C"*, ...)* @"\01??_9C@sret@@$BA@AE" to i32 (%"struct.sret::C"*)*)(%"<u></u>struct.sret::C"* %{{.*}})<br>
+// CHECK: call x86_thiscallcc void bitcast (void (%"struct.sret::C"*, ...)* @"\01??_9C@sret@@$BA@AE" to void (%"struct.sret::C"*, %"struct.sret::Big"*)*)(%"<u></u>struct.sret::C"* %{{.*}}, %"struct.sret::Big"* sret %{{.*}})<br>
+<br>
+// CHECK-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@sret@@$BA@AE"(%"<u></u>struct.sret::C"* %this, ...)<br>
+// CHECK: musttail call x86_thiscallcc void (%"struct.sret::C"*, ...)* %{{.*}}(%"struct.sret::C"* %{{.*}}, ...)<br>
+// CHECK-NEXT: ret void<br>
+<br>
+namespace cdecl_inalloca {<br>
+// Fairly evil, since now we end up doing an inalloca-style call through a<br>
+// thunk that doesn't use inalloca. Hopefully the stacks line up?<br>
+struct Big {<br>
+ Big();<br>
+ ~Big();<br>
+ int big[32];<br>
+};<br>
+struct A { virtual void __cdecl a(); };<br>
+struct B { virtual void __cdecl b(Big); };<br>
+struct C : A, B {<br>
+ virtual void __cdecl a();<br>
+ virtual void __cdecl b(Big);<br>
+};<br>
+void f(C *c) {<br>
+ Big b;<br>
+ (c->*(&C::a))();<br>
+ ((c->*(&C::b))(b));<br>
+}<br>
+}<br>
+<br>
+// CHECK-LABEL: define void @"\01?f@cdecl_inalloca@@<u></u>YAXPAUC@1@@Z"(%"struct.cdecl_<u></u>inalloca::C"* %c)<br>
+// CHECK: call void bitcast (void (%"struct.cdecl_inalloca::C"*, ...)* @"\01??_9C@cdecl_inalloca@@$<u></u>BA@AE" to void (%"struct.cdecl_inalloca::C"*)<u></u>*)(%"struct.cdecl_inalloca::C"<u></u>* %{{.*}})<br>
+// CHECK: call void bitcast (void (%"struct.cdecl_inalloca::C"*, ...)* @"\01??_9C@cdecl_inalloca@@$<u></u>BA@AE" to void (<{ %"struct.cdecl_inalloca::C"*, %"struct.cdecl_inalloca::Big" }>*)*)(<{ %"struct.cdecl_inalloca::C"*, %"struct.cdecl_inalloca::Big" }>* inalloca %{{.*}})<br>
+<br>
+// CHECK-LABEL: define linkonce_odr void @"\01??_9C@cdecl_inalloca@@$<u></u>BA@AE"(%"struct.cdecl_<u></u>inalloca::C"* %this, ...)<br>
+// CHECK: musttail call void (%"struct.cdecl_inalloca::C"*, ...)* %{{.*}}(%"struct.cdecl_<u></u>inalloca::C"* %{{.*}}, ...)<br>
+// CHECK-NEXT: ret void<br>
<br>
Added: cfe/trunk/test/CodeGenCXX/<u></u>microsoft-abi-vmemptr-<u></u>fastcall.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-vmemptr-fastcall.cpp?rev=216782&view=auto" target="_blank">http://llvm.org/viewvc/llvm-<u></u>project/cfe/trunk/test/<u></u>CodeGenCXX/microsoft-abi-<u></u>vmemptr-fastcall.cpp?rev=<u></u>216782&view=auto</a><br>
==============================<u></u>==============================<u></u>==================<br>
--- cfe/trunk/test/CodeGenCXX/<u></u>microsoft-abi-vmemptr-<u></u>fastcall.cpp (added)<br>
+++ cfe/trunk/test/CodeGenCXX/<u></u>microsoft-abi-vmemptr-<u></u>fastcall.cpp Fri Aug 29 16:43:29 2014<br>
@@ -0,0 +1,11 @@<br>
+// RUN: %clang_cc1 -triple i686-pc-windows-msvc %s -emit-llvm-only -verify<br>
+<br>
+// We reject this because LLVM doesn't forward the second regparm through the<br>
+// thunk.<br>
+<br>
+struct A {<br>
+ virtual void __fastcall f(int a, int b);<br>
+};<br>
+void (__fastcall A::*doit())(int, int) {<br>
+ return &A::f; // expected-error {{cannot compile this pointer to fastcall virtual member function yet}}<br>
+}<br>
<br>
<br>
______________________________<u></u>_________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@cs.uiuc.edu" target="_blank">cfe-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/<u></u>mailman/listinfo/cfe-commits</a><br>
</blockquote></div>