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
|
//===--- TargetCXXABI.h - C++ ABI Target Configuration ----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief Defines the TargetCXXABI class, which abstracts details of the
/// C++ ABI that we're targeting.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_TARGETCXXABI_H
#define LLVM_CLANG_TARGETCXXABI_H
#include "llvm/ADT/Triple.h"
#include "llvm/Support/ErrorHandling.h"
namespace clang {
/// \brief The basic abstraction for the target C++ ABI.
class TargetCXXABI {
public:
/// \brief The basic C++ ABI kind.
enum Kind {
/// The generic Itanium ABI is the standard ABI of most open-source
/// and Unix-like platforms. It is the primary ABI targeted by
/// many compilers, including Clang and GCC.
///
/// It is documented here:
/// http://www.codesourcery.com/public/cxx-abi/
GenericItanium,
/// The generic ARM ABI is a modified version of the Itanium ABI
/// proposed by ARM for use on ARM-based platforms.
///
/// These changes include:
/// - the representation of member function pointers is adjusted
/// to not conflict with the 'thumb' bit of ARM function pointers;
/// - constructors and destructors return 'this';
/// - guard variables are smaller;
/// - inline functions are never key functions;
/// - array cookies have a slightly different layout;
/// - additional convenience functions are specified;
/// - and more!
///
/// It is documented here:
/// http://infocenter.arm.com
/// /help/topic/com.arm.doc.ihi0041c/IHI0041C_cppabi.pdf
GenericARM,
/// The iOS ABI is a partial implementation of the ARM ABI.
/// Several of the features of the ARM ABI were not fully implemented
/// in the compilers that iOS was launched with.
///
/// Essentially, the iOS ABI includes the ARM changes to:
/// - member function pointers,
/// - guard variables,
/// - array cookies, and
/// - constructor/destructor signatures.
iOS,
/// The iOS 64-bit ABI is follows ARM's published 64-bit ABI more
/// closely, but we don't guarantee to follow it perfectly.
///
/// It is documented here:
/// http://infocenter.arm.com
/// /help/topic/com.arm.doc.ihi0059a/IHI0059A_cppabi64.pdf
iOS64,
/// The generic AArch64 ABI is also a modified version of the Itanium ABI,
/// but it has fewer divergences than the 32-bit ARM ABI.
///
/// The relevant changes from the generic ABI in this case are:
/// - representation of member function pointers adjusted as in ARM.
/// - guard variables are smaller.
GenericAArch64,
/// The Microsoft ABI is the ABI used by Microsoft Visual Studio (and
/// compatible compilers).
///
/// FIXME: should this be split into Win32 and Win64 variants?
///
/// Only scattered and incomplete official documentation exists.
Microsoft
};
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;
public:
/// 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; }
/// \brief Does this ABI generally fall into the Itanium family of ABIs?
bool isItaniumFamily() const {
switch (getKind()) {
case GenericAArch64:
case GenericItanium:
case GenericARM:
case iOS:
case iOS64:
return true;
case Microsoft:
return false;
}
llvm_unreachable("bad ABI kind");
}
/// \brief Is this ABI an MSVC-compatible ABI?
bool isMicrosoft() const {
switch (getKind()) {
case GenericAArch64:
case GenericItanium:
case GenericARM:
case iOS:
case iOS64:
return false;
case Microsoft:
return true;
}
llvm_unreachable("bad ABI kind");
}
/// \brief Is the default C++ member function calling convention
/// the same as the default calling convention?
bool isMemberFunctionCCDefault() const {
// Right now, this is always false for Microsoft.
return !isMicrosoft();
}
/// 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();
}
/// \brief Does this ABI have different entrypoints for complete-object
/// and base-subobject constructors?
bool hasConstructorVariants() const {
return isItaniumFamily();
}
/// \brief Does this ABI allow virtual bases to be primary base classes?
bool hasPrimaryVBases() const {
return isItaniumFamily();
}
/// \brief 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();
}
/// \brief Can an out-of-line inline function serve as a key function?
///
/// This flag is only useful in ABIs where type data (for example,
/// v-tables 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 GenericARM:
case iOS64:
return false;
case GenericAArch64:
case GenericItanium:
case iOS: // old iOS compilers did not follow this rule
case Microsoft:
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, and yet it is tied to language guarantees which
/// the committee has so far seen fit to strengthen no less than
/// three separate times:
/// - originally, there were no restrictions at all;
/// - C++98 declared that objects could not be allocated in the
/// tail padding of a POD type;
/// - C++03 extended the definition of POD to include classes
/// containing member pointers; and
/// - C++11 greatly broadened the definition of POD to include
/// all trivial standard-layout classes.
/// Each of these changes technically took several existing
/// platforms and made them permanently non-conformant.
enum TailPaddingUseRules {
/// The tail-padding of a base class is always theoretically
/// available, even if it's POD. This is not strictly conforming
/// in any language mode.
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.
/// This is non-strictly conforming in C++11 mode.
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 all the derived ABIs.
case GenericItanium:
case GenericAArch64:
case GenericARM:
case iOS:
return UseTailPaddingUnlessPOD03;
// iOS on ARM64 uses the C++11 POD rules. It does not honor the
// Itanium exception about classes with over-large bitfields.
case iOS64:
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");
}
/// Try to parse an ABI name, returning false on error.
bool tryParse(llvm::StringRef name);
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
|