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