1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
|
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This provides an abstract class for C++ code generation. Concrete subclasses
// of this implement code generation for specific C++ ABIs.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_LIB_CIR_CIRGENCXXABI_H
#define LLVM_CLANG_LIB_CIR_CIRGENCXXABI_H
#include "CIRGenCall.h"
#include "CIRGenFunction.h"
#include "CIRGenModule.h"
#include "clang/AST/Mangle.h"
namespace clang::CIRGen {
/// Implements C++ ABI-specific code generation functions.
class CIRGenCXXABI {
protected:
CIRGenModule &cgm;
std::unique_ptr<clang::MangleContext> mangleContext;
public:
// TODO(cir): make this protected when target-specific CIRGenCXXABIs are
// implemented.
CIRGenCXXABI(CIRGenModule &cgm)
: cgm(cgm), mangleContext(cgm.getASTContext().createMangleContext()) {}
virtual ~CIRGenCXXABI();
void setCXXABIThisValue(CIRGenFunction &cgf, mlir::Value thisPtr);
/// Emit the code to initialize hidden members required to handle virtual
/// inheritance, if needed by the ABI.
virtual void
initializeHiddenVirtualInheritanceMembers(CIRGenFunction &cgf,
const CXXRecordDecl *rd) {}
/// Emit a single constructor/destructor with the gen type from a C++
/// constructor/destructor Decl.
virtual void emitCXXStructor(clang::GlobalDecl gd) = 0;
virtual mlir::Value
getVirtualBaseClassOffset(mlir::Location loc, CIRGenFunction &cgf,
Address thisAddr, const CXXRecordDecl *classDecl,
const CXXRecordDecl *baseClassDecl) = 0;
public:
/// Similar to AddedStructorArgs, but only notes the number of additional
/// arguments.
struct AddedStructorArgCounts {
unsigned prefix = 0;
unsigned suffix = 0;
AddedStructorArgCounts() = default;
AddedStructorArgCounts(unsigned p, unsigned s) : prefix(p), suffix(s) {}
static AddedStructorArgCounts withPrefix(unsigned n) { return {n, 0}; }
static AddedStructorArgCounts withSuffix(unsigned n) { return {0, n}; }
};
/// Additional implicit arguments to add to the beginning (Prefix) and end
/// (Suffix) of a constructor / destructor arg list.
///
/// Note that Prefix should actually be inserted *after* the first existing
/// arg; `this` arguments always come first.
struct AddedStructorArgs {
struct Arg {
mlir::Value value;
QualType type;
};
llvm::SmallVector<Arg, 1> prefix;
llvm::SmallVector<Arg, 1> suffix;
AddedStructorArgs() = default;
AddedStructorArgs(llvm::SmallVector<Arg, 1> p, llvm::SmallVector<Arg, 1> s)
: prefix(std::move(p)), suffix(std::move(s)) {}
static AddedStructorArgs withPrefix(llvm::SmallVector<Arg, 1> args) {
return {std::move(args), {}};
}
static AddedStructorArgs withSuffix(llvm::SmallVector<Arg, 1> args) {
return {{}, std::move(args)};
}
};
/// Build the signature of the given constructor or destructor vairant by
/// adding any required parameters. For convenience, ArgTys has been
/// initialized with the type of 'this'.
virtual AddedStructorArgCounts
buildStructorSignature(GlobalDecl gd,
llvm::SmallVectorImpl<CanQualType> &argTys) = 0;
AddedStructorArgCounts
addImplicitConstructorArgs(CIRGenFunction &cgf, const CXXConstructorDecl *d,
CXXCtorType type, bool forVirtualBase,
bool delegating, CallArgList &args);
clang::ImplicitParamDecl *getThisDecl(CIRGenFunction &cgf) {
return cgf.cxxabiThisDecl;
}
virtual AddedStructorArgs
getImplicitConstructorArgs(CIRGenFunction &cgf, const CXXConstructorDecl *d,
CXXCtorType type, bool forVirtualBase,
bool delegating) = 0;
/// Emit the ABI-specific prolog for the function
virtual void emitInstanceFunctionProlog(SourceLocation loc,
CIRGenFunction &cgf) = 0;
virtual void emitRethrow(CIRGenFunction &cgf, bool isNoReturn) = 0;
/// Get the type of the implicit "this" parameter used by a method. May return
/// zero if no specific type is applicable, e.g. if the ABI expects the "this"
/// parameter to point to some artificial offset in a complete object due to
/// vbases being reordered.
virtual const clang::CXXRecordDecl *
getThisArgumentTypeForMethod(const clang::CXXMethodDecl *md) {
return md->getParent();
}
/// Return whether the given global decl needs a VTT (virtual table table)
/// parameter.
virtual bool needsVTTParameter(clang::GlobalDecl gd) { return false; }
/// Perform ABI-specific "this" argument adjustment required prior to
/// a call of a virtual function.
/// The "VirtualCall" argument is true iff the call itself is virtual.
virtual Address adjustThisArgumentForVirtualFunctionCall(CIRGenFunction &cgf,
clang::GlobalDecl gd,
Address thisPtr,
bool virtualCall) {
return thisPtr;
}
/// Build a parameter variable suitable for 'this'.
void buildThisParam(CIRGenFunction &cgf, FunctionArgList ¶ms);
/// Loads the incoming C++ this pointer as it was passed by the caller.
mlir::Value loadIncomingCXXThis(CIRGenFunction &cgf);
/// Emit constructor variants required by this ABI.
virtual void emitCXXConstructors(const clang::CXXConstructorDecl *d) = 0;
/// Emit dtor variants required by this ABI.
virtual void emitCXXDestructors(const clang::CXXDestructorDecl *d) = 0;
virtual void emitDestructorCall(CIRGenFunction &cgf,
const CXXDestructorDecl *dd, CXXDtorType type,
bool forVirtualBase, bool delegating,
Address thisAddr, QualType thisTy) = 0;
/// Checks if ABI requires extra virtual offset for vtable field.
virtual bool
isVirtualOffsetNeededForVTableField(CIRGenFunction &cgf,
CIRGenFunction::VPtr vptr) = 0;
/// Emits the VTable definitions required for the given record type.
virtual void emitVTableDefinitions(CIRGenVTables &cgvt,
const CXXRecordDecl *rd) = 0;
/// Emit any tables needed to implement virtual inheritance. For Itanium,
/// this emits virtual table tables.
virtual void emitVirtualInheritanceTables(const CXXRecordDecl *rd) = 0;
/// Returns true if the given destructor type should be emitted as a linkonce
/// delegating thunk, regardless of whether the dtor is defined in this TU or
/// not.
virtual bool useThunkForDtorVariant(const CXXDestructorDecl *dtor,
CXXDtorType dt) const = 0;
virtual cir::GlobalLinkageKind
getCXXDestructorLinkage(GVALinkage linkage, const CXXDestructorDecl *dtor,
CXXDtorType dt) const;
/// Get the address of the vtable for the given record decl which should be
/// used for the vptr at the given offset in RD.
virtual cir::GlobalOp getAddrOfVTable(const CXXRecordDecl *rd,
CharUnits vptrOffset) = 0;
/// Build a virtual function pointer in the ABI-specific way.
virtual CIRGenCallee getVirtualFunctionPointer(CIRGenFunction &cgf,
clang::GlobalDecl gd,
Address thisAddr,
mlir::Type ty,
SourceLocation loc) = 0;
/// Get the address point of the vtable for the given base subobject.
virtual mlir::Value
getVTableAddressPoint(BaseSubobject base,
const CXXRecordDecl *vtableClass) = 0;
/// Get the address point of the vtable for the given base subobject while
/// building a constructor or a destructor.
virtual mlir::Value getVTableAddressPointInStructor(
CIRGenFunction &cgf, const CXXRecordDecl *vtableClass, BaseSubobject base,
const CXXRecordDecl *nearestVBase) = 0;
/// Insert any ABI-specific implicit parameters into the parameter list for a
/// function. This generally involves extra data for constructors and
/// destructors.
///
/// ABIs may also choose to override the return type, which has been
/// initialized with the type of 'this' if HasThisReturn(CGF.CurGD) is true or
/// the formal return type of the function otherwise.
virtual void addImplicitStructorParams(CIRGenFunction &cgf,
clang::QualType &resTy,
FunctionArgList ¶ms) = 0;
/// Checks if ABI requires to initialize vptrs for given dynamic class.
virtual bool
doStructorsInitializeVPtrs(const clang::CXXRecordDecl *vtableClass) = 0;
/// Returns true if the given constructor or destructor is one of the kinds
/// that the ABI says returns 'this' (only applies when called non-virtually
/// for destructors).
///
/// There currently is no way to indicate if a destructor returns 'this' when
/// called virtually, and CIR generation does not support this case.
virtual bool hasThisReturn(clang::GlobalDecl gd) const { return false; }
virtual bool hasMostDerivedReturn(clang::GlobalDecl gd) const {
return false;
}
/// Gets the mangle context.
clang::MangleContext &getMangleContext() { return *mangleContext; }
clang::ImplicitParamDecl *&getStructorImplicitParamDecl(CIRGenFunction &cgf) {
return cgf.cxxStructorImplicitParamDecl;
}
mlir::Value getStructorImplicitParamValue(CIRGenFunction &cgf) {
return cgf.cxxStructorImplicitParamValue;
}
void setStructorImplicitParamValue(CIRGenFunction &cgf, mlir::Value val) {
cgf.cxxStructorImplicitParamValue = val;
}
};
/// Creates and Itanium-family ABI
CIRGenCXXABI *CreateCIRGenItaniumCXXABI(CIRGenModule &cgm);
} // namespace clang::CIRGen
#endif
|