18
18
#include " llvm/ADT/ArrayRef.h"
19
19
#include " llvm/ADT/StringMap.h"
20
20
#include " llvm/ADT/StringRef.h"
21
+ #include " llvm/ADT/StringTable.h"
21
22
#include < cstring>
22
23
23
24
// VC++ defines 'alloca' as an object-like macro, which interferes with our
@@ -55,6 +56,7 @@ struct HeaderDesc {
55
56
#undef HEADER
56
57
} ID;
57
58
59
+ constexpr HeaderDesc () : ID() {}
58
60
constexpr HeaderDesc (HeaderID ID) : ID(ID) {}
59
61
60
62
const char *getName () const ;
@@ -68,23 +70,144 @@ enum ID {
68
70
FirstTSBuiltin
69
71
};
70
72
73
+ // The info used to represent each builtin.
71
74
struct Info {
72
- llvm::StringLiteral Name;
73
- const char *Type, *Attributes;
74
- const char *Features;
75
+ // Rather than store pointers to the string literals describing these four
76
+ // aspects of builtins, we store offsets into a common string table.
77
+ struct StrOffsets {
78
+ llvm::StringTable::Offset Name;
79
+ llvm::StringTable::Offset Type;
80
+ llvm::StringTable::Offset Attributes;
81
+ llvm::StringTable::Offset Features;
82
+ } Offsets;
83
+
75
84
HeaderDesc Header;
76
85
LanguageID Langs;
77
86
};
78
87
88
+ // A constexpr function to construct an infos array from X-macros.
89
+ //
90
+ // The input array uses the same data structure, but the offsets are actually
91
+ // _lengths_ when input. This is all we can compute from the X-macro approach to
92
+ // builtins. This function will convert these lengths into actual offsets to a
93
+ // string table built up through sequentially appending strings with the given
94
+ // lengths.
95
+ template <size_t N>
96
+ static constexpr std::array<Info, N> MakeInfos (std::array<Info, N> Infos) {
97
+ // Translate lengths to offsets. We start past the initial empty string at
98
+ // offset zero.
99
+ unsigned Offset = 1 ;
100
+ for (Info &I : Infos) {
101
+ Info::StrOffsets NewOffsets = {};
102
+ NewOffsets.Name = Offset;
103
+ Offset += I.Offsets .Name .value ();
104
+ NewOffsets.Type = Offset;
105
+ Offset += I.Offsets .Type .value ();
106
+ NewOffsets.Attributes = Offset;
107
+ Offset += I.Offsets .Attributes .value ();
108
+ NewOffsets.Features = Offset;
109
+ Offset += I.Offsets .Features .value ();
110
+ I.Offsets = NewOffsets;
111
+ }
112
+ return Infos;
113
+ }
114
+
115
+ // A detail macro used below to emit a string literal that, after string literal
116
+ // concatenation, ends up triggering the `-Woverlength-strings` warning. While
117
+ // the warning is useful in general to catch accidentally excessive strings,
118
+ // here we are creating them intentionally.
119
+ //
120
+ // This relies on a subtle aspect of `_Pragma`: that the *diagnostic* ones don't
121
+ // turn into actual tokens that would disrupt string literal concatenation.
122
+ #ifdef __clang__
123
+ #define CLANG_BUILTIN_DETAIL_STR_TABLE (S ) \
124
+ _Pragma (" clang diagnostic push" ) \
125
+ _Pragma(" clang diagnostic ignored \" -Woverlength-strings\" " ) \
126
+ S _Pragma(" clang diagnostic pop" )
127
+ #else
128
+ #define CLANG_BUILTIN_DETAIL_STR_TABLE (S ) S
129
+ #endif
130
+
131
+ // We require string tables to start with an empty string so that a `0` offset
132
+ // can always be used to refer to an empty string. To satisfy that when building
133
+ // string tables with X-macros, we use this start macro prior to expanding the
134
+ // X-macros.
135
+ #define CLANG_BUILTIN_STR_TABLE_START CLANG_BUILTIN_DETAIL_STR_TABLE (" \0 " )
136
+
137
+ // A macro that can be used with `Builtins.def` and similar files as an X-macro
138
+ // to add the string arguments to a builtin string table. This is typically the
139
+ // target for the `BUILTIN`, `LANGBUILTIN`, or `LIBBUILTIN` macros in those
140
+ // files.
141
+ #define CLANG_BUILTIN_STR_TABLE (ID, TYPE, ATTRS ) \
142
+ CLANG_BUILTIN_DETAIL_STR_TABLE (#ID " \0 " TYPE " \0 " ATTRS " \0 " /* FEATURE*/ " \0 " )
143
+
144
+ // A macro that can be used with target builtin `.def` and `.inc` files as an
145
+ // X-macro to add the string arguments to a builtin string table. this is
146
+ // typically the target for the `TARGET_BUILTIN` macro.
147
+ #define CLANG_TARGET_BUILTIN_STR_TABLE (ID, TYPE, ATTRS, FEATURE ) \
148
+ CLANG_BUILTIN_DETAIL_STR_TABLE (#ID " \0 " TYPE " \0 " ATTRS " \0 " FEATURE " \0 " )
149
+
150
+ // A macro that can be used with target builtin `.def` and `.inc` files as an
151
+ // X-macro to add the string arguments to a builtin string table. this is
152
+ // typically the target for the `TARGET_HEADER_BUILTIN` macro. We can't delegate
153
+ // to `TARGET_BUILTIN` because the `FEATURE` string changes position.
154
+ #define CLANG_TARGET_HEADER_BUILTIN_STR_TABLE (ID, TYPE, ATTRS, HEADER, LANGS, \
155
+ FEATURE) \
156
+ CLANG_BUILTIN_DETAIL_STR_TABLE (#ID " \0 " TYPE " \0 " ATTRS " \0 " FEATURE " \0 " )
157
+
158
+ // A detail macro used internally to compute the desired string table
159
+ // `StrOffsets` struct for arguments to `MakeInfos`.
160
+ #define CLANG_BUILTIN_DETAIL_STR_OFFSETS (ID, TYPE, ATTRS ) \
161
+ Builtin::Info::StrOffsets { \
162
+ sizeof (#ID), sizeof (TYPE), sizeof (ATTRS), sizeof (" " ) \
163
+ }
164
+
165
+ // A detail macro used internally to compute the desired string table
166
+ // `StrOffsets` struct for arguments to `Storage::Make`.
167
+ #define CLANG_TARGET_BUILTIN_DETAIL_STR_OFFSETS (ID, TYPE, ATTRS, FEATURE ) \
168
+ Builtin::Info::StrOffsets { \
169
+ sizeof (#ID), sizeof (TYPE), sizeof (ATTRS), sizeof (FEATURE) \
170
+ }
171
+
172
+ // A set of macros that can be used with builtin `.def' files as an X-macro to
173
+ // create an `Info` struct for a particular builtin. It both computes the
174
+ // `StrOffsets` value for the string table (the lengths here, translated to
175
+ // offsets by the `MakeInfos` function), and the other metadata for each
176
+ // builtin.
177
+ //
178
+ // There is a corresponding macro for each of `BUILTIN`, `LANGBUILTIN`,
179
+ // `LIBBUILTIN`, `TARGET_BUILTIN`, and `TARGET_HEADER_BUILTIN`.
180
+ #define CLANG_BUILTIN_ENTRY (ID, TYPE, ATTRS ) \
181
+ Builtin::Info{CLANG_BUILTIN_DETAIL_STR_OFFSETS (ID, TYPE, ATTRS), \
182
+ HeaderDesc::NO_HEADER, ALL_LANGUAGES},
183
+ #define CLANG_LANGBUILTIN_ENTRY (ID, TYPE, ATTRS, LANG ) \
184
+ Builtin::Info{CLANG_BUILTIN_DETAIL_STR_OFFSETS (ID, TYPE, ATTRS), \
185
+ HeaderDesc::NO_HEADER, LANG},
186
+ #define CLANG_LIBBUILTIN_ENTRY (ID, TYPE, ATTRS, HEADER, LANG ) \
187
+ Builtin::Info{CLANG_BUILTIN_DETAIL_STR_OFFSETS (ID, TYPE, ATTRS), \
188
+ HeaderDesc::HEADER, LANG},
189
+ #define CLANG_TARGET_BUILTIN_ENTRY (ID, TYPE, ATTRS, FEATURE ) \
190
+ Builtin::Info{ \
191
+ CLANG_TARGET_BUILTIN_DETAIL_STR_OFFSETS (ID, TYPE, ATTRS, FEATURE), \
192
+ HeaderDesc::NO_HEADER, ALL_LANGUAGES},
193
+ #define CLANG_TARGET_HEADER_BUILTIN_ENTRY (ID, TYPE, ATTRS, HEADER, LANG, \
194
+ FEATURE) \
195
+ Builtin::Info{ \
196
+ CLANG_TARGET_BUILTIN_DETAIL_STR_OFFSETS (ID, TYPE, ATTRS, FEATURE), \
197
+ HeaderDesc::HEADER, LANG},
198
+
79
199
// / Holds information about both target-independent and
80
200
// / target-specific builtins, allowing easy queries by clients.
81
201
// /
82
202
// / Builtins from an optional auxiliary target are stored in
83
203
// / AuxTSRecords. Their IDs are shifted up by TSRecords.size() and need to
84
204
// / be translated back with getAuxBuiltinID() before use.
85
205
class Context {
86
- llvm::ArrayRef<Info> TSRecords;
87
- llvm::ArrayRef<Info> AuxTSRecords;
206
+ const llvm::StringTable *TSStrTable = nullptr ;
207
+ const llvm::StringTable *AuxTSStrTable = nullptr ;
208
+
209
+ llvm::ArrayRef<Info> TSInfos;
210
+ llvm::ArrayRef<Info> AuxTSInfos;
88
211
89
212
public:
90
213
Context () = default ;
@@ -100,13 +223,16 @@ class Context {
100
223
101
224
// / Return the identifier name for the specified builtin,
102
225
// / e.g. "__builtin_abs".
103
- llvm::StringRef getName (unsigned ID) const { return getRecord (ID). Name ; }
226
+ llvm::StringRef getName (unsigned ID) const ;
104
227
105
228
// / Return a quoted name for the specified builtin for use in diagnostics.
106
229
std::string getQuotedName (unsigned ID) const ;
107
230
108
231
// / Get the type descriptor string for the specified builtin.
109
- const char *getTypeString (unsigned ID) const { return getRecord (ID).Type ; }
232
+ const char *getTypeString (unsigned ID) const ;
233
+
234
+ // / Get the attributes descriptor string for the specified builtin.
235
+ const char *getAttributesString (unsigned ID) const ;
110
236
111
237
// / Return true if this function is a target-specific builtin.
112
238
bool isTSBuiltin (unsigned ID) const {
@@ -115,40 +241,40 @@ class Context {
115
241
116
242
// / Return true if this function has no side effects.
117
243
bool isPure (unsigned ID) const {
118
- return strchr (getRecord (ID). Attributes , ' U' ) != nullptr ;
244
+ return strchr (getAttributesString (ID), ' U' ) != nullptr ;
119
245
}
120
246
121
247
// / Return true if this function has no side effects and doesn't
122
248
// / read memory.
123
249
bool isConst (unsigned ID) const {
124
- return strchr (getRecord (ID). Attributes , ' c' ) != nullptr ;
250
+ return strchr (getAttributesString (ID), ' c' ) != nullptr ;
125
251
}
126
252
127
253
// / Return true if we know this builtin never throws an exception.
128
254
bool isNoThrow (unsigned ID) const {
129
- return strchr (getRecord (ID). Attributes , ' n' ) != nullptr ;
255
+ return strchr (getAttributesString (ID), ' n' ) != nullptr ;
130
256
}
131
257
132
258
// / Return true if we know this builtin never returns.
133
259
bool isNoReturn (unsigned ID) const {
134
- return strchr (getRecord (ID). Attributes , ' r' ) != nullptr ;
260
+ return strchr (getAttributesString (ID), ' r' ) != nullptr ;
135
261
}
136
262
137
263
// / Return true if we know this builtin can return twice.
138
264
bool isReturnsTwice (unsigned ID) const {
139
- return strchr (getRecord (ID). Attributes , ' j' ) != nullptr ;
265
+ return strchr (getAttributesString (ID), ' j' ) != nullptr ;
140
266
}
141
267
142
268
// / Returns true if this builtin does not perform the side-effects
143
269
// / of its arguments.
144
270
bool isUnevaluated (unsigned ID) const {
145
- return strchr (getRecord (ID). Attributes , ' u' ) != nullptr ;
271
+ return strchr (getAttributesString (ID), ' u' ) != nullptr ;
146
272
}
147
273
148
274
// / Return true if this is a builtin for a libc/libm function,
149
275
// / with a "__builtin_" prefix (e.g. __builtin_abs).
150
276
bool isLibFunction (unsigned ID) const {
151
- return strchr (getRecord (ID). Attributes , ' F' ) != nullptr ;
277
+ return strchr (getAttributesString (ID), ' F' ) != nullptr ;
152
278
}
153
279
154
280
// / Determines whether this builtin is a predefined libc/libm
@@ -159,29 +285,29 @@ class Context {
159
285
// / they do not, but they are recognized as builtins once we see
160
286
// / a declaration.
161
287
bool isPredefinedLibFunction (unsigned ID) const {
162
- return strchr (getRecord (ID). Attributes , ' f' ) != nullptr ;
288
+ return strchr (getAttributesString (ID), ' f' ) != nullptr ;
163
289
}
164
290
165
291
// / Returns true if this builtin requires appropriate header in other
166
292
// / compilers. In Clang it will work even without including it, but we can emit
167
293
// / a warning about missing header.
168
294
bool isHeaderDependentFunction (unsigned ID) const {
169
- return strchr (getRecord (ID). Attributes , ' h' ) != nullptr ;
295
+ return strchr (getAttributesString (ID), ' h' ) != nullptr ;
170
296
}
171
297
172
298
// / Determines whether this builtin is a predefined compiler-rt/libgcc
173
299
// / function, such as "__clear_cache", where we know the signature a
174
300
// / priori.
175
301
bool isPredefinedRuntimeFunction (unsigned ID) const {
176
- return strchr (getRecord (ID). Attributes , ' i' ) != nullptr ;
302
+ return strchr (getAttributesString (ID), ' i' ) != nullptr ;
177
303
}
178
304
179
305
// / Determines whether this builtin is a C++ standard library function
180
306
// / that lives in (possibly-versioned) namespace std, possibly a template
181
307
// / specialization, where the signature is determined by the standard library
182
308
// / declaration.
183
309
bool isInStdNamespace (unsigned ID) const {
184
- return strchr (getRecord (ID). Attributes , ' z' ) != nullptr ;
310
+ return strchr (getAttributesString (ID), ' z' ) != nullptr ;
185
311
}
186
312
187
313
// / Determines whether this builtin can have its address taken with no
@@ -195,33 +321,33 @@ class Context {
195
321
196
322
// / Determines whether this builtin has custom typechecking.
197
323
bool hasCustomTypechecking (unsigned ID) const {
198
- return strchr (getRecord (ID). Attributes , ' t' ) != nullptr ;
324
+ return strchr (getAttributesString (ID), ' t' ) != nullptr ;
199
325
}
200
326
201
327
// / Determines whether a declaration of this builtin should be recognized
202
328
// / even if the type doesn't match the specified signature.
203
329
bool allowTypeMismatch (unsigned ID) const {
204
- return strchr (getRecord (ID). Attributes , ' T' ) != nullptr ||
330
+ return strchr (getAttributesString (ID), ' T' ) != nullptr ||
205
331
hasCustomTypechecking (ID);
206
332
}
207
333
208
334
// / Determines whether this builtin has a result or any arguments which
209
335
// / are pointer types.
210
336
bool hasPtrArgsOrResult (unsigned ID) const {
211
- return strchr (getRecord (ID). Type , ' *' ) != nullptr ;
337
+ return strchr (getTypeString (ID), ' *' ) != nullptr ;
212
338
}
213
339
214
340
// / Return true if this builtin has a result or any arguments which are
215
341
// / reference types.
216
342
bool hasReferenceArgsOrResult (unsigned ID) const {
217
- return strchr (getRecord (ID). Type , ' &' ) != nullptr ||
218
- strchr (getRecord (ID). Type , ' A' ) != nullptr ;
343
+ return strchr (getTypeString (ID), ' &' ) != nullptr ||
344
+ strchr (getTypeString (ID), ' A' ) != nullptr ;
219
345
}
220
346
221
347
// / If this is a library function that comes from a specific
222
348
// / header, retrieve that header name.
223
349
const char *getHeaderName (unsigned ID) const {
224
- return getRecord (ID).Header .getName ();
350
+ return getInfo (ID).Header .getName ();
225
351
}
226
352
227
353
// / Determine whether this builtin is like printf in its
@@ -246,27 +372,25 @@ class Context {
246
372
// / Such functions can be const when the MathErrno lang option and FP
247
373
// / exceptions are disabled.
248
374
bool isConstWithoutErrnoAndExceptions (unsigned ID) const {
249
- return strchr (getRecord (ID). Attributes , ' e' ) != nullptr ;
375
+ return strchr (getAttributesString (ID), ' e' ) != nullptr ;
250
376
}
251
377
252
378
bool isConstWithoutExceptions (unsigned ID) const {
253
- return strchr (getRecord (ID). Attributes , ' g' ) != nullptr ;
379
+ return strchr (getAttributesString (ID), ' g' ) != nullptr ;
254
380
}
255
381
256
- const char *getRequiredFeatures (unsigned ID) const {
257
- return getRecord (ID).Features ;
258
- }
382
+ const char *getRequiredFeatures (unsigned ID) const ;
259
383
260
384
unsigned getRequiredVectorWidth (unsigned ID) const ;
261
385
262
386
// / Return true if builtin ID belongs to AuxTarget.
263
387
bool isAuxBuiltinID (unsigned ID) const {
264
- return ID >= (Builtin::FirstTSBuiltin + TSRecords .size ());
388
+ return ID >= (Builtin::FirstTSBuiltin + TSInfos .size ());
265
389
}
266
390
267
391
// / Return real builtin ID (i.e. ID it would have during compilation
268
392
// / for AuxTarget).
269
- unsigned getAuxBuiltinID (unsigned ID) const { return ID - TSRecords .size (); }
393
+ unsigned getAuxBuiltinID (unsigned ID) const { return ID - TSInfos .size (); }
270
394
271
395
// / Returns true if this is a libc/libm function without the '__builtin_'
272
396
// / prefix.
@@ -278,16 +402,21 @@ class Context {
278
402
279
403
// / Return true if this function can be constant evaluated by Clang frontend.
280
404
bool isConstantEvaluated (unsigned ID) const {
281
- return strchr (getRecord (ID). Attributes , ' E' ) != nullptr ;
405
+ return strchr (getAttributesString (ID), ' E' ) != nullptr ;
282
406
}
283
407
284
408
// / Returns true if this is an immediate (consteval) function
285
409
bool isImmediate (unsigned ID) const {
286
- return strchr (getRecord (ID). Attributes , ' G' ) != nullptr ;
410
+ return strchr (getAttributesString (ID), ' G' ) != nullptr ;
287
411
}
288
412
289
413
private:
290
- const Info &getRecord (unsigned ID) const ;
414
+ std::pair<const llvm::StringTable &, const Info &>
415
+ getStrTableAndInfo (unsigned ID) const ;
416
+
417
+ const Info &getInfo (unsigned ID) const {
418
+ return getStrTableAndInfo (ID).second ;
419
+ }
291
420
292
421
// / Helper function for isPrintfLike and isScanfLike.
293
422
bool isLike (unsigned ID, unsigned &FormatIdx, bool &HasVAListArg,
0 commit comments