Path: blob/main/contrib/llvm-project/clang/utils/TableGen/ClangBuiltinsEmitter.cpp
35230 views
//=- ClangBuiltinsEmitter.cpp - Generate Clang builtins tables -*- C++ -*-====//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 tablegen backend emits Clang's builtins tables.9//10//===----------------------------------------------------------------------===//1112#include "TableGenBackends.h"13#include "llvm/ADT/StringSwitch.h"14#include "llvm/TableGen/Error.h"15#include "llvm/TableGen/Record.h"16#include "llvm/TableGen/TableGenBackend.h"1718using namespace llvm;1920namespace {21enum class BuiltinType {22Builtin,23AtomicBuiltin,24LibBuiltin,25LangBuiltin,26TargetBuiltin,27};2829class PrototypeParser {30public:31PrototypeParser(StringRef Substitution, const Record *Builtin)32: Loc(Builtin->getFieldLoc("Prototype")), Substitution(Substitution) {33ParsePrototype(Builtin->getValueAsString("Prototype"));34}3536private:37void ParsePrototype(StringRef Prototype) {38Prototype = Prototype.trim();39ParseTypes(Prototype);40}4142void ParseTypes(StringRef &Prototype) {43auto ReturnType = Prototype.take_until([](char c) { return c == '('; });44ParseType(ReturnType);45Prototype = Prototype.drop_front(ReturnType.size() + 1);46if (!Prototype.ends_with(")"))47PrintFatalError(Loc, "Expected closing brace at end of prototype");48Prototype = Prototype.drop_back();4950// Look through the input parameters.51const size_t end = Prototype.size();52for (size_t I = 0; I != end;) {53const StringRef Current = Prototype.substr(I, end);54// Skip any leading space or commas55if (Current.starts_with(" ") || Current.starts_with(",")) {56++I;57continue;58}5960// Check if we are in _ExtVector. We do this first because61// extended vectors are written in template form with the syntax62// _ExtVector< ..., ...>, so we need to make sure we are not63// detecting the comma of the template class as a separator for64// the parameters of the prototype. Note: the assumption is that65// we cannot have nested _ExtVector.66if (Current.starts_with("_ExtVector<")) {67const size_t EndTemplate = Current.find('>', 0);68ParseType(Current.substr(0, EndTemplate + 1));69// Move the prototype beyond _ExtVector<...>70I += EndTemplate + 1;71continue;72}7374// We know that we are past _ExtVector, therefore the first seen75// comma is the boundary of a parameter in the prototype.76if (size_t CommaPos = Current.find(',', 0)) {77if (CommaPos != StringRef::npos) {78StringRef T = Current.substr(0, CommaPos);79ParseType(T);80// Move the prototype beyond the comma.81I += CommaPos + 1;82continue;83}84}8586// No more commas, parse final parameter.87ParseType(Current);88I = end;89}90}9192void ParseType(StringRef T) {93T = T.trim();94if (T.consume_back("*")) {95ParseType(T);96Type += "*";97} else if (T.consume_back("const")) {98ParseType(T);99Type += "C";100} else if (T.consume_back("volatile")) {101ParseType(T);102Type += "D";103} else if (T.consume_back("restrict")) {104ParseType(T);105Type += "R";106} else if (T.consume_back("&")) {107ParseType(T);108Type += "&";109} else if (T.consume_front("long")) {110Type += "L";111ParseType(T);112} else if (T.consume_front("unsigned")) {113Type += "U";114ParseType(T);115} else if (T.consume_front("_Complex")) {116Type += "X";117ParseType(T);118} else if (T.consume_front("_Constant")) {119Type += "I";120ParseType(T);121} else if (T.consume_front("T")) {122if (Substitution.empty())123PrintFatalError(Loc, "Not a template");124ParseType(Substitution);125} else if (T.consume_front("_ExtVector")) {126// Clang extended vector types are mangled as follows:127//128// '_ExtVector<' <lanes> ',' <scalar type> '>'129130// Before parsing T(=<scalar type>), make sure the syntax of131// `_ExtVector<N, T>` is correct...132if (!T.consume_front("<"))133PrintFatalError(Loc, "Expected '<' after '_ExtVector'");134unsigned long long Lanes;135if (llvm::consumeUnsignedInteger(T, 10, Lanes))136PrintFatalError(Loc, "Expected number of lanes after '_ExtVector<'");137Type += "E" + std::to_string(Lanes);138if (!T.consume_front(","))139PrintFatalError(Loc,140"Expected ',' after number of lanes in '_ExtVector<'");141if (!T.consume_back(">"))142PrintFatalError(143Loc, "Expected '>' after scalar type in '_ExtVector<N, type>'");144145// ...all good, we can check if we have a valid `<scalar type>`.146ParseType(T);147} else {148auto ReturnTypeVal = StringSwitch<std::string>(T)149.Case("__builtin_va_list_ref", "A")150.Case("__builtin_va_list", "a")151.Case("__float128", "LLd")152.Case("__fp16", "h")153.Case("__int128_t", "LLLi")154.Case("_Float16", "x")155.Case("bool", "b")156.Case("char", "c")157.Case("constant_CFString", "F")158.Case("double", "d")159.Case("FILE", "P")160.Case("float", "f")161.Case("id", "G")162.Case("int", "i")163.Case("int32_t", "Zi")164.Case("int64_t", "Wi")165.Case("jmp_buf", "J")166.Case("msint32_t", "Ni")167.Case("msuint32_t", "UNi")168.Case("objc_super", "M")169.Case("pid_t", "p")170.Case("ptrdiff_t", "Y")171.Case("SEL", "H")172.Case("short", "s")173.Case("sigjmp_buf", "SJ")174.Case("size_t", "z")175.Case("ucontext_t", "K")176.Case("uint32_t", "UZi")177.Case("uint64_t", "UWi")178.Case("void", "v")179.Case("wchar_t", "w")180.Case("...", ".")181.Default("error");182if (ReturnTypeVal == "error")183PrintFatalError(Loc, "Unknown Type: " + T);184Type += ReturnTypeVal;185}186}187188public:189void Print(llvm::raw_ostream &OS) const { OS << ", \"" << Type << '\"'; }190191private:192SMLoc Loc;193StringRef Substitution;194std::string Type;195};196197class HeaderNameParser {198public:199HeaderNameParser(const Record *Builtin) {200for (char c : Builtin->getValueAsString("Header")) {201if (std::islower(c))202HeaderName += static_cast<char>(std::toupper(c));203else if (c == '.' || c == '_' || c == '/' || c == '-')204HeaderName += '_';205else206PrintFatalError(Builtin->getLoc(), "Unexpected header name");207}208}209210void Print(llvm::raw_ostream &OS) const { OS << HeaderName; }211212private:213std::string HeaderName;214};215216void PrintAttributes(const Record *Builtin, BuiltinType BT,217llvm::raw_ostream &OS) {218OS << '\"';219if (Builtin->isSubClassOf("LibBuiltin")) {220if (BT == BuiltinType::LibBuiltin) {221OS << 'f';222} else {223OS << 'F';224if (Builtin->getValueAsBit("OnlyBuiltinPrefixedAliasIsConstexpr"))225OS << 'E';226}227}228229if (auto NS = Builtin->getValueAsOptionalString("Namespace")) {230if (NS != "std")231PrintFatalError(Builtin->getFieldLoc("Namespace"), "Unknown namespace: ");232OS << "z";233}234235for (const auto *Attr : Builtin->getValueAsListOfDefs("Attributes")) {236OS << Attr->getValueAsString("Mangling");237if (Attr->isSubClassOf("IndexedAttribute"))238OS << ':' << Attr->getValueAsInt("Index") << ':';239}240OS << '\"';241}242243void EmitBuiltinDef(llvm::raw_ostream &OS, StringRef Substitution,244const Record *Builtin, Twine Spelling, BuiltinType BT) {245if (Builtin->getValueAsBit("RequiresUndef"))246OS << "#undef " << Spelling << '\n';247switch (BT) {248case BuiltinType::LibBuiltin:249OS << "LIBBUILTIN";250break;251case BuiltinType::LangBuiltin:252OS << "LANGBUILTIN";253break;254case BuiltinType::Builtin:255OS << "BUILTIN";256break;257case BuiltinType::AtomicBuiltin:258OS << "ATOMIC_BUILTIN";259break;260case BuiltinType::TargetBuiltin:261OS << "TARGET_BUILTIN";262break;263}264265OS << "(" << Spelling;266PrototypeParser{Substitution, Builtin}.Print(OS);267OS << ", ";268PrintAttributes(Builtin, BT, OS);269270switch (BT) {271case BuiltinType::LibBuiltin: {272OS << ", ";273HeaderNameParser{Builtin}.Print(OS);274[[fallthrough]];275}276case BuiltinType::LangBuiltin: {277OS << ", " << Builtin->getValueAsString("Languages");278break;279}280case BuiltinType::TargetBuiltin:281OS << ", \"" << Builtin->getValueAsString("Features") << "\"";282break;283case BuiltinType::AtomicBuiltin:284case BuiltinType::Builtin:285break;286}287OS << ")\n";288}289290struct TemplateInsts {291std::vector<std::string> Substitution;292std::vector<std::string> Affix;293bool IsPrefix;294};295296TemplateInsts getTemplateInsts(const Record *R) {297TemplateInsts temp;298auto Substitutions = R->getValueAsListOfStrings("Substitutions");299auto Affixes = R->getValueAsListOfStrings("Affixes");300temp.IsPrefix = R->getValueAsBit("AsPrefix");301302if (Substitutions.size() != Affixes.size())303PrintFatalError(R->getLoc(), "Substitutions and affixes "304"don't have the same lengths");305306for (auto [Affix, Substitution] : llvm::zip(Affixes, Substitutions)) {307temp.Substitution.emplace_back(Substitution);308temp.Affix.emplace_back(Affix);309}310return temp;311}312313void EmitBuiltin(llvm::raw_ostream &OS, const Record *Builtin) {314TemplateInsts Templates = {};315if (Builtin->isSubClassOf("Template")) {316Templates = getTemplateInsts(Builtin);317} else {318Templates.Affix.emplace_back();319Templates.Substitution.emplace_back();320}321322for (auto [Substitution, Affix] :323llvm::zip(Templates.Substitution, Templates.Affix)) {324for (StringRef Spelling : Builtin->getValueAsListOfStrings("Spellings")) {325auto FullSpelling =326(Templates.IsPrefix ? Affix + Spelling : Spelling + Affix).str();327BuiltinType BT = BuiltinType::Builtin;328if (Builtin->isSubClassOf("AtomicBuiltin")) {329BT = BuiltinType::AtomicBuiltin;330} else if (Builtin->isSubClassOf("LangBuiltin")) {331BT = BuiltinType::LangBuiltin;332} else if (Builtin->isSubClassOf("TargetBuiltin")) {333BT = BuiltinType::TargetBuiltin;334} else if (Builtin->isSubClassOf("LibBuiltin")) {335BT = BuiltinType::LibBuiltin;336if (Builtin->getValueAsBit("AddBuiltinPrefixedAlias"))337EmitBuiltinDef(OS, Substitution, Builtin,338std::string("__builtin_") + FullSpelling,339BuiltinType::Builtin);340}341EmitBuiltinDef(OS, Substitution, Builtin, FullSpelling, BT);342}343}344}345} // namespace346347void clang::EmitClangBuiltins(llvm::RecordKeeper &Records,348llvm::raw_ostream &OS) {349emitSourceFileHeader("List of builtins that Clang recognizes", OS);350351OS << R"c++(352#if defined(BUILTIN) && !defined(LIBBUILTIN)353# define LIBBUILTIN(ID, TYPE, ATTRS, HEADER, BUILTIN_LANG) BUILTIN(ID, TYPE, ATTRS)354#endif355356#if defined(BUILTIN) && !defined(LANGBUILTIN)357# define LANGBUILTIN(ID, TYPE, ATTRS, BUILTIN_LANG) BUILTIN(ID, TYPE, ATTRS)358#endif359360// Some of our atomics builtins are handled by AtomicExpr rather than361// as normal builtin CallExprs. This macro is used for such builtins.362#ifndef ATOMIC_BUILTIN363# define ATOMIC_BUILTIN(ID, TYPE, ATTRS) BUILTIN(ID, TYPE, ATTRS)364#endif365366#if defined(BUILTIN) && !defined(TARGET_BUILTIN)367# define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) BUILTIN(ID, TYPE, ATTRS)368#endif369)c++";370371// AtomicBuiltins are order dependent372// emit them first to make manual checking easier373for (const auto *Builtin : Records.getAllDerivedDefinitions("AtomicBuiltin"))374EmitBuiltin(OS, Builtin);375376for (const auto *Builtin : Records.getAllDerivedDefinitions("Builtin")) {377if (Builtin->isSubClassOf("AtomicBuiltin"))378continue;379EmitBuiltin(OS, Builtin);380}381382for (const auto *Entry : Records.getAllDerivedDefinitions("CustomEntry")) {383OS << Entry->getValueAsString("Entry") << '\n';384}385386OS << R"c++(387#undef ATOMIC_BUILTIN388#undef BUILTIN389#undef LIBBUILTIN390#undef LANGBUILTIN391#undef TARGET_BUILTIN392)c++";393}394395396