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.def"
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
.equals(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 /* ObjC Unsupported */
94 if (!LangOpts
.ObjC
&& BuiltinInfo
.Langs
== OBJC_LANG
)
96 /* OpenCLC Unsupported */
97 if (!LangOpts
.OpenCL
&& (BuiltinInfo
.Langs
& ALL_OCL_LANGUAGES
))
99 /* OopenCL GAS Unsupported */
100 if (!LangOpts
.OpenCLGenericAddressSpace
&& (BuiltinInfo
.Langs
& OCL_GAS
))
102 /* OpenCL Pipe Unsupported */
103 if (!LangOpts
.OpenCLPipes
&& (BuiltinInfo
.Langs
& OCL_PIPE
))
106 // Device side enqueue is not supported until OpenCL 2.0. In 2.0 and higher
107 // support is indicated with language option for blocks.
109 /* OpenCL DSE Unsupported */
110 if ((LangOpts
.getOpenCLCompatibleVersion() < 200 || !LangOpts
.Blocks
) &&
111 (BuiltinInfo
.Langs
& OCL_DSE
))
113 /* OpenMP Unsupported */
114 if (!LangOpts
.OpenMP
&& BuiltinInfo
.Langs
== OMP_LANG
)
116 /* CUDA Unsupported */
117 if (!LangOpts
.CUDA
&& BuiltinInfo
.Langs
== CUDA_LANG
)
119 /* CPlusPlus Unsupported */
120 if (!LangOpts
.CPlusPlus
&& BuiltinInfo
.Langs
== CXX_LANG
)
125 /// initializeBuiltins - Mark the identifiers for all the builtins with their
126 /// appropriate builtin ID # and mark any non-portable builtin identifiers as
128 void Builtin::Context::initializeBuiltins(IdentifierTable
&Table
,
129 const LangOptions
& LangOpts
) {
130 // Step #1: mark all target-independent builtins with their ID's.
131 for (unsigned i
= Builtin::NotBuiltin
+1; i
!= Builtin::FirstTSBuiltin
; ++i
)
132 if (builtinIsSupported(BuiltinInfo
[i
], LangOpts
)) {
133 Table
.get(BuiltinInfo
[i
].Name
).setBuiltinID(i
);
136 // Step #2: Register target-specific builtins.
137 for (unsigned i
= 0, e
= TSRecords
.size(); i
!= e
; ++i
)
138 if (builtinIsSupported(TSRecords
[i
], LangOpts
))
139 Table
.get(TSRecords
[i
].Name
).setBuiltinID(i
+ Builtin::FirstTSBuiltin
);
141 // Step #3: Register target-specific builtins for AuxTarget.
142 for (unsigned i
= 0, e
= AuxTSRecords
.size(); i
!= e
; ++i
)
143 Table
.get(AuxTSRecords
[i
].Name
)
144 .setBuiltinID(i
+ Builtin::FirstTSBuiltin
+ TSRecords
.size());
146 // Step #4: Unregister any builtins specified by -fno-builtin-foo.
147 for (llvm::StringRef Name
: LangOpts
.NoBuiltinFuncs
) {
148 bool InStdNamespace
= Name
.consume_front("std-");
149 auto NameIt
= Table
.find(Name
);
150 if (NameIt
!= Table
.end()) {
151 unsigned ID
= NameIt
->second
->getBuiltinID();
152 if (ID
!= Builtin::NotBuiltin
&& isPredefinedLibFunction(ID
) &&
153 isInStdNamespace(ID
) == InStdNamespace
) {
154 Table
.get(Name
).setBuiltinID(Builtin::NotBuiltin
);
160 unsigned Builtin::Context::getRequiredVectorWidth(unsigned ID
) const {
161 const char *WidthPos
= ::strchr(getRecord(ID
).Attributes
, 'V');
166 assert(*WidthPos
== ':' &&
167 "Vector width specifier must be followed by a ':'");
171 unsigned Width
= ::strtol(WidthPos
, &EndPos
, 10);
172 assert(*EndPos
== ':' && "Vector width specific must end with a ':'");
176 bool Builtin::Context::isLike(unsigned ID
, unsigned &FormatIdx
,
177 bool &HasVAListArg
, const char *Fmt
) const {
178 assert(Fmt
&& "Not passed a format string");
179 assert(::strlen(Fmt
) == 2 &&
180 "Format string needs to be two characters long");
181 assert(::toupper(Fmt
[0]) == Fmt
[1] &&
182 "Format string is not in the form \"xX\"");
184 const char *Like
= ::strpbrk(getRecord(ID
).Attributes
, Fmt
);
188 HasVAListArg
= (*Like
== Fmt
[1]);
191 assert(*Like
== ':' && "Format specifier must be followed by a ':'");
194 assert(::strchr(Like
, ':') && "Format specifier must end with a ':'");
195 FormatIdx
= ::strtol(Like
, nullptr, 10);
199 bool Builtin::Context::isPrintfLike(unsigned ID
, unsigned &FormatIdx
,
200 bool &HasVAListArg
) {
201 return isLike(ID
, FormatIdx
, HasVAListArg
, "pP");
204 bool Builtin::Context::isScanfLike(unsigned ID
, unsigned &FormatIdx
,
205 bool &HasVAListArg
) {
206 return isLike(ID
, FormatIdx
, HasVAListArg
, "sS");
209 bool Builtin::Context::performsCallback(unsigned ID
,
210 SmallVectorImpl
<int> &Encoding
) const {
211 const char *CalleePos
= ::strchr(getRecord(ID
).Attributes
, 'C');
216 assert(*CalleePos
== '<' &&
217 "Callback callee specifier must be followed by a '<'");
221 int CalleeIdx
= ::strtol(CalleePos
, &EndPos
, 10);
222 assert(CalleeIdx
>= 0 && "Callee index is supposed to be positive!");
223 Encoding
.push_back(CalleeIdx
);
225 while (*EndPos
== ',') {
226 const char *PayloadPos
= EndPos
+ 1;
228 int PayloadIdx
= ::strtol(PayloadPos
, &EndPos
, 10);
229 Encoding
.push_back(PayloadIdx
);
232 assert(*EndPos
== '>' && "Callback callee specifier must end with a '>'");
236 bool Builtin::Context::canBeRedeclared(unsigned ID
) const {
237 return ID
== Builtin::NotBuiltin
|| ID
== Builtin::BI__va_start
||
238 ID
== Builtin::BI__builtin_assume_aligned
||
239 (!hasReferenceArgsOrResult(ID
) && !hasCustomTypechecking(ID
)) ||
240 isInStdNamespace(ID
);
243 bool Builtin::evaluateRequiredTargetFeatures(
244 StringRef RequiredFeatures
, const llvm::StringMap
<bool> &TargetFetureMap
) {
245 // Return true if the builtin doesn't have any required features.
246 if (RequiredFeatures
.empty())
248 assert(!RequiredFeatures
.contains(' ') && "Space in feature list");
250 TargetFeatures
TF(TargetFetureMap
);
251 return TF
.hasRequiredFeatures(RequiredFeatures
);