xref: /freebsd/contrib/llvm-project/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
2*700637cbSDimitry Andric //
3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*700637cbSDimitry Andric //
7*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8*700637cbSDimitry Andric //
9*700637cbSDimitry Andric // This provides C++ code generation targeting the Itanium C++ ABI.  The class
10*700637cbSDimitry Andric // in this file generates structures that follow the Itanium C++ ABI, which is
11*700637cbSDimitry Andric // documented at:
12*700637cbSDimitry Andric //  https://itanium-cxx-abi.github.io/cxx-abi/abi.html
13*700637cbSDimitry Andric //  https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html
14*700637cbSDimitry Andric //
15*700637cbSDimitry Andric // It also supports the closely-related ARM ABI, documented at:
16*700637cbSDimitry Andric // https://developer.arm.com/documentation/ihi0041/g/
17*700637cbSDimitry Andric //
18*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
19*700637cbSDimitry Andric 
20*700637cbSDimitry Andric #include "CIRGenCXXABI.h"
21*700637cbSDimitry Andric #include "CIRGenFunction.h"
22*700637cbSDimitry Andric 
23*700637cbSDimitry Andric #include "clang/AST/ExprCXX.h"
24*700637cbSDimitry Andric #include "clang/AST/GlobalDecl.h"
25*700637cbSDimitry Andric #include "clang/CIR/MissingFeatures.h"
26*700637cbSDimitry Andric #include "llvm/Support/ErrorHandling.h"
27*700637cbSDimitry Andric 
28*700637cbSDimitry Andric using namespace clang;
29*700637cbSDimitry Andric using namespace clang::CIRGen;
30*700637cbSDimitry Andric 
31*700637cbSDimitry Andric namespace {
32*700637cbSDimitry Andric 
33*700637cbSDimitry Andric class CIRGenItaniumCXXABI : public CIRGenCXXABI {
34*700637cbSDimitry Andric public:
CIRGenItaniumCXXABI(CIRGenModule & cgm)35*700637cbSDimitry Andric   CIRGenItaniumCXXABI(CIRGenModule &cgm) : CIRGenCXXABI(cgm) {
36*700637cbSDimitry Andric     assert(!cir::MissingFeatures::cxxabiUseARMMethodPtrABI());
37*700637cbSDimitry Andric     assert(!cir::MissingFeatures::cxxabiUseARMGuardVarABI());
38*700637cbSDimitry Andric   }
39*700637cbSDimitry Andric 
40*700637cbSDimitry Andric   bool needsVTTParameter(clang::GlobalDecl gd) override;
41*700637cbSDimitry Andric 
42*700637cbSDimitry Andric   void emitInstanceFunctionProlog(SourceLocation loc,
43*700637cbSDimitry Andric                                   CIRGenFunction &cgf) override;
44*700637cbSDimitry Andric 
45*700637cbSDimitry Andric   void emitCXXConstructors(const clang::CXXConstructorDecl *d) override;
46*700637cbSDimitry Andric   void emitCXXDestructors(const clang::CXXDestructorDecl *d) override;
47*700637cbSDimitry Andric   void emitCXXStructor(clang::GlobalDecl gd) override;
48*700637cbSDimitry Andric 
useThunkForDtorVariant(const CXXDestructorDecl * dtor,CXXDtorType dt) const49*700637cbSDimitry Andric   bool useThunkForDtorVariant(const CXXDestructorDecl *dtor,
50*700637cbSDimitry Andric                               CXXDtorType dt) const override {
51*700637cbSDimitry Andric     // Itanium does not emit any destructor variant as an inline thunk.
52*700637cbSDimitry Andric     // Delegating may occur as an optimization, but all variants are either
53*700637cbSDimitry Andric     // emitted with external linkage or as linkonce if they are inline and used.
54*700637cbSDimitry Andric     return false;
55*700637cbSDimitry Andric   }
56*700637cbSDimitry Andric };
57*700637cbSDimitry Andric 
58*700637cbSDimitry Andric } // namespace
59*700637cbSDimitry Andric 
emitInstanceFunctionProlog(SourceLocation loc,CIRGenFunction & cgf)60*700637cbSDimitry Andric void CIRGenItaniumCXXABI::emitInstanceFunctionProlog(SourceLocation loc,
61*700637cbSDimitry Andric                                                      CIRGenFunction &cgf) {
62*700637cbSDimitry Andric   // Naked functions have no prolog.
63*700637cbSDimitry Andric   if (cgf.curFuncDecl && cgf.curFuncDecl->hasAttr<NakedAttr>()) {
64*700637cbSDimitry Andric     cgf.cgm.errorNYI(cgf.curFuncDecl->getLocation(),
65*700637cbSDimitry Andric                      "emitInstanceFunctionProlog: Naked");
66*700637cbSDimitry Andric   }
67*700637cbSDimitry Andric 
68*700637cbSDimitry Andric   /// Initialize the 'this' slot. In the Itanium C++ ABI, no prologue
69*700637cbSDimitry Andric   /// adjustments are required, because they are all handled by thunks.
70*700637cbSDimitry Andric   setCXXABIThisValue(cgf, loadIncomingCXXThis(cgf));
71*700637cbSDimitry Andric 
72*700637cbSDimitry Andric   /// Classic codegen has code here to initialize the 'vtt' slot if
73*700637cbSDimitry Andric   // getStructorImplicitParamDecl(cgf) returns a non-null value, but in the
74*700637cbSDimitry Andric   // current implementation (of classic codegen) it never does.
75*700637cbSDimitry Andric   assert(!cir::MissingFeatures::cxxabiStructorImplicitParam());
76*700637cbSDimitry Andric 
77*700637cbSDimitry Andric   /// If this is a function that the ABI specifies returns 'this', initialize
78*700637cbSDimitry Andric   /// the return slot to this' at the start of the function.
79*700637cbSDimitry Andric   ///
80*700637cbSDimitry Andric   /// Unlike the setting of return types, this is done within the ABI
81*700637cbSDimitry Andric   /// implementation instead of by clients of CIRGenCXXBI because:
82*700637cbSDimitry Andric   /// 1) getThisValue is currently protected
83*700637cbSDimitry Andric   /// 2) in theory, an ABI could implement 'this' returns some other way;
84*700637cbSDimitry Andric   ///    HasThisReturn only specifies a contract, not the implementation
85*700637cbSDimitry Andric   if (hasThisReturn(cgf.curGD)) {
86*700637cbSDimitry Andric     cgf.cgm.errorNYI(cgf.curFuncDecl->getLocation(),
87*700637cbSDimitry Andric                      "emitInstanceFunctionProlog: hasThisReturn");
88*700637cbSDimitry Andric   }
89*700637cbSDimitry Andric }
90*700637cbSDimitry Andric 
91*700637cbSDimitry Andric // Find out how to cirgen the complete destructor and constructor
92*700637cbSDimitry Andric namespace {
93*700637cbSDimitry Andric enum class StructorCIRGen { Emit, RAUW, Alias, COMDAT };
94*700637cbSDimitry Andric }
95*700637cbSDimitry Andric 
getCIRGenToUse(CIRGenModule & cgm,const CXXMethodDecl * md)96*700637cbSDimitry Andric static StructorCIRGen getCIRGenToUse(CIRGenModule &cgm,
97*700637cbSDimitry Andric                                      const CXXMethodDecl *md) {
98*700637cbSDimitry Andric   if (!cgm.getCodeGenOpts().CXXCtorDtorAliases)
99*700637cbSDimitry Andric     return StructorCIRGen::Emit;
100*700637cbSDimitry Andric 
101*700637cbSDimitry Andric   // The complete and base structors are not equivalent if there are any virtual
102*700637cbSDimitry Andric   // bases, so emit separate functions.
103*700637cbSDimitry Andric   if (md->getParent()->getNumVBases()) {
104*700637cbSDimitry Andric     // The return value is correct here, but other support for this is NYI.
105*700637cbSDimitry Andric     cgm.errorNYI(md->getSourceRange(), "getCIRGenToUse: virtual bases");
106*700637cbSDimitry Andric     return StructorCIRGen::Emit;
107*700637cbSDimitry Andric   }
108*700637cbSDimitry Andric 
109*700637cbSDimitry Andric   GlobalDecl aliasDecl;
110*700637cbSDimitry Andric   if (const auto *dd = dyn_cast<CXXDestructorDecl>(md)) {
111*700637cbSDimitry Andric     // The assignment is correct here, but other support for this is NYI.
112*700637cbSDimitry Andric     cgm.errorNYI(md->getSourceRange(), "getCIRGenToUse: dtor");
113*700637cbSDimitry Andric     aliasDecl = GlobalDecl(dd, Dtor_Complete);
114*700637cbSDimitry Andric   } else {
115*700637cbSDimitry Andric     const auto *cd = cast<CXXConstructorDecl>(md);
116*700637cbSDimitry Andric     aliasDecl = GlobalDecl(cd, Ctor_Complete);
117*700637cbSDimitry Andric   }
118*700637cbSDimitry Andric 
119*700637cbSDimitry Andric   cir::GlobalLinkageKind linkage = cgm.getFunctionLinkage(aliasDecl);
120*700637cbSDimitry Andric 
121*700637cbSDimitry Andric   if (cir::isDiscardableIfUnused(linkage))
122*700637cbSDimitry Andric     return StructorCIRGen::RAUW;
123*700637cbSDimitry Andric 
124*700637cbSDimitry Andric   // FIXME: Should we allow available_externally aliases?
125*700637cbSDimitry Andric   if (!cir::isValidLinkage(linkage))
126*700637cbSDimitry Andric     return StructorCIRGen::RAUW;
127*700637cbSDimitry Andric 
128*700637cbSDimitry Andric   if (cir::isWeakForLinker(linkage)) {
129*700637cbSDimitry Andric     // Only ELF and wasm support COMDATs with arbitrary names (C5/D5).
130*700637cbSDimitry Andric     if (cgm.getTarget().getTriple().isOSBinFormatELF() ||
131*700637cbSDimitry Andric         cgm.getTarget().getTriple().isOSBinFormatWasm())
132*700637cbSDimitry Andric       return StructorCIRGen::COMDAT;
133*700637cbSDimitry Andric     return StructorCIRGen::Emit;
134*700637cbSDimitry Andric   }
135*700637cbSDimitry Andric 
136*700637cbSDimitry Andric   return StructorCIRGen::Alias;
137*700637cbSDimitry Andric }
138*700637cbSDimitry Andric 
emitConstructorDestructorAlias(CIRGenModule & cgm,GlobalDecl aliasDecl,GlobalDecl targetDecl)139*700637cbSDimitry Andric static void emitConstructorDestructorAlias(CIRGenModule &cgm,
140*700637cbSDimitry Andric                                            GlobalDecl aliasDecl,
141*700637cbSDimitry Andric                                            GlobalDecl targetDecl) {
142*700637cbSDimitry Andric   cir::GlobalLinkageKind linkage = cgm.getFunctionLinkage(aliasDecl);
143*700637cbSDimitry Andric 
144*700637cbSDimitry Andric   // Does this function alias already exists?
145*700637cbSDimitry Andric   StringRef mangledName = cgm.getMangledName(aliasDecl);
146*700637cbSDimitry Andric   auto globalValue = dyn_cast_or_null<cir::CIRGlobalValueInterface>(
147*700637cbSDimitry Andric       cgm.getGlobalValue(mangledName));
148*700637cbSDimitry Andric   if (globalValue && !globalValue.isDeclaration())
149*700637cbSDimitry Andric     return;
150*700637cbSDimitry Andric 
151*700637cbSDimitry Andric   auto entry = cast_or_null<cir::FuncOp>(cgm.getGlobalValue(mangledName));
152*700637cbSDimitry Andric 
153*700637cbSDimitry Andric   // Retrieve aliasee info.
154*700637cbSDimitry Andric   auto aliasee = cast<cir::FuncOp>(cgm.getAddrOfGlobal(targetDecl));
155*700637cbSDimitry Andric 
156*700637cbSDimitry Andric   // Populate actual alias.
157*700637cbSDimitry Andric   cgm.emitAliasForGlobal(mangledName, entry, aliasDecl, aliasee, linkage);
158*700637cbSDimitry Andric }
159*700637cbSDimitry Andric 
emitCXXStructor(GlobalDecl gd)160*700637cbSDimitry Andric void CIRGenItaniumCXXABI::emitCXXStructor(GlobalDecl gd) {
161*700637cbSDimitry Andric   auto *md = cast<CXXMethodDecl>(gd.getDecl());
162*700637cbSDimitry Andric   StructorCIRGen cirGenType = getCIRGenToUse(cgm, md);
163*700637cbSDimitry Andric   const auto *cd = dyn_cast<CXXConstructorDecl>(md);
164*700637cbSDimitry Andric 
165*700637cbSDimitry Andric   if (cd ? gd.getCtorType() == Ctor_Complete
166*700637cbSDimitry Andric          : gd.getDtorType() == Dtor_Complete) {
167*700637cbSDimitry Andric     GlobalDecl baseDecl =
168*700637cbSDimitry Andric         cd ? gd.getWithCtorType(Ctor_Base) : gd.getWithDtorType(Dtor_Base);
169*700637cbSDimitry Andric     ;
170*700637cbSDimitry Andric 
171*700637cbSDimitry Andric     if (cirGenType == StructorCIRGen::Alias ||
172*700637cbSDimitry Andric         cirGenType == StructorCIRGen::COMDAT) {
173*700637cbSDimitry Andric       emitConstructorDestructorAlias(cgm, gd, baseDecl);
174*700637cbSDimitry Andric       return;
175*700637cbSDimitry Andric     }
176*700637cbSDimitry Andric 
177*700637cbSDimitry Andric     if (cirGenType == StructorCIRGen::RAUW) {
178*700637cbSDimitry Andric       StringRef mangledName = cgm.getMangledName(gd);
179*700637cbSDimitry Andric       mlir::Operation *aliasee = cgm.getAddrOfGlobal(baseDecl);
180*700637cbSDimitry Andric       cgm.addReplacement(mangledName, aliasee);
181*700637cbSDimitry Andric       return;
182*700637cbSDimitry Andric     }
183*700637cbSDimitry Andric   }
184*700637cbSDimitry Andric 
185*700637cbSDimitry Andric   auto fn = cgm.codegenCXXStructor(gd);
186*700637cbSDimitry Andric 
187*700637cbSDimitry Andric   cgm.maybeSetTrivialComdat(*md, fn);
188*700637cbSDimitry Andric }
189*700637cbSDimitry Andric 
emitCXXConstructors(const CXXConstructorDecl * d)190*700637cbSDimitry Andric void CIRGenItaniumCXXABI::emitCXXConstructors(const CXXConstructorDecl *d) {
191*700637cbSDimitry Andric   // Just make sure we're in sync with TargetCXXABI.
192*700637cbSDimitry Andric   assert(cgm.getTarget().getCXXABI().hasConstructorVariants());
193*700637cbSDimitry Andric 
194*700637cbSDimitry Andric   // The constructor used for constructing this as a base class;
195*700637cbSDimitry Andric   // ignores virtual bases.
196*700637cbSDimitry Andric   cgm.emitGlobal(GlobalDecl(d, Ctor_Base));
197*700637cbSDimitry Andric 
198*700637cbSDimitry Andric   // The constructor used for constructing this as a complete class;
199*700637cbSDimitry Andric   // constructs the virtual bases, then calls the base constructor.
200*700637cbSDimitry Andric   if (!d->getParent()->isAbstract()) {
201*700637cbSDimitry Andric     // We don't need to emit the complete ctro if the class is abstract.
202*700637cbSDimitry Andric     cgm.emitGlobal(GlobalDecl(d, Ctor_Complete));
203*700637cbSDimitry Andric   }
204*700637cbSDimitry Andric }
205*700637cbSDimitry Andric 
emitCXXDestructors(const CXXDestructorDecl * d)206*700637cbSDimitry Andric void CIRGenItaniumCXXABI::emitCXXDestructors(const CXXDestructorDecl *d) {
207*700637cbSDimitry Andric   // The destructor used for destructing this as a base class; ignores
208*700637cbSDimitry Andric   // virtual bases.
209*700637cbSDimitry Andric   cgm.emitGlobal(GlobalDecl(d, Dtor_Base));
210*700637cbSDimitry Andric 
211*700637cbSDimitry Andric   // The destructor used for destructing this as a most-derived class;
212*700637cbSDimitry Andric   // call the base destructor and then destructs any virtual bases.
213*700637cbSDimitry Andric   cgm.emitGlobal(GlobalDecl(d, Dtor_Complete));
214*700637cbSDimitry Andric 
215*700637cbSDimitry Andric   // The destructor in a virtual table is always a 'deleting'
216*700637cbSDimitry Andric   // destructor, which calls the complete destructor and then uses the
217*700637cbSDimitry Andric   // appropriate operator delete.
218*700637cbSDimitry Andric   if (d->isVirtual())
219*700637cbSDimitry Andric     cgm.emitGlobal(GlobalDecl(d, Dtor_Deleting));
220*700637cbSDimitry Andric }
221*700637cbSDimitry Andric 
222*700637cbSDimitry Andric /// Return whether the given global decl needs a VTT (virtual table table)
223*700637cbSDimitry Andric /// parameter, which it does if it's a base constructor or destructor with
224*700637cbSDimitry Andric /// virtual bases.
needsVTTParameter(GlobalDecl gd)225*700637cbSDimitry Andric bool CIRGenItaniumCXXABI::needsVTTParameter(GlobalDecl gd) {
226*700637cbSDimitry Andric   auto *md = cast<CXXMethodDecl>(gd.getDecl());
227*700637cbSDimitry Andric 
228*700637cbSDimitry Andric   // We don't have any virtual bases, just return early.
229*700637cbSDimitry Andric   if (!md->getParent()->getNumVBases())
230*700637cbSDimitry Andric     return false;
231*700637cbSDimitry Andric 
232*700637cbSDimitry Andric   // Check if we have a base constructor.
233*700637cbSDimitry Andric   if (isa<CXXConstructorDecl>(md) && gd.getCtorType() == Ctor_Base)
234*700637cbSDimitry Andric     return true;
235*700637cbSDimitry Andric 
236*700637cbSDimitry Andric   // Check if we have a base destructor.
237*700637cbSDimitry Andric   if (isa<CXXDestructorDecl>(md) && gd.getDtorType() == Dtor_Base)
238*700637cbSDimitry Andric     return true;
239*700637cbSDimitry Andric 
240*700637cbSDimitry Andric   return false;
241*700637cbSDimitry Andric }
242*700637cbSDimitry Andric 
CreateCIRGenItaniumCXXABI(CIRGenModule & cgm)243*700637cbSDimitry Andric CIRGenCXXABI *clang::CIRGen::CreateCIRGenItaniumCXXABI(CIRGenModule &cgm) {
244*700637cbSDimitry Andric   switch (cgm.getASTContext().getCXXABIKind()) {
245*700637cbSDimitry Andric   case TargetCXXABI::GenericItanium:
246*700637cbSDimitry Andric   case TargetCXXABI::GenericAArch64:
247*700637cbSDimitry Andric     return new CIRGenItaniumCXXABI(cgm);
248*700637cbSDimitry Andric 
249*700637cbSDimitry Andric   case TargetCXXABI::AppleARM64:
250*700637cbSDimitry Andric     // The general Itanium ABI will do until we implement something that
251*700637cbSDimitry Andric     // requires special handling.
252*700637cbSDimitry Andric     assert(!cir::MissingFeatures::cxxabiAppleARM64CXXABI());
253*700637cbSDimitry Andric     return new CIRGenItaniumCXXABI(cgm);
254*700637cbSDimitry Andric 
255*700637cbSDimitry Andric   default:
256*700637cbSDimitry Andric     llvm_unreachable("bad or NYI ABI kind");
257*700637cbSDimitry Andric   }
258*700637cbSDimitry Andric }
259