1 //===--- Builtins.cpp - Builtin function implementation -------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file implements various things for builtin functions.
11 //===----------------------------------------------------------------------===//
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"
19 using namespace clang
;
21 const char *HeaderDesc::getName() const {
23 #define HEADER(ID, NAME) \
26 #include "clang/Basic/BuiltinHeaders.def"
29 llvm_unreachable("Unknown HeaderDesc::HeaderID enum");
32 static constexpr Builtin::Info BuiltinInfo
[] = {
33 {"not a builtin function", nullptr, nullptr, nullptr, HeaderDesc::NO_HEADER
,
35 #define BUILTIN(ID, TYPE, ATTRS) \
36 {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
37 #define LANGBUILTIN(ID, TYPE, ATTRS, LANGS) \
38 {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, LANGS},
39 #define LIBBUILTIN(ID, TYPE, ATTRS, HEADER, LANGS) \
40 {#ID, TYPE, ATTRS, nullptr, HeaderDesc::HEADER, LANGS},
41 #include "clang/Basic/Builtins.inc"
44 const Builtin::Info
&Builtin::Context::getRecord(unsigned ID
) const {
45 if (ID
< Builtin::FirstTSBuiltin
)
46 return BuiltinInfo
[ID
];
47 assert(((ID
- Builtin::FirstTSBuiltin
) <
48 (TSRecords
.size() + AuxTSRecords
.size())) &&
49 "Invalid builtin ID!");
50 if (isAuxBuiltinID(ID
))
51 return AuxTSRecords
[getAuxBuiltinID(ID
) - Builtin::FirstTSBuiltin
];
52 return TSRecords
[ID
- Builtin::FirstTSBuiltin
];
55 void Builtin::Context::InitializeTarget(const TargetInfo
&Target
,
56 const TargetInfo
*AuxTarget
) {
57 assert(TSRecords
.empty() && "Already initialized target?");
58 TSRecords
= Target
.getTargetBuiltins();
60 AuxTSRecords
= AuxTarget
->getTargetBuiltins();
63 bool Builtin::Context::isBuiltinFunc(llvm::StringRef FuncName
) {
64 bool InStdNamespace
= FuncName
.consume_front("std-");
65 for (unsigned i
= Builtin::NotBuiltin
+ 1; i
!= Builtin::FirstTSBuiltin
;
67 if (FuncName
== BuiltinInfo
[i
].Name
&&
68 (bool)strchr(BuiltinInfo
[i
].Attributes
, 'z') == InStdNamespace
)
69 return strchr(BuiltinInfo
[i
].Attributes
, 'f') != nullptr;
75 /// Is this builtin supported according to the given language options?
76 static bool builtinIsSupported(const Builtin::Info
&BuiltinInfo
,
77 const LangOptions
&LangOpts
) {
78 /* Builtins Unsupported */
79 if (LangOpts
.NoBuiltin
&& strchr(BuiltinInfo
.Attributes
, 'f') != nullptr)
81 /* CorBuiltins Unsupported */
82 if (!LangOpts
.Coroutines
&& (BuiltinInfo
.Langs
& COR_LANG
))
84 /* MathBuiltins Unsupported */
85 if (LangOpts
.NoMathBuiltin
&& BuiltinInfo
.Header
.ID
== HeaderDesc::MATH_H
)
87 /* GnuMode Unsupported */
88 if (!LangOpts
.GNUMode
&& (BuiltinInfo
.Langs
& GNU_LANG
))
90 /* MSMode Unsupported */
91 if (!LangOpts
.MicrosoftExt
&& (BuiltinInfo
.Langs
& MS_LANG
))
93 /* HLSLMode Unsupported */
94 if (!LangOpts
.HLSL
&& (BuiltinInfo
.Langs
& HLSL_LANG
))
96 /* ObjC Unsupported */
97 if (!LangOpts
.ObjC
&& BuiltinInfo
.Langs
== OBJC_LANG
)
99 /* OpenCLC Unsupported */
100 if (!LangOpts
.OpenCL
&& (BuiltinInfo
.Langs
& ALL_OCL_LANGUAGES
))
102 /* OopenCL GAS Unsupported */
103 if (!LangOpts
.OpenCLGenericAddressSpace
&& (BuiltinInfo
.Langs
& OCL_GAS
))
105 /* OpenCL Pipe Unsupported */
106 if (!LangOpts
.OpenCLPipes
&& (BuiltinInfo
.Langs
& OCL_PIPE
))
109 // Device side enqueue is not supported until OpenCL 2.0. In 2.0 and higher
110 // support is indicated with language option for blocks.
112 /* OpenCL DSE Unsupported */
113 if ((LangOpts
.getOpenCLCompatibleVersion() < 200 || !LangOpts
.Blocks
) &&
114 (BuiltinInfo
.Langs
& OCL_DSE
))
116 /* OpenMP Unsupported */
117 if (!LangOpts
.OpenMP
&& BuiltinInfo
.Langs
== OMP_LANG
)
119 /* CUDA Unsupported */
120 if (!LangOpts
.CUDA
&& BuiltinInfo
.Langs
== CUDA_LANG
)
122 /* CPlusPlus Unsupported */
123 if (!LangOpts
.CPlusPlus
&& BuiltinInfo
.Langs
== CXX_LANG
)
125 /* consteval Unsupported */
126 if (!LangOpts
.CPlusPlus20
&& strchr(BuiltinInfo
.Attributes
, 'G') != nullptr)
131 /// initializeBuiltins - Mark the identifiers for all the builtins with their
132 /// appropriate builtin ID # and mark any non-portable builtin identifiers as
134 void Builtin::Context::initializeBuiltins(IdentifierTable
&Table
,
135 const LangOptions
& LangOpts
) {
136 // Step #1: mark all target-independent builtins with their ID's.
137 for (unsigned i
= Builtin::NotBuiltin
+1; i
!= Builtin::FirstTSBuiltin
; ++i
)
138 if (builtinIsSupported(BuiltinInfo
[i
], LangOpts
)) {
139 Table
.get(BuiltinInfo
[i
].Name
).setBuiltinID(i
);
142 // Step #2: Register target-specific builtins.
143 for (unsigned i
= 0, e
= TSRecords
.size(); i
!= e
; ++i
)
144 if (builtinIsSupported(TSRecords
[i
], LangOpts
))
145 Table
.get(TSRecords
[i
].Name
).setBuiltinID(i
+ Builtin::FirstTSBuiltin
);
147 // Step #3: Register target-specific builtins for AuxTarget.
148 for (unsigned i
= 0, e
= AuxTSRecords
.size(); i
!= e
; ++i
)
149 Table
.get(AuxTSRecords
[i
].Name
)
150 .setBuiltinID(i
+ Builtin::FirstTSBuiltin
+ TSRecords
.size());
152 // Step #4: Unregister any builtins specified by -fno-builtin-foo.
153 for (llvm::StringRef Name
: LangOpts
.NoBuiltinFuncs
) {
154 bool InStdNamespace
= Name
.consume_front("std-");
155 auto NameIt
= Table
.find(Name
);
156 if (NameIt
!= Table
.end()) {
157 unsigned ID
= NameIt
->second
->getBuiltinID();
158 if (ID
!= Builtin::NotBuiltin
&& isPredefinedLibFunction(ID
) &&
159 isInStdNamespace(ID
) == InStdNamespace
) {
160 NameIt
->second
->clearBuiltinID();
166 unsigned Builtin::Context::getRequiredVectorWidth(unsigned ID
) const {
167 const char *WidthPos
= ::strchr(getRecord(ID
).Attributes
, 'V');
172 assert(*WidthPos
== ':' &&
173 "Vector width specifier must be followed by a ':'");
177 unsigned Width
= ::strtol(WidthPos
, &EndPos
, 10);
178 assert(*EndPos
== ':' && "Vector width specific must end with a ':'");
182 bool Builtin::Context::isLike(unsigned ID
, unsigned &FormatIdx
,
183 bool &HasVAListArg
, const char *Fmt
) const {
184 assert(Fmt
&& "Not passed a format string");
185 assert(::strlen(Fmt
) == 2 &&
186 "Format string needs to be two characters long");
187 assert(::toupper(Fmt
[0]) == Fmt
[1] &&
188 "Format string is not in the form \"xX\"");
190 const char *Like
= ::strpbrk(getRecord(ID
).Attributes
, Fmt
);
194 HasVAListArg
= (*Like
== Fmt
[1]);
197 assert(*Like
== ':' && "Format specifier must be followed by a ':'");
200 assert(::strchr(Like
, ':') && "Format specifier must end with a ':'");
201 FormatIdx
= ::strtol(Like
, nullptr, 10);
205 bool Builtin::Context::isPrintfLike(unsigned ID
, unsigned &FormatIdx
,
206 bool &HasVAListArg
) {
207 return isLike(ID
, FormatIdx
, HasVAListArg
, "pP");
210 bool Builtin::Context::isScanfLike(unsigned ID
, unsigned &FormatIdx
,
211 bool &HasVAListArg
) {
212 return isLike(ID
, FormatIdx
, HasVAListArg
, "sS");
215 bool Builtin::Context::performsCallback(unsigned ID
,
216 SmallVectorImpl
<int> &Encoding
) const {
217 const char *CalleePos
= ::strchr(getRecord(ID
).Attributes
, 'C');
222 assert(*CalleePos
== '<' &&
223 "Callback callee specifier must be followed by a '<'");
227 int CalleeIdx
= ::strtol(CalleePos
, &EndPos
, 10);
228 assert(CalleeIdx
>= 0 && "Callee index is supposed to be positive!");
229 Encoding
.push_back(CalleeIdx
);
231 while (*EndPos
== ',') {
232 const char *PayloadPos
= EndPos
+ 1;
234 int PayloadIdx
= ::strtol(PayloadPos
, &EndPos
, 10);
235 Encoding
.push_back(PayloadIdx
);
238 assert(*EndPos
== '>' && "Callback callee specifier must end with a '>'");
242 bool Builtin::Context::canBeRedeclared(unsigned ID
) const {
243 return ID
== Builtin::NotBuiltin
|| ID
== Builtin::BI__va_start
||
244 ID
== Builtin::BI__builtin_assume_aligned
||
245 (!hasReferenceArgsOrResult(ID
) && !hasCustomTypechecking(ID
)) ||
246 isInStdNamespace(ID
);
249 bool Builtin::evaluateRequiredTargetFeatures(
250 StringRef RequiredFeatures
, const llvm::StringMap
<bool> &TargetFetureMap
) {
251 // Return true if the builtin doesn't have any required features.
252 if (RequiredFeatures
.empty())
254 assert(!RequiredFeatures
.contains(' ') && "Space in feature list");
256 TargetFeatures
TF(TargetFetureMap
);
257 return TF
.hasRequiredFeatures(RequiredFeatures
);