Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
213799 views
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:
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
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
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
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
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
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
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.
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
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
260