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