I think this revision has introduced a bug, see PR20944 for details. On Sat Aug 30 2014 at 1:58:28 AM Reid Kleckner <[email protected]> wrote:
> 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 >
_______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
