r216782 - Make all virtual member pointers use variadic musttail calls
Timur Iskhodzhanov
timurrrr at google.com
Wed Jan 21 10:06:55 PST 2015
I think this revision has introduced a bug, see PR20944 for details.
On Sat Aug 30 2014 at 1:58:28 AM Reid Kleckner <reid at kleckner.net> 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 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}}
> +}
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20150121/78f46ca4/attachment.html>
More information about the cfe-commits
mailing list