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
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
|
#pragma once
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
//===--- TargetCXXABI.h - C++ ABI Target Configuration ----------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Defines the TargetCXXABI class, which abstracts details of the
/// C++ ABI that we're targeting.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_BASIC_TARGETCXXABI_H
#define LLVM_CLANG_BASIC_TARGETCXXABI_H
#include <map>
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/ErrorHandling.h"
namespace clang {
/// The basic abstraction for the target C++ ABI.
class TargetCXXABI {
public:
/// The basic C++ ABI kind.
enum Kind {
#define CXXABI(Name, Str) Name,
#include "TargetCXXABI.def"
};
private:
// Right now, this class is passed around as a cheap value type.
// If you add more members, especially non-POD members, please
// audit the users to pass it by reference instead.
Kind TheKind;
static const auto &getABIMap() {
static llvm::StringMap<Kind> ABIMap = {
#define CXXABI(Name, Str) {Str, Name},
#include "TargetCXXABI.def"
};
return ABIMap;
}
static const auto &getSpellingMap() {
static std::map<Kind, std::string> SpellingMap = {
#define CXXABI(Name, Str) {Name, Str},
#include "TargetCXXABI.def"
};
return SpellingMap;
}
public:
static Kind getKind(StringRef Name) { return getABIMap().lookup(Name); }
static const auto &getSpelling(Kind ABIKind) {
return getSpellingMap().find(ABIKind)->second;
}
static bool isABI(StringRef Name) {
return getABIMap().find(Name) != getABIMap().end();
}
// Return true if this target should use the relative vtables C++ ABI by
// default.
static bool usesRelativeVTables(const llvm::Triple &T) {
return T.isOSFuchsia();
}
/// A bogus initialization of the platform ABI.
TargetCXXABI() : TheKind(GenericItanium) {}
TargetCXXABI(Kind kind) : TheKind(kind) {}
void set(Kind kind) {
TheKind = kind;
}
Kind getKind() const { return TheKind; }
// Check that the kind provided by the fc++-abi flag is supported on this
// target. Users who want to experiment using different ABIs on specific
// platforms can change this freely, but this function should be conservative
// enough such that not all ABIs are allowed on all platforms. For example, we
// probably don't want to allow usage of an ARM ABI on an x86 architecture.
static bool isSupportedCXXABI(const llvm::Triple &T, Kind Kind) {
switch (Kind) {
case GenericARM:
return T.isARM() || T.isAArch64();
case iOS:
case WatchOS:
case AppleARM64:
return T.isOSDarwin();
case Fuchsia:
return T.isOSFuchsia();
case GenericAArch64:
return T.isAArch64();
case GenericMIPS:
return T.isMIPS();
case WebAssembly:
return T.isWasm();
case XL:
return T.isOSAIX();
case GenericItanium:
return true;
case Microsoft:
return T.isKnownWindowsMSVCEnvironment();
}
llvm_unreachable("invalid CXXABI kind");
};
/// Does this ABI generally fall into the Itanium family of ABIs?
bool isItaniumFamily() const {
switch (getKind()) {
#define CXXABI(Name, Str)
#define ITANIUM_CXXABI(Name, Str) case Name:
#include "TargetCXXABI.def"
return true;
default:
return false;
}
llvm_unreachable("bad ABI kind");
}
/// Is this ABI an MSVC-compatible ABI?
bool isMicrosoft() const {
switch (getKind()) {
#define CXXABI(Name, Str)
#define MICROSOFT_CXXABI(Name, Str) case Name:
#include "TargetCXXABI.def"
return true;
default:
return false;
}
llvm_unreachable("bad ABI kind");
}
/// Are member functions differently aligned?
///
/// Many Itanium-style C++ ABIs require member functions to be aligned, so
/// that a pointer to such a function is guaranteed to have a zero in the
/// least significant bit, so that pointers to member functions can use that
/// bit to distinguish between virtual and non-virtual functions. However,
/// some Itanium-style C++ ABIs differentiate between virtual and non-virtual
/// functions via other means, and consequently don't require that member
/// functions be aligned.
bool areMemberFunctionsAligned() const {
switch (getKind()) {
case WebAssembly:
// WebAssembly doesn't require any special alignment for member functions.
return false;
case AppleARM64:
case Fuchsia:
case GenericARM:
case GenericAArch64:
case GenericMIPS:
// TODO: ARM-style pointers to member functions put the discriminator in
// the this adjustment, so they don't require functions to have any
// special alignment and could therefore also return false.
case GenericItanium:
case iOS:
case WatchOS:
case Microsoft:
case XL:
return true;
}
llvm_unreachable("bad ABI kind");
}
/// Are arguments to a call destroyed left to right in the callee?
/// This is a fundamental language change, since it implies that objects
/// passed by value do *not* live to the end of the full expression.
/// Temporaries passed to a function taking a const reference live to the end
/// of the full expression as usual. Both the caller and the callee must
/// have access to the destructor, while only the caller needs the
/// destructor if this is false.
bool areArgsDestroyedLeftToRightInCallee() const {
return isMicrosoft();
}
/// Does this ABI have different entrypoints for complete-object
/// and base-subobject constructors?
bool hasConstructorVariants() const {
return isItaniumFamily();
}
/// Does this ABI allow virtual bases to be primary base classes?
bool hasPrimaryVBases() const {
return isItaniumFamily();
}
/// Does this ABI use key functions? If so, class data such as the
/// vtable is emitted with strong linkage by the TU containing the key
/// function.
bool hasKeyFunctions() const {
return isItaniumFamily();
}
/// Can an out-of-line inline function serve as a key function?
///
/// This flag is only useful in ABIs where type data (for example,
/// vtables and type_info objects) are emitted only after processing
/// the definition of a special "key" virtual function. (This is safe
/// because the ODR requires that every virtual function be defined
/// somewhere in a program.) This usually permits such data to be
/// emitted in only a single object file, as opposed to redundantly
/// in every object file that requires it.
///
/// One simple and common definition of "key function" is the first
/// virtual function in the class definition which is not defined there.
/// This rule works very well when that function has a non-inline
/// definition in some non-header file. Unfortunately, when that
/// function is defined inline, this rule requires the type data
/// to be emitted weakly, as if there were no key function.
///
/// The ARM ABI observes that the ODR provides an additional guarantee:
/// a virtual function is always ODR-used, so if it is defined inline,
/// that definition must appear in every translation unit that defines
/// the class. Therefore, there is no reason to allow such functions
/// to serve as key functions.
///
/// Because this changes the rules for emitting type data,
/// it can cause type data to be emitted with both weak and strong
/// linkage, which is not allowed on all platforms. Therefore,
/// exploiting this observation requires an ABI break and cannot be
/// done on a generic Itanium platform.
bool canKeyFunctionBeInline() const {
switch (getKind()) {
case AppleARM64:
case Fuchsia:
case GenericARM:
case WebAssembly:
case WatchOS:
return false;
case GenericAArch64:
case GenericItanium:
case iOS: // old iOS compilers did not follow this rule
case Microsoft:
case GenericMIPS:
case XL:
return true;
}
llvm_unreachable("bad ABI kind");
}
/// When is record layout allowed to allocate objects in the tail
/// padding of a base class?
///
/// This decision cannot be changed without breaking platform ABI
/// compatibility. In ISO C++98, tail padding reuse was only permitted for
/// non-POD base classes, but that restriction was removed retroactively by
/// DR 43, and tail padding reuse is always permitted in all de facto C++
/// language modes. However, many platforms use a variant of the old C++98
/// rule for compatibility.
enum TailPaddingUseRules {
/// The tail-padding of a base class is always theoretically
/// available, even if it's POD.
AlwaysUseTailPadding,
/// Only allocate objects in the tail padding of a base class if
/// the base class is not POD according to the rules of C++ TR1.
UseTailPaddingUnlessPOD03,
/// Only allocate objects in the tail padding of a base class if
/// the base class is not POD according to the rules of C++11.
UseTailPaddingUnlessPOD11
};
TailPaddingUseRules getTailPaddingUseRules() const {
switch (getKind()) {
// To preserve binary compatibility, the generic Itanium ABI has
// permanently locked the definition of POD to the rules of C++ TR1,
// and that trickles down to derived ABIs.
case GenericItanium:
case GenericAArch64:
case GenericARM:
case iOS:
case GenericMIPS:
case XL:
return UseTailPaddingUnlessPOD03;
// AppleARM64 and WebAssembly use the C++11 POD rules. They do not honor
// the Itanium exception about classes with over-large bitfields.
case AppleARM64:
case Fuchsia:
case WebAssembly:
case WatchOS:
return UseTailPaddingUnlessPOD11;
// MSVC always allocates fields in the tail-padding of a base class
// subobject, even if they're POD.
case Microsoft:
return AlwaysUseTailPadding;
}
llvm_unreachable("bad ABI kind");
}
friend bool operator==(const TargetCXXABI &left, const TargetCXXABI &right) {
return left.getKind() == right.getKind();
}
friend bool operator!=(const TargetCXXABI &left, const TargetCXXABI &right) {
return !(left == right);
}
};
} // end namespace clang
#endif
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
|