@@ -35,6 +35,18 @@ using namespace clang::CIRGen;
35
35
CIRGenVTables::CIRGenVTables (CIRGenModule &CGM)
36
36
: CGM(CGM), VTContext(CGM.getASTContext().getVTableContext()) {}
37
37
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
+
38
50
static bool UseRelativeLayout (const CIRGenModule &CGM) {
39
51
return CGM.getTarget ().getCXXABI ().isItaniumFamily () &&
40
52
CGM.getItaniumVTableContext ().isRelativeLayout ();
@@ -474,8 +486,6 @@ cir::GlobalLinkageKind CIRGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
474
486
auto r = shouldEmitAvailableExternallyVTable (*this , RD)
475
487
? cir::GlobalLinkageKind::AvailableExternallyLinkage
476
488
: cir::GlobalLinkageKind::ExternalLinkage;
477
- assert (r == cir::GlobalLinkageKind::ExternalLinkage &&
478
- " available external NYI" );
479
489
return r;
480
490
}
481
491
@@ -644,6 +654,134 @@ void CIRGenVTables::emitVTTDefinition(cir::GlobalOp VTT,
644
654
assert (!cir::MissingFeatures::setComdat ());
645
655
}
646
656
}
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
+ }
647
785
648
786
void CIRGenVTables::emitThunks (GlobalDecl GD) {
649
787
const CXXMethodDecl *MD =
@@ -659,8 +797,8 @@ void CIRGenVTables::emitThunks(GlobalDecl GD) {
659
797
if (!ThunkInfoVector)
660
798
return ;
661
799
662
- for ([[maybe_unused]] const ThunkInfo &Thunk : *ThunkInfoVector)
663
- llvm_unreachable ( " NYI " );
800
+ for (const ThunkInfo &Thunk : *ThunkInfoVector)
801
+ maybeEmitThunk (GD, Thunk, /* ForVTable= */ false );
664
802
}
665
803
666
804
bool CIRGenModule::AlwaysHasLTOVisibilityPublic (const CXXRecordDecl *RD) {
0 commit comments