Path: blob/main/contrib/llvm-project/clang/lib/Basic/Builtins.cpp
35233 views
//===--- Builtins.cpp - Builtin function implementation -------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file implements various things for builtin functions.9//10//===----------------------------------------------------------------------===//1112#include "clang/Basic/Builtins.h"13#include "BuiltinTargetFeatures.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"18using namespace clang;1920const char *HeaderDesc::getName() const {21switch (ID) {22#define HEADER(ID, NAME) \23case ID: \24return NAME;25#include "clang/Basic/BuiltinHeaders.def"26#undef HEADER27};28llvm_unreachable("Unknown HeaderDesc::HeaderID enum");29}3031static constexpr Builtin::Info BuiltinInfo[] = {32{"not a builtin function", nullptr, nullptr, nullptr, HeaderDesc::NO_HEADER,33ALL_LANGUAGES},34#define BUILTIN(ID, TYPE, ATTRS) \35{#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},36#define LANGBUILTIN(ID, TYPE, ATTRS, LANGS) \37{#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, LANGS},38#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER, LANGS) \39{#ID, TYPE, ATTRS, nullptr, HeaderDesc::HEADER, LANGS},40#include "clang/Basic/Builtins.inc"41};4243const Builtin::Info &Builtin::Context::getRecord(unsigned ID) const {44if (ID < Builtin::FirstTSBuiltin)45return BuiltinInfo[ID];46assert(((ID - Builtin::FirstTSBuiltin) <47(TSRecords.size() + AuxTSRecords.size())) &&48"Invalid builtin ID!");49if (isAuxBuiltinID(ID))50return AuxTSRecords[getAuxBuiltinID(ID) - Builtin::FirstTSBuiltin];51return TSRecords[ID - Builtin::FirstTSBuiltin];52}5354void Builtin::Context::InitializeTarget(const TargetInfo &Target,55const TargetInfo *AuxTarget) {56assert(TSRecords.empty() && "Already initialized target?");57TSRecords = Target.getTargetBuiltins();58if (AuxTarget)59AuxTSRecords = AuxTarget->getTargetBuiltins();60}6162bool Builtin::Context::isBuiltinFunc(llvm::StringRef FuncName) {63bool InStdNamespace = FuncName.consume_front("std-");64for (unsigned i = Builtin::NotBuiltin + 1; i != Builtin::FirstTSBuiltin;65++i) {66if (FuncName == BuiltinInfo[i].Name &&67(bool)strchr(BuiltinInfo[i].Attributes, 'z') == InStdNamespace)68return strchr(BuiltinInfo[i].Attributes, 'f') != nullptr;69}7071return false;72}7374/// Is this builtin supported according to the given language options?75static bool builtinIsSupported(const Builtin::Info &BuiltinInfo,76const LangOptions &LangOpts) {77/* Builtins Unsupported */78if (LangOpts.NoBuiltin && strchr(BuiltinInfo.Attributes, 'f') != nullptr)79return false;80/* CorBuiltins Unsupported */81if (!LangOpts.Coroutines && (BuiltinInfo.Langs & COR_LANG))82return false;83/* MathBuiltins Unsupported */84if (LangOpts.NoMathBuiltin && BuiltinInfo.Header.ID == HeaderDesc::MATH_H)85return false;86/* GnuMode Unsupported */87if (!LangOpts.GNUMode && (BuiltinInfo.Langs & GNU_LANG))88return false;89/* MSMode Unsupported */90if (!LangOpts.MicrosoftExt && (BuiltinInfo.Langs & MS_LANG))91return false;92/* ObjC Unsupported */93if (!LangOpts.ObjC && BuiltinInfo.Langs == OBJC_LANG)94return false;95/* OpenCLC Unsupported */96if (!LangOpts.OpenCL && (BuiltinInfo.Langs & ALL_OCL_LANGUAGES))97return false;98/* OopenCL GAS Unsupported */99if (!LangOpts.OpenCLGenericAddressSpace && (BuiltinInfo.Langs & OCL_GAS))100return false;101/* OpenCL Pipe Unsupported */102if (!LangOpts.OpenCLPipes && (BuiltinInfo.Langs & OCL_PIPE))103return false;104105// Device side enqueue is not supported until OpenCL 2.0. In 2.0 and higher106// support is indicated with language option for blocks.107108/* OpenCL DSE Unsupported */109if ((LangOpts.getOpenCLCompatibleVersion() < 200 || !LangOpts.Blocks) &&110(BuiltinInfo.Langs & OCL_DSE))111return false;112/* OpenMP Unsupported */113if (!LangOpts.OpenMP && BuiltinInfo.Langs == OMP_LANG)114return false;115/* CUDA Unsupported */116if (!LangOpts.CUDA && BuiltinInfo.Langs == CUDA_LANG)117return false;118/* CPlusPlus Unsupported */119if (!LangOpts.CPlusPlus && BuiltinInfo.Langs == CXX_LANG)120return false;121/* consteval Unsupported */122if (!LangOpts.CPlusPlus20 && strchr(BuiltinInfo.Attributes, 'G') != nullptr)123return false;124return true;125}126127/// initializeBuiltins - Mark the identifiers for all the builtins with their128/// appropriate builtin ID # and mark any non-portable builtin identifiers as129/// such.130void Builtin::Context::initializeBuiltins(IdentifierTable &Table,131const LangOptions& LangOpts) {132// Step #1: mark all target-independent builtins with their ID's.133for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i)134if (builtinIsSupported(BuiltinInfo[i], LangOpts)) {135Table.get(BuiltinInfo[i].Name).setBuiltinID(i);136}137138// Step #2: Register target-specific builtins.139for (unsigned i = 0, e = TSRecords.size(); i != e; ++i)140if (builtinIsSupported(TSRecords[i], LangOpts))141Table.get(TSRecords[i].Name).setBuiltinID(i + Builtin::FirstTSBuiltin);142143// Step #3: Register target-specific builtins for AuxTarget.144for (unsigned i = 0, e = AuxTSRecords.size(); i != e; ++i)145Table.get(AuxTSRecords[i].Name)146.setBuiltinID(i + Builtin::FirstTSBuiltin + TSRecords.size());147148// Step #4: Unregister any builtins specified by -fno-builtin-foo.149for (llvm::StringRef Name : LangOpts.NoBuiltinFuncs) {150bool InStdNamespace = Name.consume_front("std-");151auto NameIt = Table.find(Name);152if (NameIt != Table.end()) {153unsigned ID = NameIt->second->getBuiltinID();154if (ID != Builtin::NotBuiltin && isPredefinedLibFunction(ID) &&155isInStdNamespace(ID) == InStdNamespace) {156NameIt->second->clearBuiltinID();157}158}159}160}161162unsigned Builtin::Context::getRequiredVectorWidth(unsigned ID) const {163const char *WidthPos = ::strchr(getRecord(ID).Attributes, 'V');164if (!WidthPos)165return 0;166167++WidthPos;168assert(*WidthPos == ':' &&169"Vector width specifier must be followed by a ':'");170++WidthPos;171172char *EndPos;173unsigned Width = ::strtol(WidthPos, &EndPos, 10);174assert(*EndPos == ':' && "Vector width specific must end with a ':'");175return Width;176}177178bool Builtin::Context::isLike(unsigned ID, unsigned &FormatIdx,179bool &HasVAListArg, const char *Fmt) const {180assert(Fmt && "Not passed a format string");181assert(::strlen(Fmt) == 2 &&182"Format string needs to be two characters long");183assert(::toupper(Fmt[0]) == Fmt[1] &&184"Format string is not in the form \"xX\"");185186const char *Like = ::strpbrk(getRecord(ID).Attributes, Fmt);187if (!Like)188return false;189190HasVAListArg = (*Like == Fmt[1]);191192++Like;193assert(*Like == ':' && "Format specifier must be followed by a ':'");194++Like;195196assert(::strchr(Like, ':') && "Format specifier must end with a ':'");197FormatIdx = ::strtol(Like, nullptr, 10);198return true;199}200201bool Builtin::Context::isPrintfLike(unsigned ID, unsigned &FormatIdx,202bool &HasVAListArg) {203return isLike(ID, FormatIdx, HasVAListArg, "pP");204}205206bool Builtin::Context::isScanfLike(unsigned ID, unsigned &FormatIdx,207bool &HasVAListArg) {208return isLike(ID, FormatIdx, HasVAListArg, "sS");209}210211bool Builtin::Context::performsCallback(unsigned ID,212SmallVectorImpl<int> &Encoding) const {213const char *CalleePos = ::strchr(getRecord(ID).Attributes, 'C');214if (!CalleePos)215return false;216217++CalleePos;218assert(*CalleePos == '<' &&219"Callback callee specifier must be followed by a '<'");220++CalleePos;221222char *EndPos;223int CalleeIdx = ::strtol(CalleePos, &EndPos, 10);224assert(CalleeIdx >= 0 && "Callee index is supposed to be positive!");225Encoding.push_back(CalleeIdx);226227while (*EndPos == ',') {228const char *PayloadPos = EndPos + 1;229230int PayloadIdx = ::strtol(PayloadPos, &EndPos, 10);231Encoding.push_back(PayloadIdx);232}233234assert(*EndPos == '>' && "Callback callee specifier must end with a '>'");235return true;236}237238bool Builtin::Context::canBeRedeclared(unsigned ID) const {239return ID == Builtin::NotBuiltin || ID == Builtin::BI__va_start ||240ID == Builtin::BI__builtin_assume_aligned ||241(!hasReferenceArgsOrResult(ID) && !hasCustomTypechecking(ID)) ||242isInStdNamespace(ID);243}244245bool Builtin::evaluateRequiredTargetFeatures(246StringRef RequiredFeatures, const llvm::StringMap<bool> &TargetFetureMap) {247// Return true if the builtin doesn't have any required features.248if (RequiredFeatures.empty())249return true;250assert(!RequiredFeatures.contains(' ') && "Space in feature list");251252TargetFeatures TF(TargetFetureMap);253return TF.hasRequiredFeatures(RequiredFeatures);254}255256257