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" 19 using namespace clang; 20 21 const 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 32 static constexpr Builtin::Info BuiltinInfo[] = { 33 {"not a builtin function", nullptr, nullptr, nullptr, HeaderDesc::NO_HEADER, 34 ALL_LANGUAGES}, 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" 42 }; 43 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]; 53 } 54 55 void Builtin::Context::InitializeTarget(const TargetInfo &Target, 56 const TargetInfo *AuxTarget) { 57 assert(TSRecords.empty() && "Already initialized target?"); 58 TSRecords = Target.getTargetBuiltins(); 59 if (AuxTarget) 60 AuxTSRecords = AuxTarget->getTargetBuiltins(); 61 } 62 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; 66 ++i) { 67 if (FuncName == BuiltinInfo[i].Name && 68 (bool)strchr(BuiltinInfo[i].Attributes, 'z') == InStdNamespace) 69 return strchr(BuiltinInfo[i].Attributes, 'f') != nullptr; 70 } 71 72 return false; 73 } 74 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) 80 return false; 81 /* CorBuiltins Unsupported */ 82 if (!LangOpts.Coroutines && (BuiltinInfo.Langs & COR_LANG)) 83 return false; 84 /* MathBuiltins Unsupported */ 85 if (LangOpts.NoMathBuiltin && BuiltinInfo.Header.ID == HeaderDesc::MATH_H) 86 return false; 87 /* GnuMode Unsupported */ 88 if (!LangOpts.GNUMode && (BuiltinInfo.Langs & GNU_LANG)) 89 return false; 90 /* MSMode Unsupported */ 91 if (!LangOpts.MicrosoftExt && (BuiltinInfo.Langs & MS_LANG)) 92 return false; 93 /* HLSLMode Unsupported */ 94 if (!LangOpts.HLSL && (BuiltinInfo.Langs & HLSL_LANG)) 95 return false; 96 /* ObjC Unsupported */ 97 if (!LangOpts.ObjC && BuiltinInfo.Langs == OBJC_LANG) 98 return false; 99 /* OpenCLC Unsupported */ 100 if (!LangOpts.OpenCL && (BuiltinInfo.Langs & ALL_OCL_LANGUAGES)) 101 return false; 102 /* OopenCL GAS Unsupported */ 103 if (!LangOpts.OpenCLGenericAddressSpace && (BuiltinInfo.Langs & OCL_GAS)) 104 return false; 105 /* OpenCL Pipe Unsupported */ 106 if (!LangOpts.OpenCLPipes && (BuiltinInfo.Langs & OCL_PIPE)) 107 return false; 108 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. 111 112 /* OpenCL DSE Unsupported */ 113 if ((LangOpts.getOpenCLCompatibleVersion() < 200 || !LangOpts.Blocks) && 114 (BuiltinInfo.Langs & OCL_DSE)) 115 return false; 116 /* OpenMP Unsupported */ 117 if (!LangOpts.OpenMP && BuiltinInfo.Langs == OMP_LANG) 118 return false; 119 /* CUDA Unsupported */ 120 if (!LangOpts.CUDA && BuiltinInfo.Langs == CUDA_LANG) 121 return false; 122 /* CPlusPlus Unsupported */ 123 if (!LangOpts.CPlusPlus && BuiltinInfo.Langs == CXX_LANG) 124 return false; 125 /* consteval Unsupported */ 126 if (!LangOpts.CPlusPlus20 && strchr(BuiltinInfo.Attributes, 'G') != nullptr) 127 return false; 128 return true; 129 } 130 131 /// initializeBuiltins - Mark the identifiers for all the builtins with their 132 /// appropriate builtin ID # and mark any non-portable builtin identifiers as 133 /// such. 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); 140 } 141 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); 146 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()); 151 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(); 161 } 162 } 163 } 164 } 165 166 std::string Builtin::Context::getQuotedName(unsigned ID) const { 167 return (llvm::Twine("'") + getName(ID) + "'").str(); 168 } 169 170 unsigned Builtin::Context::getRequiredVectorWidth(unsigned ID) const { 171 const char *WidthPos = ::strchr(getRecord(ID).Attributes, 'V'); 172 if (!WidthPos) 173 return 0; 174 175 ++WidthPos; 176 assert(*WidthPos == ':' && 177 "Vector width specifier must be followed by a ':'"); 178 ++WidthPos; 179 180 char *EndPos; 181 unsigned Width = ::strtol(WidthPos, &EndPos, 10); 182 assert(*EndPos == ':' && "Vector width specific must end with a ':'"); 183 return Width; 184 } 185 186 bool Builtin::Context::isLike(unsigned ID, unsigned &FormatIdx, 187 bool &HasVAListArg, const char *Fmt) const { 188 assert(Fmt && "Not passed a format string"); 189 assert(::strlen(Fmt) == 2 && 190 "Format string needs to be two characters long"); 191 assert(::toupper(Fmt[0]) == Fmt[1] && 192 "Format string is not in the form \"xX\""); 193 194 const char *Like = ::strpbrk(getRecord(ID).Attributes, Fmt); 195 if (!Like) 196 return false; 197 198 HasVAListArg = (*Like == Fmt[1]); 199 200 ++Like; 201 assert(*Like == ':' && "Format specifier must be followed by a ':'"); 202 ++Like; 203 204 assert(::strchr(Like, ':') && "Format specifier must end with a ':'"); 205 FormatIdx = ::strtol(Like, nullptr, 10); 206 return true; 207 } 208 209 bool Builtin::Context::isPrintfLike(unsigned ID, unsigned &FormatIdx, 210 bool &HasVAListArg) { 211 return isLike(ID, FormatIdx, HasVAListArg, "pP"); 212 } 213 214 bool Builtin::Context::isScanfLike(unsigned ID, unsigned &FormatIdx, 215 bool &HasVAListArg) { 216 return isLike(ID, FormatIdx, HasVAListArg, "sS"); 217 } 218 219 bool Builtin::Context::performsCallback(unsigned ID, 220 SmallVectorImpl<int> &Encoding) const { 221 const char *CalleePos = ::strchr(getRecord(ID).Attributes, 'C'); 222 if (!CalleePos) 223 return false; 224 225 ++CalleePos; 226 assert(*CalleePos == '<' && 227 "Callback callee specifier must be followed by a '<'"); 228 ++CalleePos; 229 230 char *EndPos; 231 int CalleeIdx = ::strtol(CalleePos, &EndPos, 10); 232 assert(CalleeIdx >= 0 && "Callee index is supposed to be positive!"); 233 Encoding.push_back(CalleeIdx); 234 235 while (*EndPos == ',') { 236 const char *PayloadPos = EndPos + 1; 237 238 int PayloadIdx = ::strtol(PayloadPos, &EndPos, 10); 239 Encoding.push_back(PayloadIdx); 240 } 241 242 assert(*EndPos == '>' && "Callback callee specifier must end with a '>'"); 243 return true; 244 } 245 246 bool Builtin::Context::canBeRedeclared(unsigned ID) const { 247 return ID == Builtin::NotBuiltin || ID == Builtin::BI__va_start || 248 ID == Builtin::BI__builtin_assume_aligned || 249 (!hasReferenceArgsOrResult(ID) && !hasCustomTypechecking(ID)) || 250 isInStdNamespace(ID); 251 } 252 253 bool Builtin::evaluateRequiredTargetFeatures( 254 StringRef RequiredFeatures, const llvm::StringMap<bool> &TargetFetureMap) { 255 // Return true if the builtin doesn't have any required features. 256 if (RequiredFeatures.empty()) 257 return true; 258 assert(!RequiredFeatures.contains(' ') && "Space in feature list"); 259 260 TargetFeatures TF(TargetFetureMap); 261 return TF.hasRequiredFeatures(RequiredFeatures); 262 } 263