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 static const Builtin::Info BuiltinInfo[] = { 22 { "not a builtin function", nullptr, nullptr, nullptr, ALL_LANGUAGES,nullptr}, 23 #define BUILTIN(ID, TYPE, ATTRS) \ 24 { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, 25 #define LANGBUILTIN(ID, TYPE, ATTRS, LANGS) \ 26 { #ID, TYPE, ATTRS, nullptr, LANGS, nullptr }, 27 #define LIBBUILTIN(ID, TYPE, ATTRS, HEADER, LANGS) \ 28 { #ID, TYPE, ATTRS, HEADER, LANGS, nullptr }, 29 #include "clang/Basic/Builtins.def" 30 }; 31 32 const Builtin::Info &Builtin::Context::getRecord(unsigned ID) const { 33 if (ID < Builtin::FirstTSBuiltin) 34 return BuiltinInfo[ID]; 35 assert(((ID - Builtin::FirstTSBuiltin) < 36 (TSRecords.size() + AuxTSRecords.size())) && 37 "Invalid builtin ID!"); 38 if (isAuxBuiltinID(ID)) 39 return AuxTSRecords[getAuxBuiltinID(ID) - Builtin::FirstTSBuiltin]; 40 return TSRecords[ID - Builtin::FirstTSBuiltin]; 41 } 42 43 void Builtin::Context::InitializeTarget(const TargetInfo &Target, 44 const TargetInfo *AuxTarget) { 45 assert(TSRecords.empty() && "Already initialized target?"); 46 TSRecords = Target.getTargetBuiltins(); 47 if (AuxTarget) 48 AuxTSRecords = AuxTarget->getTargetBuiltins(); 49 } 50 51 bool Builtin::Context::isBuiltinFunc(llvm::StringRef FuncName) { 52 bool InStdNamespace = FuncName.consume_front("std-"); 53 for (unsigned i = Builtin::NotBuiltin + 1; i != Builtin::FirstTSBuiltin; 54 ++i) { 55 if (FuncName.equals(BuiltinInfo[i].Name) && 56 (bool)strchr(BuiltinInfo[i].Attributes, 'z') == InStdNamespace) 57 return strchr(BuiltinInfo[i].Attributes, 'f') != nullptr; 58 } 59 60 return false; 61 } 62 63 /// Is this builtin supported according to the given language options? 64 static bool builtinIsSupported(const Builtin::Info &BuiltinInfo, 65 const LangOptions &LangOpts) { 66 bool BuiltinsUnsupported = 67 LangOpts.NoBuiltin && strchr(BuiltinInfo.Attributes, 'f') != nullptr; 68 bool CorBuiltinsUnsupported = 69 !LangOpts.Coroutines && (BuiltinInfo.Langs & COR_LANG); 70 bool MathBuiltinsUnsupported = 71 LangOpts.NoMathBuiltin && BuiltinInfo.HeaderName && 72 llvm::StringRef(BuiltinInfo.HeaderName).equals("math.h"); 73 bool GnuModeUnsupported = !LangOpts.GNUMode && (BuiltinInfo.Langs & GNU_LANG); 74 bool MSModeUnsupported = 75 !LangOpts.MicrosoftExt && (BuiltinInfo.Langs & MS_LANG); 76 bool ObjCUnsupported = !LangOpts.ObjC && BuiltinInfo.Langs == OBJC_LANG; 77 bool OclCUnsupported = 78 !LangOpts.OpenCL && (BuiltinInfo.Langs & ALL_OCL_LANGUAGES); 79 bool OclGASUnsupported = 80 !LangOpts.OpenCLGenericAddressSpace && (BuiltinInfo.Langs & OCL_GAS); 81 bool OclPipeUnsupported = 82 !LangOpts.OpenCLPipes && (BuiltinInfo.Langs & OCL_PIPE); 83 // Device side enqueue is not supported until OpenCL 2.0. In 2.0 and higher 84 // support is indicated with language option for blocks. 85 bool OclDSEUnsupported = 86 (LangOpts.getOpenCLCompatibleVersion() < 200 || !LangOpts.Blocks) && 87 (BuiltinInfo.Langs & OCL_DSE); 88 bool OpenMPUnsupported = !LangOpts.OpenMP && BuiltinInfo.Langs == OMP_LANG; 89 bool CUDAUnsupported = !LangOpts.CUDA && BuiltinInfo.Langs == CUDA_LANG; 90 bool CPlusPlusUnsupported = 91 !LangOpts.CPlusPlus && BuiltinInfo.Langs == CXX_LANG; 92 return !BuiltinsUnsupported && !CorBuiltinsUnsupported && 93 !MathBuiltinsUnsupported && !OclCUnsupported && !OclGASUnsupported && 94 !OclPipeUnsupported && !OclDSEUnsupported && !OpenMPUnsupported && 95 !GnuModeUnsupported && !MSModeUnsupported && !ObjCUnsupported && 96 !CPlusPlusUnsupported && !CUDAUnsupported; 97 } 98 99 /// initializeBuiltins - Mark the identifiers for all the builtins with their 100 /// appropriate builtin ID # and mark any non-portable builtin identifiers as 101 /// such. 102 void Builtin::Context::initializeBuiltins(IdentifierTable &Table, 103 const LangOptions& LangOpts) { 104 // Step #1: mark all target-independent builtins with their ID's. 105 for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i) 106 if (builtinIsSupported(BuiltinInfo[i], LangOpts)) { 107 Table.get(BuiltinInfo[i].Name).setBuiltinID(i); 108 } 109 110 // Step #2: Register target-specific builtins. 111 for (unsigned i = 0, e = TSRecords.size(); i != e; ++i) 112 if (builtinIsSupported(TSRecords[i], LangOpts)) 113 Table.get(TSRecords[i].Name).setBuiltinID(i + Builtin::FirstTSBuiltin); 114 115 // Step #3: Register target-specific builtins for AuxTarget. 116 for (unsigned i = 0, e = AuxTSRecords.size(); i != e; ++i) 117 Table.get(AuxTSRecords[i].Name) 118 .setBuiltinID(i + Builtin::FirstTSBuiltin + TSRecords.size()); 119 120 // Step #4: Unregister any builtins specified by -fno-builtin-foo. 121 for (llvm::StringRef Name : LangOpts.NoBuiltinFuncs) { 122 bool InStdNamespace = Name.consume_front("std-"); 123 auto NameIt = Table.find(Name); 124 if (NameIt != Table.end()) { 125 unsigned ID = NameIt->second->getBuiltinID(); 126 if (ID != Builtin::NotBuiltin && isPredefinedLibFunction(ID) && 127 isInStdNamespace(ID) == InStdNamespace) { 128 Table.get(Name).setBuiltinID(Builtin::NotBuiltin); 129 } 130 } 131 } 132 } 133 134 unsigned Builtin::Context::getRequiredVectorWidth(unsigned ID) const { 135 const char *WidthPos = ::strchr(getRecord(ID).Attributes, 'V'); 136 if (!WidthPos) 137 return 0; 138 139 ++WidthPos; 140 assert(*WidthPos == ':' && 141 "Vector width specifier must be followed by a ':'"); 142 ++WidthPos; 143 144 char *EndPos; 145 unsigned Width = ::strtol(WidthPos, &EndPos, 10); 146 assert(*EndPos == ':' && "Vector width specific must end with a ':'"); 147 return Width; 148 } 149 150 bool Builtin::Context::isLike(unsigned ID, unsigned &FormatIdx, 151 bool &HasVAListArg, const char *Fmt) const { 152 assert(Fmt && "Not passed a format string"); 153 assert(::strlen(Fmt) == 2 && 154 "Format string needs to be two characters long"); 155 assert(::toupper(Fmt[0]) == Fmt[1] && 156 "Format string is not in the form \"xX\""); 157 158 const char *Like = ::strpbrk(getRecord(ID).Attributes, Fmt); 159 if (!Like) 160 return false; 161 162 HasVAListArg = (*Like == Fmt[1]); 163 164 ++Like; 165 assert(*Like == ':' && "Format specifier must be followed by a ':'"); 166 ++Like; 167 168 assert(::strchr(Like, ':') && "Format specifier must end with a ':'"); 169 FormatIdx = ::strtol(Like, nullptr, 10); 170 return true; 171 } 172 173 bool Builtin::Context::isPrintfLike(unsigned ID, unsigned &FormatIdx, 174 bool &HasVAListArg) { 175 return isLike(ID, FormatIdx, HasVAListArg, "pP"); 176 } 177 178 bool Builtin::Context::isScanfLike(unsigned ID, unsigned &FormatIdx, 179 bool &HasVAListArg) { 180 return isLike(ID, FormatIdx, HasVAListArg, "sS"); 181 } 182 183 bool Builtin::Context::performsCallback(unsigned ID, 184 SmallVectorImpl<int> &Encoding) const { 185 const char *CalleePos = ::strchr(getRecord(ID).Attributes, 'C'); 186 if (!CalleePos) 187 return false; 188 189 ++CalleePos; 190 assert(*CalleePos == '<' && 191 "Callback callee specifier must be followed by a '<'"); 192 ++CalleePos; 193 194 char *EndPos; 195 int CalleeIdx = ::strtol(CalleePos, &EndPos, 10); 196 assert(CalleeIdx >= 0 && "Callee index is supposed to be positive!"); 197 Encoding.push_back(CalleeIdx); 198 199 while (*EndPos == ',') { 200 const char *PayloadPos = EndPos + 1; 201 202 int PayloadIdx = ::strtol(PayloadPos, &EndPos, 10); 203 Encoding.push_back(PayloadIdx); 204 } 205 206 assert(*EndPos == '>' && "Callback callee specifier must end with a '>'"); 207 return true; 208 } 209 210 bool Builtin::Context::canBeRedeclared(unsigned ID) const { 211 return ID == Builtin::NotBuiltin || ID == Builtin::BI__va_start || 212 (!hasReferenceArgsOrResult(ID) && !hasCustomTypechecking(ID)) || 213 isInStdNamespace(ID); 214 } 215 216 bool Builtin::evaluateRequiredTargetFeatures( 217 StringRef RequiredFeatures, const llvm::StringMap<bool> &TargetFetureMap) { 218 // Return true if the builtin doesn't have any required features. 219 if (RequiredFeatures.empty()) 220 return true; 221 assert(!RequiredFeatures.contains(' ') && "Space in feature list"); 222 223 TargetFeatures TF(TargetFetureMap); 224 return TF.hasRequiredFeatures(RequiredFeatures); 225 } 226