@@ -35,6 +35,18 @@ using namespace clang::CIRGen;
3535CIRGenVTables::CIRGenVTables (CIRGenModule &CGM)
3636 : CGM(CGM), VTContext(CGM.getASTContext().getVTableContext()) {}
3737
38+ cir::FuncOp CIRGenModule::getAddrOfThunk (StringRef name, mlir::Type fnTy,
39+ GlobalDecl gd) {
40+ return GetOrCreateCIRFunction (name, fnTy, gd, /* ForVTable=*/ true ,
41+ /* DontDefer=*/ true , /* IsThunk=*/ true );
42+ }
43+
44+ static void setThunkProperties (CIRGenModule &cgm, const ThunkInfo &thunk,
45+ cir::FuncOp thunkFn, bool forVTable,
46+ GlobalDecl gd) {
47+ llvm_unreachable (" NYI" );
48+ }
49+
3850static bool UseRelativeLayout (const CIRGenModule &CGM) {
3951 return CGM.getTarget ().getCXXABI ().isItaniumFamily () &&
4052 CGM.getItaniumVTableContext ().isRelativeLayout ();
@@ -474,8 +486,6 @@ cir::GlobalLinkageKind CIRGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
474486 auto r = shouldEmitAvailableExternallyVTable (*this , RD)
475487 ? cir::GlobalLinkageKind::AvailableExternallyLinkage
476488 : cir::GlobalLinkageKind::ExternalLinkage;
477- assert (r == cir::GlobalLinkageKind::ExternalLinkage &&
478- " available external NYI" );
479489 return r;
480490 }
481491
@@ -644,6 +654,134 @@ void CIRGenVTables::emitVTTDefinition(cir::GlobalOp VTT,
644654 assert (!cir::MissingFeatures::setComdat ());
645655 }
646656}
657+ static bool shouldEmitVTableThunk (CIRGenModule &CGM, const CXXMethodDecl *MD,
658+ bool IsUnprototyped, bool ForVTable) {
659+ // Always emit thunks in the MS C++ ABI. We cannot rely on other TUs to
660+ // provide thunks for us.
661+ if (CGM.getTarget ().getCXXABI ().isMicrosoft ())
662+ return true ;
663+
664+ // In the Itanium C++ ABI, vtable thunks are provided by TUs that provide
665+ // definitions of the main method. Therefore, emitting thunks with the vtable
666+ // is purely an optimization. Emit the thunk if optimizations are enabled and
667+ // all of the parameter types are complete.
668+ if (ForVTable)
669+ return CGM.getCodeGenOpts ().OptimizationLevel && !IsUnprototyped;
670+
671+ // Always emit thunks along with the method definition.
672+ return true ;
673+ }
674+
675+ cir::FuncOp CIRGenVTables::maybeEmitThunk (GlobalDecl GD,
676+ const ThunkInfo &ThunkAdjustments,
677+ bool ForVTable) {
678+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl ());
679+ SmallString<256 > Name;
680+ MangleContext &MCtx = CGM.getCXXABI ().getMangleContext ();
681+
682+ llvm::raw_svector_ostream Out (Name);
683+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
684+ MCtx.mangleCXXDtorThunk (DD, GD.getDtorType (), ThunkAdjustments,
685+ /* elideOverrideInfo */ false , Out);
686+ } else
687+ MCtx.mangleThunk (MD, ThunkAdjustments, /* elideOverrideInfo */ false , Out);
688+
689+ if (CGM.getASTContext ().useAbbreviatedThunkName (GD, Name.str ())) {
690+ Name = " " ;
691+ if (const CXXDestructorDecl *dd = dyn_cast<CXXDestructorDecl>(MD))
692+ MCtx.mangleCXXDtorThunk (dd, GD.getDtorType (), ThunkAdjustments,
693+ /* elideOverrideInfo */ true , Out);
694+ else
695+ MCtx.mangleThunk (MD, ThunkAdjustments, /* elideOverrideInfo */ true , Out);
696+ }
697+
698+ cir::FuncType ThunkVTableTy = CGM.getTypes ().GetFunctionTypeForVTable (GD);
699+ cir::FuncOp Thunk = CGM.getAddrOfThunk (Name, ThunkVTableTy, GD);
700+
701+ // If we don't need to emit a definition, return this declaration as is.
702+ bool IsUnprototyped = !CGM.getTypes ().isFuncTypeConvertible (
703+ MD->getType ()->castAs <FunctionType>());
704+ if (!shouldEmitVTableThunk (CGM, MD, IsUnprototyped, ForVTable))
705+ return Thunk;
706+
707+ // Arrange a function prototype appropriate for a function definition. In some
708+ // cases in the MS ABI, we may need to build an unprototyped musttail thunk.
709+ const CIRGenFunctionInfo &FnInfo =
710+ IsUnprototyped ? CGM.getTypes ().arrangeUnprototypedMustTailThunk (MD)
711+ : CGM.getTypes ().arrangeGlobalDeclaration (GD);
712+ cir::FuncType ThunkFnTy = CGM.getTypes ().GetFunctionType (FnInfo);
713+
714+ // This is to replace OG's casting to a function, keeping it here to
715+ // streamline the 1-to-1 mapping from OG starting below
716+ cir::FuncOp ThunkFn = Thunk;
717+ if (Thunk.getFunctionType () != ThunkFnTy) {
718+ cir::FuncOp OldThunkFn = ThunkFn;
719+
720+ assert (OldThunkFn.isDeclaration () && " Shouldn't replace non-declaration" );
721+
722+ // Remove the name from the old thunk function and get a new thunk.
723+ OldThunkFn.setName (StringRef ());
724+ auto thunkFn =
725+ cir::FuncOp::create (CGM.getBuilder (), Thunk->getLoc (), Name.str (),
726+ ThunkFnTy, cir::GlobalLinkageKind::ExternalLinkage);
727+ CGM.setCIRFunctionAttributes (MD, FnInfo, thunkFn, /* IsThunk=*/ false );
728+
729+ if (!OldThunkFn->use_empty ()) {
730+ OldThunkFn->replaceAllUsesWith (thunkFn);
731+ }
732+
733+ // Remove the old thunk.
734+ OldThunkFn->erase ();
735+ }
736+ bool ABIHasKeyFunctions = CGM.getTarget ().getCXXABI ().hasKeyFunctions ();
737+ bool UseAvailableExternallyLinkage = ForVTable && ABIHasKeyFunctions;
738+ // If the type of the underlying GlobalValue is wrong, we'll have to replace
739+ // it. It should be a declaration.
740+ if (!ThunkFn.isDeclaration ()) {
741+ if (!ABIHasKeyFunctions || UseAvailableExternallyLinkage) {
742+ // There is already a thunk emitted for this function, do nothing.
743+ return ThunkFn;
744+ }
745+
746+ setThunkProperties (CGM, ThunkAdjustments, ThunkFn, ForVTable, GD);
747+ return ThunkFn;
748+ }
749+ if (IsUnprototyped)
750+ ThunkFn->setAttr (" thunk" , mlir::UnitAttr::get (&CGM.getMLIRContext ()));
751+
752+ CGM.setCIRFunctionAttributesForDefinition (GD.getDecl (), ThunkFn);
753+ //
754+ // Thunks for variadic methods are special because in general variadic
755+ // arguments cannot be perfectly forwarded. In the general case, clang
756+ // implements such thunks by cloning the original function body. However, for
757+ // thunks with no return adjustment on targets that support musttail, we can
758+ // use musttail to perfectly forward the variadic arguments.
759+ bool ShouldCloneVarArgs = false ;
760+ if (!IsUnprototyped && ThunkFn.getFunctionType ().isVarArg ()) {
761+ ShouldCloneVarArgs = true ;
762+ if (ThunkAdjustments.Return .isEmpty ()) {
763+ switch (CGM.getTriple ().getArch ()) {
764+ case llvm::Triple::x86_64:
765+ case llvm::Triple::x86:
766+ case llvm::Triple::aarch64:
767+ ShouldCloneVarArgs = false ;
768+ break ;
769+ default :
770+ break ;
771+ }
772+ }
773+ }
774+ if (ShouldCloneVarArgs) {
775+ if (UseAvailableExternallyLinkage)
776+ return ThunkFn;
777+ llvm_unreachable (" NYI method, see OG GenerateVarArgsThunk" );
778+ } else {
779+ llvm_unreachable (" NYI method, see OG generateThunk" );
780+ }
781+
782+ setThunkProperties (CGM, ThunkAdjustments, ThunkFn, ForVTable, GD);
783+ return ThunkFn;
784+ }
647785
648786void CIRGenVTables::emitThunks (GlobalDecl GD) {
649787 const CXXMethodDecl *MD =
@@ -659,8 +797,8 @@ void CIRGenVTables::emitThunks(GlobalDecl GD) {
659797 if (!ThunkInfoVector)
660798 return ;
661799
662- for ([[maybe_unused]] const ThunkInfo &Thunk : *ThunkInfoVector)
663- llvm_unreachable ( " NYI " );
800+ for (const ThunkInfo &Thunk : *ThunkInfoVector)
801+ maybeEmitThunk (GD, Thunk, /* ForVTable= */ false );
664802}
665803
666804bool CIRGenModule::AlwaysHasLTOVisibilityPublic (const CXXRecordDecl *RD) {
0 commit comments