10b57cec5SDimitry Andric //===--- Builtins.cpp - Builtin function implementation -------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file implements various things for builtin functions. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "clang/Basic/Builtins.h" 1481ad6265SDimitry Andric #include "BuiltinTargetFeatures.h" 150b57cec5SDimitry Andric #include "clang/Basic/IdentifierTable.h" 160b57cec5SDimitry Andric #include "clang/Basic/LangOptions.h" 170b57cec5SDimitry Andric #include "clang/Basic/TargetInfo.h" 180b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 190b57cec5SDimitry Andric using namespace clang; 200b57cec5SDimitry Andric 21bdd1243dSDimitry Andric const char *HeaderDesc::getName() const { 22bdd1243dSDimitry Andric switch (ID) { 23bdd1243dSDimitry Andric #define HEADER(ID, NAME) \ 24bdd1243dSDimitry Andric case ID: \ 25bdd1243dSDimitry Andric return NAME; 26bdd1243dSDimitry Andric #include "clang/Basic/BuiltinHeaders.def" 27bdd1243dSDimitry Andric #undef HEADER 28bdd1243dSDimitry Andric }; 29bdd1243dSDimitry Andric llvm_unreachable("Unknown HeaderDesc::HeaderID enum"); 30bdd1243dSDimitry Andric } 31bdd1243dSDimitry Andric 32bdd1243dSDimitry Andric static constexpr Builtin::Info BuiltinInfo[] = { 33bdd1243dSDimitry Andric {"not a builtin function", nullptr, nullptr, nullptr, HeaderDesc::NO_HEADER, 34bdd1243dSDimitry Andric ALL_LANGUAGES}, 350b57cec5SDimitry Andric #define BUILTIN(ID, TYPE, ATTRS) \ 36bdd1243dSDimitry Andric {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, 370b57cec5SDimitry Andric #define LANGBUILTIN(ID, TYPE, ATTRS, LANGS) \ 38bdd1243dSDimitry Andric {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, LANGS}, 390b57cec5SDimitry Andric #define LIBBUILTIN(ID, TYPE, ATTRS, HEADER, LANGS) \ 40bdd1243dSDimitry Andric {#ID, TYPE, ATTRS, nullptr, HeaderDesc::HEADER, LANGS}, 41*0fca6ea1SDimitry Andric #include "clang/Basic/Builtins.inc" 420b57cec5SDimitry Andric }; 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric const Builtin::Info &Builtin::Context::getRecord(unsigned ID) const { 450b57cec5SDimitry Andric if (ID < Builtin::FirstTSBuiltin) 460b57cec5SDimitry Andric return BuiltinInfo[ID]; 470b57cec5SDimitry Andric assert(((ID - Builtin::FirstTSBuiltin) < 480b57cec5SDimitry Andric (TSRecords.size() + AuxTSRecords.size())) && 490b57cec5SDimitry Andric "Invalid builtin ID!"); 500b57cec5SDimitry Andric if (isAuxBuiltinID(ID)) 510b57cec5SDimitry Andric return AuxTSRecords[getAuxBuiltinID(ID) - Builtin::FirstTSBuiltin]; 520b57cec5SDimitry Andric return TSRecords[ID - Builtin::FirstTSBuiltin]; 530b57cec5SDimitry Andric } 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric void Builtin::Context::InitializeTarget(const TargetInfo &Target, 560b57cec5SDimitry Andric const TargetInfo *AuxTarget) { 570b57cec5SDimitry Andric assert(TSRecords.empty() && "Already initialized target?"); 580b57cec5SDimitry Andric TSRecords = Target.getTargetBuiltins(); 590b57cec5SDimitry Andric if (AuxTarget) 600b57cec5SDimitry Andric AuxTSRecords = AuxTarget->getTargetBuiltins(); 610b57cec5SDimitry Andric } 620b57cec5SDimitry Andric 63480093f4SDimitry Andric bool Builtin::Context::isBuiltinFunc(llvm::StringRef FuncName) { 6481ad6265SDimitry Andric bool InStdNamespace = FuncName.consume_front("std-"); 6581ad6265SDimitry Andric for (unsigned i = Builtin::NotBuiltin + 1; i != Builtin::FirstTSBuiltin; 6681ad6265SDimitry Andric ++i) { 67*0fca6ea1SDimitry Andric if (FuncName == BuiltinInfo[i].Name && 6881ad6265SDimitry Andric (bool)strchr(BuiltinInfo[i].Attributes, 'z') == InStdNamespace) 690b57cec5SDimitry Andric return strchr(BuiltinInfo[i].Attributes, 'f') != nullptr; 7081ad6265SDimitry Andric } 710b57cec5SDimitry Andric 720b57cec5SDimitry Andric return false; 730b57cec5SDimitry Andric } 740b57cec5SDimitry Andric 7581ad6265SDimitry Andric /// Is this builtin supported according to the given language options? 7681ad6265SDimitry Andric static bool builtinIsSupported(const Builtin::Info &BuiltinInfo, 770b57cec5SDimitry Andric const LangOptions &LangOpts) { 78bdd1243dSDimitry Andric /* Builtins Unsupported */ 79bdd1243dSDimitry Andric if (LangOpts.NoBuiltin && strchr(BuiltinInfo.Attributes, 'f') != nullptr) 80bdd1243dSDimitry Andric return false; 81bdd1243dSDimitry Andric /* CorBuiltins Unsupported */ 82bdd1243dSDimitry Andric if (!LangOpts.Coroutines && (BuiltinInfo.Langs & COR_LANG)) 83bdd1243dSDimitry Andric return false; 84bdd1243dSDimitry Andric /* MathBuiltins Unsupported */ 85bdd1243dSDimitry Andric if (LangOpts.NoMathBuiltin && BuiltinInfo.Header.ID == HeaderDesc::MATH_H) 86bdd1243dSDimitry Andric return false; 87bdd1243dSDimitry Andric /* GnuMode Unsupported */ 88bdd1243dSDimitry Andric if (!LangOpts.GNUMode && (BuiltinInfo.Langs & GNU_LANG)) 89bdd1243dSDimitry Andric return false; 90bdd1243dSDimitry Andric /* MSMode Unsupported */ 91bdd1243dSDimitry Andric if (!LangOpts.MicrosoftExt && (BuiltinInfo.Langs & MS_LANG)) 92bdd1243dSDimitry Andric return false; 93bdd1243dSDimitry Andric /* ObjC Unsupported */ 94bdd1243dSDimitry Andric if (!LangOpts.ObjC && BuiltinInfo.Langs == OBJC_LANG) 95bdd1243dSDimitry Andric return false; 96bdd1243dSDimitry Andric /* OpenCLC Unsupported */ 97bdd1243dSDimitry Andric if (!LangOpts.OpenCL && (BuiltinInfo.Langs & ALL_OCL_LANGUAGES)) 98bdd1243dSDimitry Andric return false; 99bdd1243dSDimitry Andric /* OopenCL GAS Unsupported */ 100bdd1243dSDimitry Andric if (!LangOpts.OpenCLGenericAddressSpace && (BuiltinInfo.Langs & OCL_GAS)) 101bdd1243dSDimitry Andric return false; 102bdd1243dSDimitry Andric /* OpenCL Pipe Unsupported */ 103bdd1243dSDimitry Andric if (!LangOpts.OpenCLPipes && (BuiltinInfo.Langs & OCL_PIPE)) 104bdd1243dSDimitry Andric return false; 105bdd1243dSDimitry Andric 106d56accc7SDimitry Andric // Device side enqueue is not supported until OpenCL 2.0. In 2.0 and higher 107d56accc7SDimitry Andric // support is indicated with language option for blocks. 108bdd1243dSDimitry Andric 109bdd1243dSDimitry Andric /* OpenCL DSE Unsupported */ 110bdd1243dSDimitry Andric if ((LangOpts.getOpenCLCompatibleVersion() < 200 || !LangOpts.Blocks) && 111bdd1243dSDimitry Andric (BuiltinInfo.Langs & OCL_DSE)) 112bdd1243dSDimitry Andric return false; 113bdd1243dSDimitry Andric /* OpenMP Unsupported */ 114bdd1243dSDimitry Andric if (!LangOpts.OpenMP && BuiltinInfo.Langs == OMP_LANG) 115bdd1243dSDimitry Andric return false; 116bdd1243dSDimitry Andric /* CUDA Unsupported */ 117bdd1243dSDimitry Andric if (!LangOpts.CUDA && BuiltinInfo.Langs == CUDA_LANG) 118bdd1243dSDimitry Andric return false; 119bdd1243dSDimitry Andric /* CPlusPlus Unsupported */ 120bdd1243dSDimitry Andric if (!LangOpts.CPlusPlus && BuiltinInfo.Langs == CXX_LANG) 121bdd1243dSDimitry Andric return false; 122*0fca6ea1SDimitry Andric /* consteval Unsupported */ 123*0fca6ea1SDimitry Andric if (!LangOpts.CPlusPlus20 && strchr(BuiltinInfo.Attributes, 'G') != nullptr) 124*0fca6ea1SDimitry Andric return false; 125bdd1243dSDimitry Andric return true; 1260b57cec5SDimitry Andric } 1270b57cec5SDimitry Andric 1280b57cec5SDimitry Andric /// initializeBuiltins - Mark the identifiers for all the builtins with their 1290b57cec5SDimitry Andric /// appropriate builtin ID # and mark any non-portable builtin identifiers as 1300b57cec5SDimitry Andric /// such. 1310b57cec5SDimitry Andric void Builtin::Context::initializeBuiltins(IdentifierTable &Table, 1320b57cec5SDimitry Andric const LangOptions& LangOpts) { 1330b57cec5SDimitry Andric // Step #1: mark all target-independent builtins with their ID's. 1340b57cec5SDimitry Andric for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i) 1350b57cec5SDimitry Andric if (builtinIsSupported(BuiltinInfo[i], LangOpts)) { 1360b57cec5SDimitry Andric Table.get(BuiltinInfo[i].Name).setBuiltinID(i); 1370b57cec5SDimitry Andric } 1380b57cec5SDimitry Andric 1390b57cec5SDimitry Andric // Step #2: Register target-specific builtins. 1400b57cec5SDimitry Andric for (unsigned i = 0, e = TSRecords.size(); i != e; ++i) 1410b57cec5SDimitry Andric if (builtinIsSupported(TSRecords[i], LangOpts)) 1420b57cec5SDimitry Andric Table.get(TSRecords[i].Name).setBuiltinID(i + Builtin::FirstTSBuiltin); 1430b57cec5SDimitry Andric 1440b57cec5SDimitry Andric // Step #3: Register target-specific builtins for AuxTarget. 1450b57cec5SDimitry Andric for (unsigned i = 0, e = AuxTSRecords.size(); i != e; ++i) 1460b57cec5SDimitry Andric Table.get(AuxTSRecords[i].Name) 1470b57cec5SDimitry Andric .setBuiltinID(i + Builtin::FirstTSBuiltin + TSRecords.size()); 14881ad6265SDimitry Andric 14981ad6265SDimitry Andric // Step #4: Unregister any builtins specified by -fno-builtin-foo. 15081ad6265SDimitry Andric for (llvm::StringRef Name : LangOpts.NoBuiltinFuncs) { 15181ad6265SDimitry Andric bool InStdNamespace = Name.consume_front("std-"); 15281ad6265SDimitry Andric auto NameIt = Table.find(Name); 15381ad6265SDimitry Andric if (NameIt != Table.end()) { 15481ad6265SDimitry Andric unsigned ID = NameIt->second->getBuiltinID(); 15581ad6265SDimitry Andric if (ID != Builtin::NotBuiltin && isPredefinedLibFunction(ID) && 15681ad6265SDimitry Andric isInStdNamespace(ID) == InStdNamespace) { 15706c3fb27SDimitry Andric NameIt->second->clearBuiltinID(); 15881ad6265SDimitry Andric } 15981ad6265SDimitry Andric } 16081ad6265SDimitry Andric } 1610b57cec5SDimitry Andric } 1620b57cec5SDimitry Andric 1630b57cec5SDimitry Andric unsigned Builtin::Context::getRequiredVectorWidth(unsigned ID) const { 1640b57cec5SDimitry Andric const char *WidthPos = ::strchr(getRecord(ID).Attributes, 'V'); 1650b57cec5SDimitry Andric if (!WidthPos) 1660b57cec5SDimitry Andric return 0; 1670b57cec5SDimitry Andric 1680b57cec5SDimitry Andric ++WidthPos; 1690b57cec5SDimitry Andric assert(*WidthPos == ':' && 1700b57cec5SDimitry Andric "Vector width specifier must be followed by a ':'"); 1710b57cec5SDimitry Andric ++WidthPos; 1720b57cec5SDimitry Andric 1730b57cec5SDimitry Andric char *EndPos; 1740b57cec5SDimitry Andric unsigned Width = ::strtol(WidthPos, &EndPos, 10); 1750b57cec5SDimitry Andric assert(*EndPos == ':' && "Vector width specific must end with a ':'"); 1760b57cec5SDimitry Andric return Width; 1770b57cec5SDimitry Andric } 1780b57cec5SDimitry Andric 1790b57cec5SDimitry Andric bool Builtin::Context::isLike(unsigned ID, unsigned &FormatIdx, 1800b57cec5SDimitry Andric bool &HasVAListArg, const char *Fmt) const { 1810b57cec5SDimitry Andric assert(Fmt && "Not passed a format string"); 1820b57cec5SDimitry Andric assert(::strlen(Fmt) == 2 && 1830b57cec5SDimitry Andric "Format string needs to be two characters long"); 1840b57cec5SDimitry Andric assert(::toupper(Fmt[0]) == Fmt[1] && 1850b57cec5SDimitry Andric "Format string is not in the form \"xX\""); 1860b57cec5SDimitry Andric 1870b57cec5SDimitry Andric const char *Like = ::strpbrk(getRecord(ID).Attributes, Fmt); 1880b57cec5SDimitry Andric if (!Like) 1890b57cec5SDimitry Andric return false; 1900b57cec5SDimitry Andric 1910b57cec5SDimitry Andric HasVAListArg = (*Like == Fmt[1]); 1920b57cec5SDimitry Andric 1930b57cec5SDimitry Andric ++Like; 1940b57cec5SDimitry Andric assert(*Like == ':' && "Format specifier must be followed by a ':'"); 1950b57cec5SDimitry Andric ++Like; 1960b57cec5SDimitry Andric 1970b57cec5SDimitry Andric assert(::strchr(Like, ':') && "Format specifier must end with a ':'"); 1980b57cec5SDimitry Andric FormatIdx = ::strtol(Like, nullptr, 10); 1990b57cec5SDimitry Andric return true; 2000b57cec5SDimitry Andric } 2010b57cec5SDimitry Andric 2020b57cec5SDimitry Andric bool Builtin::Context::isPrintfLike(unsigned ID, unsigned &FormatIdx, 2030b57cec5SDimitry Andric bool &HasVAListArg) { 2040b57cec5SDimitry Andric return isLike(ID, FormatIdx, HasVAListArg, "pP"); 2050b57cec5SDimitry Andric } 2060b57cec5SDimitry Andric 2070b57cec5SDimitry Andric bool Builtin::Context::isScanfLike(unsigned ID, unsigned &FormatIdx, 2080b57cec5SDimitry Andric bool &HasVAListArg) { 2090b57cec5SDimitry Andric return isLike(ID, FormatIdx, HasVAListArg, "sS"); 2100b57cec5SDimitry Andric } 2110b57cec5SDimitry Andric 2120b57cec5SDimitry Andric bool Builtin::Context::performsCallback(unsigned ID, 2130b57cec5SDimitry Andric SmallVectorImpl<int> &Encoding) const { 2140b57cec5SDimitry Andric const char *CalleePos = ::strchr(getRecord(ID).Attributes, 'C'); 2150b57cec5SDimitry Andric if (!CalleePos) 2160b57cec5SDimitry Andric return false; 2170b57cec5SDimitry Andric 2180b57cec5SDimitry Andric ++CalleePos; 2190b57cec5SDimitry Andric assert(*CalleePos == '<' && 2200b57cec5SDimitry Andric "Callback callee specifier must be followed by a '<'"); 2210b57cec5SDimitry Andric ++CalleePos; 2220b57cec5SDimitry Andric 2230b57cec5SDimitry Andric char *EndPos; 2240b57cec5SDimitry Andric int CalleeIdx = ::strtol(CalleePos, &EndPos, 10); 2250b57cec5SDimitry Andric assert(CalleeIdx >= 0 && "Callee index is supposed to be positive!"); 2260b57cec5SDimitry Andric Encoding.push_back(CalleeIdx); 2270b57cec5SDimitry Andric 2280b57cec5SDimitry Andric while (*EndPos == ',') { 2290b57cec5SDimitry Andric const char *PayloadPos = EndPos + 1; 2300b57cec5SDimitry Andric 2310b57cec5SDimitry Andric int PayloadIdx = ::strtol(PayloadPos, &EndPos, 10); 2320b57cec5SDimitry Andric Encoding.push_back(PayloadIdx); 2330b57cec5SDimitry Andric } 2340b57cec5SDimitry Andric 2350b57cec5SDimitry Andric assert(*EndPos == '>' && "Callback callee specifier must end with a '>'"); 2360b57cec5SDimitry Andric return true; 2370b57cec5SDimitry Andric } 2380b57cec5SDimitry Andric 2390b57cec5SDimitry Andric bool Builtin::Context::canBeRedeclared(unsigned ID) const { 24081ad6265SDimitry Andric return ID == Builtin::NotBuiltin || ID == Builtin::BI__va_start || 241bdd1243dSDimitry Andric ID == Builtin::BI__builtin_assume_aligned || 24281ad6265SDimitry Andric (!hasReferenceArgsOrResult(ID) && !hasCustomTypechecking(ID)) || 24381ad6265SDimitry Andric isInStdNamespace(ID); 24481ad6265SDimitry Andric } 24581ad6265SDimitry Andric 24681ad6265SDimitry Andric bool Builtin::evaluateRequiredTargetFeatures( 24781ad6265SDimitry Andric StringRef RequiredFeatures, const llvm::StringMap<bool> &TargetFetureMap) { 24881ad6265SDimitry Andric // Return true if the builtin doesn't have any required features. 24981ad6265SDimitry Andric if (RequiredFeatures.empty()) 25081ad6265SDimitry Andric return true; 25181ad6265SDimitry Andric assert(!RequiredFeatures.contains(' ') && "Space in feature list"); 25281ad6265SDimitry Andric 25381ad6265SDimitry Andric TargetFeatures TF(TargetFetureMap); 25481ad6265SDimitry Andric return TF.hasRequiredFeatures(RequiredFeatures); 2550b57cec5SDimitry Andric } 256