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