r194827 - [-cxx-abi microsoft] Emit thunks for pointers to virtual member functions

Mark Lacey mark.lacey at apple.com
Fri Nov 15 10:42:37 PST 2013


Hi Hans,

On Nov 15, 2013, at 9:24 AM, Hans Wennborg <hans at hanshq.net> wrote:

> Author: hans
> Date: Fri Nov 15 11:24:45 2013
> New Revision: 194827
> 
> URL: http://llvm.org/viewvc/llvm-project?rev=194827&view=rev
> Log:
> [-cxx-abi microsoft] Emit thunks for pointers to virtual member functions
> 
> Instead of storing the vtable offset directly in the function pointer and
> doing a branch to check for virtualness at each call site, the MS ABI
> generates a thunk for calling the function at a specific vtable offset,
> and puts that in the function pointer.
> 
> This patch adds support for emitting such thunks. However, it doesn't support
> pointers to virtual member functions that are variadic, have an incomplete
> aggregate return type or parameter, or are overriding a function in a virtual
> base class.
> 
> Differential Revision: http://llvm-reviews.chandlerc.com/D2104
> 
> Added:
>    cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-member-pointers.cpp
> Modified:
>    cfe/trunk/include/clang/AST/Mangle.h
>    cfe/trunk/lib/AST/MicrosoftMangle.cpp
>    cfe/trunk/lib/CodeGen/CGVTables.cpp
>    cfe/trunk/lib/CodeGen/CodeGenFunction.h
>    cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
> 
> Modified: cfe/trunk/include/clang/AST/Mangle.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Mangle.h?rev=194827&r1=194826&r2=194827&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/AST/Mangle.h (original)
> +++ cfe/trunk/include/clang/AST/Mangle.h Fri Nov 15 11:24:45 2013
> @@ -193,6 +193,9 @@ public:
>                                 ArrayRef<const CXXRecordDecl *> BasePath,
>                                 raw_ostream &Out) = 0;
> 
> +  virtual void mangleVirtualMemPtrThunk(const CXXMethodDecl *MD,
> +                                        int OffsetInVFTable, raw_ostream &) = 0;
> +
>   static bool classof(const MangleContext *C) {
>     return C->getKind() == MK_Microsoft;
>   }
> 
> Modified: cfe/trunk/lib/AST/MicrosoftMangle.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/MicrosoftMangle.cpp?rev=194827&r1=194826&r2=194827&view=diff
> ==============================================================================
> --- cfe/trunk/lib/AST/MicrosoftMangle.cpp (original)
> +++ cfe/trunk/lib/AST/MicrosoftMangle.cpp Fri Nov 15 11:24:45 2013
> @@ -181,6 +181,8 @@ public:
>       : MicrosoftMangleContext(Context, Diags) {}
>   virtual bool shouldMangleCXXName(const NamedDecl *D);
>   virtual void mangleCXXName(const NamedDecl *D, raw_ostream &Out);
> +  virtual void mangleVirtualMemPtrThunk(const CXXMethodDecl *MD,
> +                                        int OffsetInVFTable, raw_ostream &);
>   virtual void mangleThunk(const CXXMethodDecl *MD,
>                            const ThunkInfo &Thunk,
>                            raw_ostream &);
> @@ -1921,6 +1923,19 @@ static void mangleThunkThisAdjustment(co
>   }
> }
> 
> +void MicrosoftMangleContextImpl::mangleVirtualMemPtrThunk(
> +    const CXXMethodDecl *MD, int OffsetInVFTable, raw_ostream &Out) {
> +  bool Is64Bit = getASTContext().getTargetInfo().getPointerWidth(0) == 64;
> +
> +  MicrosoftCXXNameMangler Mangler(*this, Out);
> +  Mangler.getStream() << "\01??_9";
> +  Mangler.mangleName(MD->getParent());
> +  Mangler.getStream() << "$B";
> +  Mangler.mangleNumber(OffsetInVFTable);
> +  Mangler.getStream() << "A";
> +  Mangler.getStream() << (Is64Bit ? "A" : "E");
> +}
> +
> void MicrosoftMangleContextImpl::mangleThunk(const CXXMethodDecl *MD,
>                                              const ThunkInfo &Thunk,
>                                              raw_ostream &Out) {
> 
> Modified: cfe/trunk/lib/CodeGen/CGVTables.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVTables.cpp?rev=194827&r1=194826&r2=194827&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGVTables.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGVTables.cpp Fri Nov 15 11:24:45 2013
> @@ -238,92 +238,99 @@ void CodeGenFunction::GenerateVarArgsThu
>   }
> }
> 
> -void CodeGenFunction::GenerateThunk(llvm::Function *Fn,
> -                                    const CGFunctionInfo &FnInfo,
> -                                    GlobalDecl GD, const ThunkInfo &Thunk) {
> +void CodeGenFunction::StartThunk(llvm::Function *Fn, GlobalDecl GD,
> +                                 const CGFunctionInfo &FnInfo) {
> +  assert(!CurGD.getDecl() && "CurGD was already set!");
> +  CurGD = GD;
> +
> +  // Build FunctionArgs.
>   const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
> -  const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
>   QualType ThisType = MD->getThisType(getContext());
> +  const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
>   QualType ResultType =
>     CGM.getCXXABI().HasThisReturn(GD) ? ThisType : FPT->getResultType();
> -
>   FunctionArgList FunctionArgs;
> 
> -  // FIXME: It would be nice if more of this code could be shared with 
> -  // CodeGenFunction::GenerateCode.
> -
>   // Create the implicit 'this' parameter declaration.
> -  CurGD = GD;
>   CGM.getCXXABI().BuildInstanceFunctionParams(*this, ResultType, FunctionArgs);
> 
>   // Add the rest of the parameters.
>   for (FunctionDecl::param_const_iterator I = MD->param_begin(),
> -       E = MD->param_end(); I != E; ++I) {
> -    ParmVarDecl *Param = *I;
> -    
> -    FunctionArgs.push_back(Param);
> -  }
> +                                          E = MD->param_end();
> +       I != E; ++I)
> +    FunctionArgs.push_back(*I);
> 
> +  // Start defining the function.
>   StartFunction(GlobalDecl(), ResultType, Fn, FnInfo, FunctionArgs,
>                 SourceLocation());
> 
> +  // Since we didn't pass a GlobalDecl to StartFunction, do this ourselves.
>   CGM.getCXXABI().EmitInstanceFunctionProlog(*this);
>   CXXThisValue = CXXABIThisValue;
> +}
> 
> -  // Adjust the 'this' pointer if necessary.
> -  llvm::Value *AdjustedThisPtr =
> -      CGM.getCXXABI().performThisAdjustment(*this, LoadCXXThis(), Thunk.This);
> +void CodeGenFunction::EmitCallAndReturnForThunk(GlobalDecl GD,
> +                                                llvm::Value *Callee,
> +                                                const ThunkInfo *Thunk) {
> +  assert(isa<CXXMethodDecl>(CurGD.getDecl()) &&
> +         "Please use a new CGF for this thunk");
> +  const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
> 
> +  // Adjust the 'this' pointer if necessary
> +  llvm::Value *AdjustedThisPtr = Thunk ? CGM.getCXXABI().performThisAdjustment(
> +                                             *this, LoadCXXThis(), Thunk->This)
> +                                       : LoadCXXThis();
> +
> +  // Start building CallArgs.
>   CallArgList CallArgs;
> -  
> -  // Add our adjusted 'this' pointer.
> +  QualType ThisType = MD->getThisType(getContext());
>   CallArgs.add(RValue::get(AdjustedThisPtr), ThisType);
> 
>   if (isa<CXXDestructorDecl>(MD))
>     CGM.getCXXABI().adjustCallArgsForDestructorThunk(*this, GD, CallArgs);
> 
> -  // Add the rest of the parameters.
> +  // Add the rest of the arguments.
>   for (FunctionDecl::param_const_iterator I = MD->param_begin(),
> -       E = MD->param_end(); I != E; ++I) {
> -    ParmVarDecl *param = *I;
> -    EmitDelegateCallArg(CallArgs, param, param->getLocStart());
> -  }
> +       E = MD->param_end(); I != E; ++I)
> +    EmitDelegateCallArg(CallArgs, *I, (*I)->getLocStart());
> 
> -  // Get our callee.
> -  llvm::Type *Ty =
> -    CGM.getTypes().GetFunctionType(CGM.getTypes().arrangeGlobalDeclaration(GD));
> -  llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty, /*ForVTable=*/true);
> +  const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
> 
> #ifndef NDEBUG
>   const CGFunctionInfo &CallFnInfo =
>     CGM.getTypes().arrangeCXXMethodCall(CallArgs, FPT,
>                                        RequiredArgs::forPrototypePlus(FPT, 1));
> -  assert(CallFnInfo.getRegParm() == FnInfo.getRegParm() &&
> -         CallFnInfo.isNoReturn() == FnInfo.isNoReturn() &&
> -         CallFnInfo.getCallingConvention() == FnInfo.getCallingConvention());
> +  assert(CallFnInfo.getRegParm() == CurFnInfo->getRegParm() &&
> +         CallFnInfo.isNoReturn() == CurFnInfo->isNoReturn() &&
> +         CallFnInfo.getCallingConvention() == CurFnInfo->getCallingConvention());
>   assert(isa<CXXDestructorDecl>(MD) || // ignore dtor return types
>          similar(CallFnInfo.getReturnInfo(), CallFnInfo.getReturnType(),
> -                 FnInfo.getReturnInfo(), FnInfo.getReturnType()));
> -  assert(CallFnInfo.arg_size() == FnInfo.arg_size());
> -  for (unsigned i = 0, e = FnInfo.arg_size(); i != e; ++i)
> +                 CurFnInfo->getReturnInfo(), CurFnInfo->getReturnType()));
> +  assert(CallFnInfo.arg_size() == CurFnInfo->arg_size());
> +  for (unsigned i = 0, e = CurFnInfo->arg_size(); i != e; ++i)
>     assert(similar(CallFnInfo.arg_begin()[i].info,
>                    CallFnInfo.arg_begin()[i].type,
> -                   FnInfo.arg_begin()[i].info, FnInfo.arg_begin()[i].type));
> +                   CurFnInfo->arg_begin()[i].info,
> +                   CurFnInfo->arg_begin()[i].type));
> #endif
> -  
> +
>   // Determine whether we have a return value slot to use.
> +  QualType ResultType =
> +    CGM.getCXXABI().HasThisReturn(GD) ? ThisType : FPT->getResultType();
>   ReturnValueSlot Slot;
>   if (!ResultType->isVoidType() &&
> -      FnInfo.getReturnInfo().getKind() == ABIArgInfo::Indirect &&
> +      CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect &&
>       !hasScalarEvaluationKind(CurFnInfo->getReturnType()))
>     Slot = ReturnValueSlot(ReturnValue, ResultType.isVolatileQualified());
> 
>   // Now emit our call.
> -  RValue RV = EmitCall(FnInfo, Callee, Slot, CallArgs, MD);
> +  RValue RV = EmitCall(*CurFnInfo, Callee, Slot, CallArgs, MD);
> 
> -  if (!Thunk.Return.isEmpty())
> -    RV = PerformReturnAdjustment(*this, ResultType, RV, Thunk);
> +  // Consider return adjustment if we have ThunkInfo.
> +  if (Thunk && !Thunk->Return.isEmpty())
> +    RV = PerformReturnAdjustment(*this, ResultType, RV, *Thunk);
> 
> +  // Emit return.
>   if (!ResultType->isVoidType() && Slot.isNull())
>     CGM.getCXXABI().EmitReturnFromThunk(*this, RV, ResultType);
> 
> @@ -331,11 +338,26 @@ void CodeGenFunction::GenerateThunk(llvm
>   AutoreleaseResult = false;
> 
>   FinishFunction();
> +}
> +
> +void CodeGenFunction::GenerateThunk(llvm::Function *Fn,
> +                                    const CGFunctionInfo &FnInfo,
> +                                    GlobalDecl GD, const ThunkInfo &Thunk) {
> +  StartThunk(Fn, GD, FnInfo);
> +
> +  // Get our callee.
> +  llvm::Type *Ty =
> +    CGM.getTypes().GetFunctionType(CGM.getTypes().arrangeGlobalDeclaration(GD));
> +  llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty, /*ForVTable=*/true);
> +
> +  // Make the call and return the result.
> +  EmitCallAndReturnForThunk(GD, Callee, &Thunk);
> 
>   // Set the right linkage.
>   CGM.setFunctionLinkage(GD, Fn);
> 
>   // Set the right visibility.
> +  const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
>   setThunkVisibility(CGM, MD, Thunk, Fn);
> }
> 
> 
> Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=194827&r1=194826&r2=194827&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
> +++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Fri Nov 15 11:24:45 2013
> @@ -1153,6 +1153,11 @@ public:
>   /// legal to call this function even if there is no current insertion point.
>   void FinishFunction(SourceLocation EndLoc=SourceLocation());
> 
> +  void StartThunk(llvm::Function *Fn, GlobalDecl GD, const CGFunctionInfo &FnInfo);
> +
> +  void EmitCallAndReturnForThunk(GlobalDecl GD, llvm::Value *Callee,
> +                                 const ThunkInfo *Thunk);
> +
>   /// GenerateThunk - Generate a thunk for the given method.
>   void GenerateThunk(llvm::Function *Fn, const CGFunctionInfo &FnInfo,
>                      GlobalDecl GD, const ThunkInfo &Thunk);
> 
> Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=194827&r1=194826&r2=194827&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original)
> +++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Fri Nov 15 11:24:45 2013
> @@ -311,6 +311,10 @@ private:
>   /// \brief Caching wrapper around VBTableBuilder::enumerateVBTables().
>   const VBTableVector &EnumerateVBTables(const CXXRecordDecl *RD);
> 
> +  /// \brief Generate a thunk for calling a virtual member function MD.
> +  llvm::Function *EmitVirtualMemPtrThunk(const CXXMethodDecl *MD,
> +                                         StringRef ThunkName);
> +
> public:
>   virtual llvm::Type *ConvertMemberPointerType(const MemberPointerType *MPT);
> 
> @@ -970,6 +974,43 @@ MicrosoftCXXABI::EnumerateVBTables(const
>   return VBTables;
> }
> 
> +llvm::Function *
> +MicrosoftCXXABI::EmitVirtualMemPtrThunk(const CXXMethodDecl *MD,
> +                                        StringRef ThunkName) {
> +  // If the thunk has been generated previously, just return it.
> +  if (llvm::GlobalValue *GV = CGM.getModule().getNamedValue(ThunkName))
> +    return cast<llvm::Function>(GV);
> +
> +  // Create the llvm::Function.
> +  const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeGlobalDeclaration(MD);
> +  llvm::FunctionType *ThunkTy = CGM.getTypes().GetFunctionType(FnInfo);
> +  llvm::Function *ThunkFn =
> +      llvm::Function::Create(ThunkTy, llvm::Function::ExternalLinkage,
> +                             ThunkName.str(), &CGM.getModule());
> +  assert(ThunkFn->getName() == ThunkName && "name was uniqued!");
> +
> +  LinkageInfo LV = MD->getLinkageAndVisibility();

LV is unused. Did you intend to use it in the call to setLinkage below?

Mark

> +  ThunkFn->setLinkage(MD->isExternallyVisible()
> +                          ? llvm::GlobalValue::LinkOnceODRLinkage
> +                          : llvm::GlobalValue::InternalLinkage);
> +
> +  CGM.SetLLVMFunctionAttributes(MD, FnInfo, ThunkFn);
> +  CGM.SetLLVMFunctionAttributesForDefinition(MD, ThunkFn);
> +
> +  // Start codegen.
> +  CodeGenFunction CGF(CGM);
> +  CGF.StartThunk(ThunkFn, MD, FnInfo);
> +
> +  // Get to the Callee.
> +  llvm::Value *This = CGF.LoadCXXThis();
> +  llvm::Value *Callee = getVirtualFunctionPointer(CGF, MD, This, ThunkTy);
> +
> +  // Make the call and return the result.
> +  CGF.EmitCallAndReturnForThunk(MD, Callee, 0);
> +
> +  return ThunkFn;
> +}
> +
> void MicrosoftCXXABI::emitVirtualInheritanceTables(const CXXRecordDecl *RD) {
>   const VBTableVector &VBTables = EnumerateVBTables(RD);
>   llvm::GlobalVariable::LinkageTypes Linkage = CGM.getVTableLinkage(RD);
> @@ -1370,12 +1411,7 @@ MicrosoftCXXABI::BuildMemberPointer(cons
>   CodeGenTypes &Types = CGM.getTypes();
> 
>   llvm::Constant *FirstField;
> -  if (MD->isVirtual()) {
> -    // FIXME: We have to instantiate a thunk that loads the vftable and jumps to
> -    // the right offset.
> -    CGM.ErrorUnsupported(MD, "pointer to virtual member function");
> -    FirstField = llvm::Constant::getNullValue(CGM.VoidPtrTy);
> -  } else {
> +  if (!MD->isVirtual()) {
>     const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
>     llvm::Type *Ty;
>     // Check whether the function has a computable LLVM signature.
> @@ -1389,6 +1425,33 @@ MicrosoftCXXABI::BuildMemberPointer(cons
>     }
>     FirstField = CGM.GetAddrOfFunction(MD, Ty);
>     FirstField = llvm::ConstantExpr::getBitCast(FirstField, CGM.VoidPtrTy);
> +  } 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>())) {
> +      CGM.ErrorUnsupported(MD, "pointer to virtual member function with "
> +                               "incomplete return or parameter type");
> +      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");
> +      FirstField = llvm::Constant::getNullValue(CGM.VoidPtrTy);
> +    } else {
> +      SmallString<256> ThunkName;
> +      int OffsetInVFTable =
> +          ML.Index *
> +          getContext().getTypeSizeInChars(getContext().VoidPtrTy).getQuantity();
> +      llvm::raw_svector_ostream Out(ThunkName);
> +      getMangleContext().mangleVirtualMemPtrThunk(MD, OffsetInVFTable, Out);
> +      Out.flush();
> +
> +      llvm::Function *Thunk = EmitVirtualMemPtrThunk(MD, ThunkName.str());
> +      FirstField = llvm::ConstantExpr::getBitCast(Thunk, CGM.VoidPtrTy);
> +    }
>   }
> 
>   // The rest of the fields are common with data member pointers.
> @@ -1875,4 +1938,3 @@ MicrosoftCXXABI::EmitLoadOfMemberFunctio
> CGCXXABI *clang::CodeGen::CreateMicrosoftCXXABI(CodeGenModule &CGM) {
>   return new MicrosoftCXXABI(CGM);
> }
> -
> 
> Added: 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=194827&view=auto
> ==============================================================================
> --- cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-member-pointers.cpp (added)
> +++ cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-member-pointers.cpp Fri Nov 15 11:24:45 2013
> @@ -0,0 +1,108 @@
> +// RUN: %clang_cc1 -fno-rtti -emit-llvm -cxx-abi microsoft -triple=i386-pc-win32 %s -o - | FileCheck %s --check-prefix=CHECK32
> +// RUN: %clang_cc1 -fno-rtti -emit-llvm -cxx-abi microsoft -triple=x86_64-pc-win32 %s -o - | FileCheck %s --check-prefix=CHECK64
> +
> +struct S {
> +  int x, y, z;
> +};
> +
> +struct C {
> +  virtual void foo();
> +  virtual int bar(int, double);
> +  virtual S baz(int);
> +};
> +
> +namespace {
> +struct D {
> +  virtual void foo();
> +};
> +}
> +
> +void f() {
> +  void (C::*ptr)();
> +  ptr = &C::foo;
> +  ptr = &C::foo; // Don't crash trying to define the thunk twice :)
> +
> +  int (C::*ptr2)(int, double);
> +  ptr2 = &C::bar;
> +
> +  S (C::*ptr3)(int);
> +  ptr3 = &C::baz;
> +
> +  void (D::*ptr4)();
> +  ptr4 = &D::foo;
> +
> +// 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.S*, %struct.C*, 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: }
> +//
> +// 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.S*, %struct.C*, 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: }
> +}
> +
> +
> +// 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) 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: }
> +//
> +// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BA at AA"(%struct.C* %this) 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: }
> +
> +// 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) unnamed_addr
> +// 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: }
> +//
> +// CHECK64-LABEL: define linkonce_odr i32 @"\01??_9C@@$B7AA"(%struct.C* %this, i32, double) unnamed_addr
> +// 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: }
> +
> +// 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.S* noalias sret %agg.result, %struct.C* %this, i32) unnamed_addr
> +// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.S*, %struct.C*, i32)** %{{.*}}, i64 2
> +// CHECK32: [[CALLEE:%.*]] = load void (%struct.S*, %struct.C*, i32)** [[VPTR]]
> +// CHECK32: call x86_thiscallcc void [[CALLEE]](%struct.S* sret %agg.result, %struct.C* %{{.*}}, i32 %{{.*}})
> +// CHECK32: ret void
> +// CHECK32: }
> +//
> +// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BBA at AA"(%struct.S* noalias sret %agg.result, %struct.C* %this, i32) unnamed_addr
> +// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.S*, %struct.C*, i32)** %{{.*}}, i64 2
> +// CHECK64: [[CALLEE:%.*]] = load void (%struct.S*, %struct.C*, i32)** [[VPTR]]
> +// CHECK64: call void [[CALLEE]](%struct.S* sret %agg.result, %struct.C* %{{.*}}, i32 %{{.*}})
> +// CHECK64: 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) unnamed_addr
> +// 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: }
> +//
> +// CHECK64-LABEL: define internal void @"\01??_9D@?A@@$BA at AA"(%"struct.<anonymous namespace>::D"* %this) unnamed_addr
> +// 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: }
> 
> 
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits




More information about the cfe-commits mailing list