1//===--- Builtins.cpp - Builtin function implementation -------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements various things for builtin functions.
10//
11//===----------------------------------------------------------------------===//
12
13#include "clang/Basic/Builtins.h"
14#include "BuiltinTargetFeatures.h"
15#include "clang/Basic/IdentifierTable.h"
16#include "clang/Basic/LangOptions.h"
17#include "clang/Basic/TargetInfo.h"
18#include "llvm/ADT/StringRef.h"
19using namespace clang;
20
21const char *HeaderDesc::getName() const {
22 switch (ID) {
23#define HEADER(ID, NAME) \
24 case ID: \
25 return NAME;
26#include "clang/Basic/BuiltinHeaders.def"
27#undef HEADER
28 };
29 llvm_unreachable("Unknown HeaderDesc::HeaderID enum");
30}
31
32static constexpr unsigned NumBuiltins = Builtin::FirstTSBuiltin;
33
34#define GET_BUILTIN_STR_TABLE
35#include "clang/Basic/Builtins.inc"
36#undef GET_BUILTIN_STR_TABLE
37
38static constexpr Builtin::Info BuiltinInfos[] = {
39 Builtin::Info{}, // No-builtin info entry.
40#define GET_BUILTIN_INFOS
41#include "clang/Basic/Builtins.inc"
42#undef GET_BUILTIN_INFOS
43};
44static_assert(std::size(BuiltinInfos) == NumBuiltins);
45
46std::pair<const Builtin::InfosShard &, const Builtin::Info &>
47Builtin::Context::getShardAndInfo(unsigned ID) const {
48 assert((ID < (Builtin::FirstTSBuiltin + NumTargetBuiltins +
49 NumAuxTargetBuiltins)) &&
50 "Invalid builtin ID!");
51
52 ArrayRef<InfosShard> Shards = BuiltinShards;
53 if (isAuxBuiltinID(ID)) {
54 Shards = AuxTargetShards;
55 ID = getAuxBuiltinID(ID) - Builtin::FirstTSBuiltin;
56 } else if (ID >= Builtin::FirstTSBuiltin) {
57 Shards = TargetShards;
58 ID -= Builtin::FirstTSBuiltin;
59 }
60
61 // Loop over the shards to find the one matching this ID. We don't expect to
62 // have many shards and so its better to search linearly than with a binary
63 // search.
64 for (const auto &Shard : Shards) {
65 if (ID < Shard.Infos.size()) {
66 return {Shard, Shard.Infos[ID]};
67 }
68
69 ID -= Shard.Infos.size();
70 }
71 llvm_unreachable("Invalid target builtin shard structure!");
72}
73
74std::string Builtin::Info::getName(const Builtin::InfosShard &Shard) const {
75 return (Twine(Shard.NamePrefix) + (*Shard.Strings)[Offsets.Name]).str();
76}
77
78/// Return the identifier name for the specified builtin,
79/// e.g. "__builtin_abs".
80std::string Builtin::Context::getName(unsigned ID) const {
81 const auto &[Shard, I] = getShardAndInfo(ID);
82 return I.getName(Shard);
83}
84
85std::string Builtin::Context::getQuotedName(unsigned ID) const {
86 const auto &[Shard, I] = getShardAndInfo(ID);
87 return (Twine("'") + Shard.NamePrefix + (*Shard.Strings)[I.Offsets.Name] +
88 "'")
89 .str();
90}
91
92const char *Builtin::Context::getTypeString(unsigned ID) const {
93 const auto &[Shard, I] = getShardAndInfo(ID);
94 return (*Shard.Strings)[I.Offsets.Type].data();
95}
96
97const char *Builtin::Context::getAttributesString(unsigned ID) const {
98 const auto &[Shard, I] = getShardAndInfo(ID);
99 return (*Shard.Strings)[I.Offsets.Attributes].data();
100}
101
102const char *Builtin::Context::getRequiredFeatures(unsigned ID) const {
103 const auto &[Shard, I] = getShardAndInfo(ID);
104 return (*Shard.Strings)[I.Offsets.Features].data();
105}
106
107Builtin::Context::Context() : BuiltinShards{{&BuiltinStrings, BuiltinInfos}} {}
108
109void Builtin::Context::InitializeTarget(const TargetInfo &Target,
110 const TargetInfo *AuxTarget) {
111 assert(TargetShards.empty() && "Already initialized target?");
112 assert(NumTargetBuiltins == 0 && "Already initialized target?");
113 TargetShards = Target.getTargetBuiltins();
114 for (const auto &Shard : TargetShards)
115 NumTargetBuiltins += Shard.Infos.size();
116 if (AuxTarget) {
117 AuxTargetShards = AuxTarget->getTargetBuiltins();
118 for (const auto &Shard : AuxTargetShards)
119 NumAuxTargetBuiltins += Shard.Infos.size();
120 }
121}
122
123bool Builtin::Context::isBuiltinFunc(llvm::StringRef FuncName) {
124 bool InStdNamespace = FuncName.consume_front(Prefix: "std-");
125 for (const auto &Shard : {InfosShard{&BuiltinStrings, BuiltinInfos}})
126 if (llvm::StringRef FuncNameSuffix = FuncName;
127 FuncNameSuffix.consume_front(Shard.NamePrefix))
128 for (const auto &I : Shard.Infos)
129 if (FuncNameSuffix == (*Shard.Strings)[I.Offsets.Name] &&
130 (bool)strchr((*Shard.Strings)[I.Offsets.Attributes].data(), 'z') ==
131 InStdNamespace)
132 return strchr((*Shard.Strings)[I.Offsets.Attributes].data(), 'f') !=
133 nullptr;
134
135 return false;
136}
137
138/// Is this builtin supported according to the given language options?
139static bool builtinIsSupported(const llvm::StringTable &Strings,
140 const Builtin::Info &BuiltinInfo,
141 const LangOptions &LangOpts) {
142 auto AttributesStr = Strings[BuiltinInfo.Offsets.Attributes];
143
144 /* Builtins Unsupported */
145 if (LangOpts.NoBuiltin && strchr(s: AttributesStr.data(), c: 'f') != nullptr)
146 return false;
147 /* CorBuiltins Unsupported */
148 if (!LangOpts.Coroutines && (BuiltinInfo.Langs & COR_LANG))
149 return false;
150 /* MathBuiltins Unsupported */
151 if (LangOpts.NoMathBuiltin && BuiltinInfo.Header.ID == HeaderDesc::MATH_H)
152 return false;
153 /* GnuMode Unsupported */
154 if (!LangOpts.GNUMode && (BuiltinInfo.Langs & GNU_LANG))
155 return false;
156 /* MSMode Unsupported */
157 if (!LangOpts.MicrosoftExt && (BuiltinInfo.Langs & MS_LANG))
158 return false;
159 /* HLSLMode Unsupported */
160 if (!LangOpts.HLSL && (BuiltinInfo.Langs & HLSL_LANG))
161 return false;
162 /* ObjC Unsupported */
163 if (!LangOpts.ObjC && BuiltinInfo.Langs == OBJC_LANG)
164 return false;
165 /* OpenCLC Unsupported */
166 if (!LangOpts.OpenCL && (BuiltinInfo.Langs & ALL_OCL_LANGUAGES))
167 return false;
168 /* OopenCL GAS Unsupported */
169 if (!LangOpts.OpenCLGenericAddressSpace && (BuiltinInfo.Langs & OCL_GAS))
170 return false;
171 /* OpenCL Pipe Unsupported */
172 if (!LangOpts.OpenCLPipes && (BuiltinInfo.Langs & OCL_PIPE))
173 return false;
174
175 // Device side enqueue is not supported until OpenCL 2.0. In 2.0 and higher
176 // support is indicated with language option for blocks.
177
178 /* OpenCL DSE Unsupported */
179 if ((LangOpts.getOpenCLCompatibleVersion() < 200 || !LangOpts.Blocks) &&
180 (BuiltinInfo.Langs & OCL_DSE))
181 return false;
182 /* OpenMP Unsupported */
183 if (!LangOpts.OpenMP && BuiltinInfo.Langs == OMP_LANG)
184 return false;
185 /* CUDA Unsupported */
186 if (!LangOpts.CUDA && BuiltinInfo.Langs == CUDA_LANG)
187 return false;
188 /* CPlusPlus Unsupported */
189 if (!LangOpts.CPlusPlus && BuiltinInfo.Langs == CXX_LANG)
190 return false;
191 /* consteval Unsupported */
192 if (!LangOpts.CPlusPlus20 && strchr(s: AttributesStr.data(), c: 'G') != nullptr)
193 return false;
194 /* C23 unsupported */
195 if (!LangOpts.C23 && BuiltinInfo.Langs == C23_LANG)
196 return false;
197 return true;
198}
199
200/// initializeBuiltins - Mark the identifiers for all the builtins with their
201/// appropriate builtin ID # and mark any non-portable builtin identifiers as
202/// such.
203void Builtin::Context::initializeBuiltins(IdentifierTable &Table,
204 const LangOptions &LangOpts) {
205 {
206 unsigned ID = 0;
207 // Step #1: mark all target-independent builtins with their ID's.
208 for (const auto &Shard : BuiltinShards)
209 for (const auto &I : Shard.Infos) {
210 // If this is a real builtin (ID != 0) and is supported, add it.
211 if (ID != 0 && builtinIsSupported(*Shard.Strings, I, LangOpts))
212 Table.get(I.getName(Shard)).setBuiltinID(ID);
213 ++ID;
214 }
215 assert(ID == FirstTSBuiltin && "Should have added all non-target IDs!");
216
217 // Step #2: Register target-specific builtins.
218 for (const auto &Shard : TargetShards)
219 for (const auto &I : Shard.Infos) {
220 if (builtinIsSupported(*Shard.Strings, I, LangOpts))
221 Table.get(I.getName(Shard)).setBuiltinID(ID);
222 ++ID;
223 }
224
225 // Step #3: Register target-specific builtins for AuxTarget.
226 for (const auto &Shard : AuxTargetShards)
227 for (const auto &I : Shard.Infos) {
228 Table.get(I.getName(Shard)).setBuiltinID(ID);
229 ++ID;
230 }
231 }
232
233 // Step #4: Unregister any builtins specified by -fno-builtin-foo.
234 for (llvm::StringRef Name : LangOpts.NoBuiltinFuncs) {
235 bool InStdNamespace = Name.consume_front(Prefix: "std-");
236 auto NameIt = Table.find(Name);
237 if (NameIt != Table.end()) {
238 unsigned ID = NameIt->second->getBuiltinID();
239 if (ID != Builtin::NotBuiltin && isPredefinedLibFunction(ID) &&
240 isInStdNamespace(ID) == InStdNamespace) {
241 NameIt->second->clearBuiltinID();
242 }
243 }
244 }
245}
246
247unsigned Builtin::Context::getRequiredVectorWidth(unsigned ID) const {
248 const char *WidthPos = ::strchr(s: getAttributesString(ID), c: 'V');
249 if (!WidthPos)
250 return 0;
251
252 ++WidthPos;
253 assert(*WidthPos == ':' &&
254 "Vector width specifier must be followed by a ':'");
255 ++WidthPos;
256
257 char *EndPos;
258 unsigned Width = ::strtol(nptr: WidthPos, endptr: &EndPos, base: 10);
259 assert(*EndPos == ':' && "Vector width specific must end with a ':'");
260 return Width;
261}
262
263bool Builtin::Context::isLike(unsigned ID, unsigned &FormatIdx,
264 bool &HasVAListArg, const char *Fmt) const {
265 assert(Fmt && "Not passed a format string");
266 assert(::strlen(Fmt) == 2 &&
267 "Format string needs to be two characters long");
268 assert(::toupper(Fmt[0]) == Fmt[1] &&
269 "Format string is not in the form \"xX\"");
270
271 const char *Like = ::strpbrk(s: getAttributesString(ID), accept: Fmt);
272 if (!Like)
273 return false;
274
275 HasVAListArg = (*Like == Fmt[1]);
276
277 ++Like;
278 assert(*Like == ':' && "Format specifier must be followed by a ':'");
279 ++Like;
280
281 assert(::strchr(Like, ':') && "Format specifier must end with a ':'");
282 FormatIdx = ::strtol(nptr: Like, endptr: nullptr, base: 10);
283 return true;
284}
285
286bool Builtin::Context::isPrintfLike(unsigned ID, unsigned &FormatIdx,
287 bool &HasVAListArg) {
288 return isLike(ID, FormatIdx, HasVAListArg, Fmt: "pP");
289}
290
291bool Builtin::Context::isScanfLike(unsigned ID, unsigned &FormatIdx,
292 bool &HasVAListArg) {
293 return isLike(ID, FormatIdx, HasVAListArg, Fmt: "sS");
294}
295
296bool Builtin::Context::performsCallback(unsigned ID,
297 SmallVectorImpl<int> &Encoding) const {
298 const char *CalleePos = ::strchr(s: getAttributesString(ID), c: 'C');
299 if (!CalleePos)
300 return false;
301
302 ++CalleePos;
303 assert(*CalleePos == '<' &&
304 "Callback callee specifier must be followed by a '<'");
305 ++CalleePos;
306
307 char *EndPos;
308 int CalleeIdx = ::strtol(nptr: CalleePos, endptr: &EndPos, base: 10);
309 assert(CalleeIdx >= 0 && "Callee index is supposed to be positive!");
310 Encoding.push_back(Elt: CalleeIdx);
311
312 while (*EndPos == ',') {
313 const char *PayloadPos = EndPos + 1;
314
315 int PayloadIdx = ::strtol(nptr: PayloadPos, endptr: &EndPos, base: 10);
316 Encoding.push_back(Elt: PayloadIdx);
317 }
318
319 assert(*EndPos == '>' && "Callback callee specifier must end with a '>'");
320 return true;
321}
322
323bool Builtin::Context::canBeRedeclared(unsigned ID) const {
324 return ID == Builtin::NotBuiltin || ID == Builtin::BI__va_start ||
325 ID == Builtin::BI__builtin_assume_aligned ||
326 (!hasReferenceArgsOrResult(ID) && !hasCustomTypechecking(ID)) ||
327 isInStdNamespace(ID);
328}
329
330bool Builtin::evaluateRequiredTargetFeatures(
331 StringRef RequiredFeatures, const llvm::StringMap<bool> &TargetFetureMap) {
332 // Return true if the builtin doesn't have any required features.
333 if (RequiredFeatures.empty())
334 return true;
335 assert(!RequiredFeatures.contains(' ') && "Space in feature list");
336
337 TargetFeatures TF(TargetFetureMap);
338 return TF.hasRequiredFeatures(FeatureList: RequiredFeatures);
339}
340

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of clang/lib/Basic/Builtins.cpp