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 "clang/Basic/IdentifierTable.h"
15 #include "clang/Basic/LangOptions.h"
16 #include "clang/Basic/TargetInfo.h"
17 #include "llvm/ADT/StringRef.h"
18 using namespace clang
;
20 static const Builtin::Info BuiltinInfo
[] = {
21 { "not a builtin function", nullptr, nullptr, nullptr, ALL_LANGUAGES
,nullptr},
22 #define BUILTIN(ID, TYPE, ATTRS) \
23 { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr },
24 #define LANGBUILTIN(ID, TYPE, ATTRS, LANGS) \
25 { #ID, TYPE, ATTRS, nullptr, LANGS, nullptr },
26 #define LIBBUILTIN(ID, TYPE, ATTRS, HEADER, LANGS) \
27 { #ID, TYPE, ATTRS, HEADER, LANGS, nullptr },
28 #include "clang/Basic/Builtins.def"
31 const Builtin::Info
&Builtin::Context::getRecord(unsigned ID
) const {
32 if (ID
< Builtin::FirstTSBuiltin
)
33 return BuiltinInfo
[ID
];
34 assert(((ID
- Builtin::FirstTSBuiltin
) <
35 (TSRecords
.size() + AuxTSRecords
.size())) &&
36 "Invalid builtin ID!");
37 if (isAuxBuiltinID(ID
))
38 return AuxTSRecords
[getAuxBuiltinID(ID
) - Builtin::FirstTSBuiltin
];
39 return TSRecords
[ID
- Builtin::FirstTSBuiltin
];
42 void Builtin::Context::InitializeTarget(const TargetInfo
&Target
,
43 const TargetInfo
*AuxTarget
) {
44 assert(TSRecords
.empty() && "Already initialized target?");
45 TSRecords
= Target
.getTargetBuiltins();
47 AuxTSRecords
= AuxTarget
->getTargetBuiltins();
50 bool Builtin::Context::isBuiltinFunc(llvm::StringRef FuncName
) {
51 for (unsigned i
= Builtin::NotBuiltin
+ 1; i
!= Builtin::FirstTSBuiltin
; ++i
)
52 if (FuncName
.equals(BuiltinInfo
[i
].Name
))
53 return strchr(BuiltinInfo
[i
].Attributes
, 'f') != nullptr;
58 bool Builtin::Context::builtinIsSupported(const Builtin::Info
&BuiltinInfo
,
59 const LangOptions
&LangOpts
) {
60 bool BuiltinsUnsupported
=
61 (LangOpts
.NoBuiltin
|| LangOpts
.isNoBuiltinFunc(BuiltinInfo
.Name
)) &&
62 strchr(BuiltinInfo
.Attributes
, 'f');
63 bool CorBuiltinsUnsupported
=
64 !LangOpts
.Coroutines
&& (BuiltinInfo
.Langs
& COR_LANG
);
65 bool MathBuiltinsUnsupported
=
66 LangOpts
.NoMathBuiltin
&& BuiltinInfo
.HeaderName
&&
67 llvm::StringRef(BuiltinInfo
.HeaderName
).equals("math.h");
68 bool GnuModeUnsupported
= !LangOpts
.GNUMode
&& (BuiltinInfo
.Langs
& GNU_LANG
);
69 bool MSModeUnsupported
=
70 !LangOpts
.MicrosoftExt
&& (BuiltinInfo
.Langs
& MS_LANG
);
71 bool ObjCUnsupported
= !LangOpts
.ObjC
&& BuiltinInfo
.Langs
== OBJC_LANG
;
72 bool OclCUnsupported
=
73 !LangOpts
.OpenCL
&& (BuiltinInfo
.Langs
& ALL_OCL_LANGUAGES
);
74 bool OclGASUnsupported
=
75 !LangOpts
.OpenCLGenericAddressSpace
&& (BuiltinInfo
.Langs
& OCL_GAS
);
76 bool OclPipeUnsupported
=
77 !LangOpts
.OpenCLPipes
&& (BuiltinInfo
.Langs
& OCL_PIPE
);
78 // Device side enqueue is not supported until OpenCL 2.0. In 2.0 and higher
79 // support is indicated with language option for blocks.
80 bool OclDSEUnsupported
=
81 (LangOpts
.getOpenCLCompatibleVersion() < 200 || !LangOpts
.Blocks
) &&
82 (BuiltinInfo
.Langs
& OCL_DSE
);
83 bool OpenMPUnsupported
= !LangOpts
.OpenMP
&& BuiltinInfo
.Langs
== OMP_LANG
;
84 bool CUDAUnsupported
= !LangOpts
.CUDA
&& BuiltinInfo
.Langs
== CUDA_LANG
;
85 bool CPlusPlusUnsupported
=
86 !LangOpts
.CPlusPlus
&& BuiltinInfo
.Langs
== CXX_LANG
;
87 return !BuiltinsUnsupported
&& !CorBuiltinsUnsupported
&&
88 !MathBuiltinsUnsupported
&& !OclCUnsupported
&& !OclGASUnsupported
&&
89 !OclPipeUnsupported
&& !OclDSEUnsupported
&& !OpenMPUnsupported
&&
90 !GnuModeUnsupported
&& !MSModeUnsupported
&& !ObjCUnsupported
&&
91 !CPlusPlusUnsupported
&& !CUDAUnsupported
;
94 /// initializeBuiltins - Mark the identifiers for all the builtins with their
95 /// appropriate builtin ID # and mark any non-portable builtin identifiers as
97 void Builtin::Context::initializeBuiltins(IdentifierTable
&Table
,
98 const LangOptions
& LangOpts
) {
99 // Step #1: mark all target-independent builtins with their ID's.
100 for (unsigned i
= Builtin::NotBuiltin
+1; i
!= Builtin::FirstTSBuiltin
; ++i
)
101 if (builtinIsSupported(BuiltinInfo
[i
], LangOpts
)) {
102 Table
.get(BuiltinInfo
[i
].Name
).setBuiltinID(i
);
105 // Step #2: Register target-specific builtins.
106 for (unsigned i
= 0, e
= TSRecords
.size(); i
!= e
; ++i
)
107 if (builtinIsSupported(TSRecords
[i
], LangOpts
))
108 Table
.get(TSRecords
[i
].Name
).setBuiltinID(i
+ Builtin::FirstTSBuiltin
);
110 // Step #3: Register target-specific builtins for AuxTarget.
111 for (unsigned i
= 0, e
= AuxTSRecords
.size(); i
!= e
; ++i
)
112 Table
.get(AuxTSRecords
[i
].Name
)
113 .setBuiltinID(i
+ Builtin::FirstTSBuiltin
+ TSRecords
.size());
116 unsigned Builtin::Context::getRequiredVectorWidth(unsigned ID
) const {
117 const char *WidthPos
= ::strchr(getRecord(ID
).Attributes
, 'V');
122 assert(*WidthPos
== ':' &&
123 "Vector width specifier must be followed by a ':'");
127 unsigned Width
= ::strtol(WidthPos
, &EndPos
, 10);
128 assert(*EndPos
== ':' && "Vector width specific must end with a ':'");
132 bool Builtin::Context::isLike(unsigned ID
, unsigned &FormatIdx
,
133 bool &HasVAListArg
, const char *Fmt
) const {
134 assert(Fmt
&& "Not passed a format string");
135 assert(::strlen(Fmt
) == 2 &&
136 "Format string needs to be two characters long");
137 assert(::toupper(Fmt
[0]) == Fmt
[1] &&
138 "Format string is not in the form \"xX\"");
140 const char *Like
= ::strpbrk(getRecord(ID
).Attributes
, Fmt
);
144 HasVAListArg
= (*Like
== Fmt
[1]);
147 assert(*Like
== ':' && "Format specifier must be followed by a ':'");
150 assert(::strchr(Like
, ':') && "Format specifier must end with a ':'");
151 FormatIdx
= ::strtol(Like
, nullptr, 10);
155 bool Builtin::Context::isPrintfLike(unsigned ID
, unsigned &FormatIdx
,
156 bool &HasVAListArg
) {
157 return isLike(ID
, FormatIdx
, HasVAListArg
, "pP");
160 bool Builtin::Context::isScanfLike(unsigned ID
, unsigned &FormatIdx
,
161 bool &HasVAListArg
) {
162 return isLike(ID
, FormatIdx
, HasVAListArg
, "sS");
165 bool Builtin::Context::performsCallback(unsigned ID
,
166 SmallVectorImpl
<int> &Encoding
) const {
167 const char *CalleePos
= ::strchr(getRecord(ID
).Attributes
, 'C');
172 assert(*CalleePos
== '<' &&
173 "Callback callee specifier must be followed by a '<'");
177 int CalleeIdx
= ::strtol(CalleePos
, &EndPos
, 10);
178 assert(CalleeIdx
>= 0 && "Callee index is supposed to be positive!");
179 Encoding
.push_back(CalleeIdx
);
181 while (*EndPos
== ',') {
182 const char *PayloadPos
= EndPos
+ 1;
184 int PayloadIdx
= ::strtol(PayloadPos
, &EndPos
, 10);
185 Encoding
.push_back(PayloadIdx
);
188 assert(*EndPos
== '>' && "Callback callee specifier must end with a '>'");
192 bool Builtin::Context::canBeRedeclared(unsigned ID
) const {
193 return ID
== Builtin::NotBuiltin
||
194 ID
== Builtin::BI__va_start
||
195 (!hasReferenceArgsOrResult(ID
) &&
196 !hasCustomTypechecking(ID
));