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