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
28using namespace clang;
29using namespace clang::CIRGen;
30
31namespace {
32
33class CIRGenItaniumCXXABI : public CIRGenCXXABI {
34public:
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
49 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
60void 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(gd: 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
92namespace {
93enum class StructorCIRGen { Emit, RAUW, Alias, COMDAT };
94}
95
96static 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>(Val: 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>(Val: 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
139static 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(gd: 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
160void CIRGenItaniumCXXABI::emitCXXStructor(GlobalDecl gd) {
161 auto *md = cast<CXXMethodDecl>(Val: gd.getDecl());
162 StructorCIRGen cirGenType = getCIRGenToUse(cgm, md);
163 const auto *cd = dyn_cast<CXXConstructorDecl>(Val: md);
164
165 if (cd ? gd.getCtorType() == Ctor_Complete
166 : gd.getDtorType() == Dtor_Complete) {
167 GlobalDecl baseDecl =
168 cd ? gd.getWithCtorType(Type: Ctor_Base) : gd.getWithDtorType(Type: Dtor_Base);
169 ;
170
171 if (cirGenType == StructorCIRGen::Alias ||
172 cirGenType == StructorCIRGen::COMDAT) {
173 emitConstructorDestructorAlias(cgm, aliasDecl: gd, targetDecl: 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
190void 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(gd: 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(gd: GlobalDecl(d, Ctor_Complete));
203 }
204}
205
206void CIRGenItaniumCXXABI::emitCXXDestructors(const CXXDestructorDecl *d) {
207 // The destructor used for destructing this as a base class; ignores
208 // virtual bases.
209 cgm.emitGlobal(gd: 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(gd: 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(gd: 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.
225bool CIRGenItaniumCXXABI::needsVTTParameter(GlobalDecl gd) {
226 auto *md = cast<CXXMethodDecl>(Val: 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>(Val: md) && gd.getCtorType() == Ctor_Base)
234 return true;
235
236 // Check if we have a base destructor.
237 if (isa<CXXDestructorDecl>(Val: md) && gd.getDtorType() == Dtor_Base)
238 return true;
239
240 return false;
241}
242
243CIRGenCXXABI *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

source code of clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp