brintos

brintos / llvm-project-archived public Read only

0
0
Text · 19.5 KiB · 9b6dd37 Raw
595 lines · cpp
1//===-- ClangBuiltinsEmitter.cpp - Generate Clang builtins tables ---------===//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-exception6//7//===----------------------------------------------------------------------===//8//9// This tablegen backend emits Clang's builtins tables.10//11//===----------------------------------------------------------------------===//12 13#include "TableGenBackends.h"14#include "llvm/ADT/StringExtras.h"15#include "llvm/ADT/StringSwitch.h"16#include "llvm/TableGen/Error.h"17#include "llvm/TableGen/Record.h"18#include "llvm/TableGen/StringToOffsetTable.h"19#include "llvm/TableGen/TableGenBackend.h"20#include <sstream>21 22using namespace llvm;23 24namespace {25enum class BuiltinType {26  Builtin,27  AtomicBuiltin,28  LibBuiltin,29  LangBuiltin,30  TargetBuiltin,31  TargetLibBuiltin,32};33 34class HeaderNameParser {35public:36  HeaderNameParser(const Record *Builtin) {37    for (char c : Builtin->getValueAsString("Header")) {38      if (std::islower(c))39        HeaderName += static_cast<char>(std::toupper(c));40      else if (c == '.' || c == '_' || c == '/' || c == '-')41        HeaderName += '_';42      else43        PrintFatalError(Builtin->getLoc(), "Unexpected header name");44    }45  }46 47  void Print(raw_ostream &OS) const { OS << HeaderName; }48 49private:50  std::string HeaderName;51};52 53struct Builtin {54  BuiltinType BT;55  std::string Name;56  std::string Type;57  std::string Attributes;58 59  const Record *BuiltinRecord;60 61  void EmitEnumerator(llvm::raw_ostream &OS) const {62    OS << "    BI";63    // If there is a required name prefix, include its spelling in the64    // enumerator.65    if (auto *PrefixRecord =66            BuiltinRecord->getValueAsOptionalDef("RequiredNamePrefix"))67      OS << PrefixRecord->getValueAsString("Spelling");68    OS << Name << ",\n";69  }70 71  void EmitInfo(llvm::raw_ostream &OS, const StringToOffsetTable &Table) const {72    OS << "    Builtin::Info{Builtin::Info::StrOffsets{"73       << Table.GetStringOffset(Name) << " /* " << Name << " */, "74       << Table.GetStringOffset(Type) << " /* " << Type << " */, "75       << Table.GetStringOffset(Attributes) << " /* " << Attributes << " */, ";76    if (BT == BuiltinType::TargetBuiltin) {77      const auto &Features = BuiltinRecord->getValueAsString("Features");78      OS << Table.GetStringOffset(Features) << " /* " << Features << " */";79    } else {80      OS << "0";81    }82    OS << "}, ";83    if (BT == BuiltinType::LibBuiltin || BT == BuiltinType::TargetLibBuiltin) {84      OS << "HeaderDesc::";85      HeaderNameParser{BuiltinRecord}.Print(OS);86    } else {87      OS << "HeaderDesc::NO_HEADER";88    }89    OS << ", ";90    if (BT == BuiltinType::LibBuiltin || BT == BuiltinType::LangBuiltin ||91        BT == BuiltinType::TargetLibBuiltin) {92      OS << BuiltinRecord->getValueAsString("Languages");93    } else {94      OS << "ALL_LANGUAGES";95    }96    OS << "},\n";97  }98 99  void EmitXMacro(llvm::raw_ostream &OS) const {100    if (BuiltinRecord->getValueAsBit("RequiresUndef"))101      OS << "#undef " << Name << '\n';102    switch (BT) {103    case BuiltinType::LibBuiltin:104      OS << "LIBBUILTIN";105      break;106    case BuiltinType::LangBuiltin:107      OS << "LANGBUILTIN";108      break;109    case BuiltinType::Builtin:110      OS << "BUILTIN";111      break;112    case BuiltinType::AtomicBuiltin:113      OS << "ATOMIC_BUILTIN";114      break;115    case BuiltinType::TargetBuiltin:116      OS << "TARGET_BUILTIN";117      break;118    case BuiltinType::TargetLibBuiltin:119      OS << "TARGET_HEADER_BUILTIN";120      break;121    }122 123    OS << "(" << Name << ", \"" << Type << "\", \"" << Attributes << "\"";124 125    switch (BT) {126    case BuiltinType::LibBuiltin: {127      OS << ", ";128      HeaderNameParser{BuiltinRecord}.Print(OS);129      [[fallthrough]];130    }131    case BuiltinType::LangBuiltin: {132      OS << ", " << BuiltinRecord->getValueAsString("Languages");133      break;134    }135    case BuiltinType::TargetLibBuiltin: {136      OS << ", ";137      HeaderNameParser{BuiltinRecord}.Print(OS);138      OS << ", " << BuiltinRecord->getValueAsString("Languages");139      [[fallthrough]];140    }141    case BuiltinType::TargetBuiltin: {142      OS << ", \"" << BuiltinRecord->getValueAsString("Features") << "\"";143      break;144    }145    case BuiltinType::AtomicBuiltin:146    case BuiltinType::Builtin:147      break;148    }149    OS << ")\n";150  }151};152 153class PrototypeParser {154public:155  PrototypeParser(StringRef Substitution, const Record *Builtin)156      : Loc(Builtin->getFieldLoc("Prototype")), Substitution(Substitution),157        EnableOpenCLLong(Builtin->getValueAsBit("EnableOpenCLLong")) {158    ParsePrototype(Builtin->getValueAsString("Prototype"));159  }160 161  std::string takeTypeString() && { return std::move(Type); }162 163private:164  void ParsePrototype(StringRef Prototype) {165    Prototype = Prototype.trim();166 167    // Some builtins don't have an expressible prototype, simply emit an empty168    // string for them.169    if (Prototype.empty()) {170      Type = "";171      return;172    }173 174    ParseTypes(Prototype);175  }176 177  void ParseTypes(StringRef &Prototype) {178    auto ReturnType = Prototype.take_until([](char c) { return c == '('; });179    ParseType(ReturnType);180    Prototype = Prototype.drop_front(ReturnType.size() + 1);181    if (!Prototype.ends_with(")"))182      PrintFatalError(Loc, "Expected closing brace at end of prototype");183    Prototype = Prototype.drop_back();184 185    // Look through the input parameters.186    const size_t end = Prototype.size();187    for (size_t I = 0; I != end;) {188      const StringRef Current = Prototype.substr(I, end);189      // Skip any leading space or commas190      if (Current.starts_with(" ") || Current.starts_with(",")) {191        ++I;192        continue;193      }194 195      // Check if we are in _ExtVector. We do this first because196      // extended vectors are written in template form with the syntax197      // _ExtVector< ..., ...>, so we need to make sure we are not198      // detecting the comma of the template class as a separator for199      // the parameters of the prototype. Note: the assumption is that200      // we cannot have nested _ExtVector.201      if (Current.starts_with("_ExtVector<") ||202          Current.starts_with("_Vector<")) {203        const size_t EndTemplate = Current.find('>', 0);204        ParseType(Current.substr(0, EndTemplate + 1));205        // Move the prototype beyond _ExtVector<...>206        I += EndTemplate + 1;207        continue;208      }209 210      // We know that we are past _ExtVector, therefore the first seen211      // comma is the boundary of a parameter in the prototype.212      if (size_t CommaPos = Current.find(',', 0)) {213        if (CommaPos != StringRef::npos) {214          StringRef T = Current.substr(0, CommaPos);215          ParseType(T);216          // Move the prototype beyond the comma.217          I += CommaPos + 1;218          continue;219        }220      }221 222      // No more commas, parse final parameter.223      ParseType(Current);224      I = end;225    }226  }227 228  void ParseType(StringRef T) {229    T = T.trim();230 231    auto ConsumeAddrSpace = [&]() -> std::optional<unsigned> {232      T = T.trim();233      if (!T.consume_back(">"))234        return std::nullopt;235 236      auto Open = T.find_last_of('<');237      if (Open == StringRef::npos)238        PrintFatalError(Loc, "Mismatched angle-brackets in type");239 240      StringRef ArgStr = T.substr(Open + 1);241      T = T.slice(0, Open);242      if (!T.consume_back("address_space"))243        PrintFatalError(Loc,244                        "Only `address_space<N>` supported as a parameterized "245                        "pointer or reference type qualifier");246 247      unsigned Number = 0;248      if (ArgStr.getAsInteger(10, Number))249        PrintFatalError(250            Loc, "Expected an integer argument to the address_space qualifier");251      if (Number == 0)252        PrintFatalError(Loc, "No need for a qualifier for address space `0`");253      return Number;254    };255 256    if (T.consume_back("*")) {257      // Pointers may have an address space qualifier immediately before them.258      std::optional<unsigned> AS = ConsumeAddrSpace();259      ParseType(T);260      Type += "*";261      if (AS)262        Type += std::to_string(*AS);263    } else if (T.consume_back("const")) {264      ParseType(T);265      Type += "C";266    } else if (T.consume_back("volatile")) {267      ParseType(T);268      Type += "D";269    } else if (T.consume_back("restrict")) {270      ParseType(T);271      Type += "R";272    } else if (T.consume_back("&")) {273      // References may have an address space qualifier immediately before them.274      std::optional<unsigned> AS = ConsumeAddrSpace();275      ParseType(T);276      Type += "&";277      if (AS)278        Type += std::to_string(*AS);279    } else if (T.consume_back(")")) {280      ParseType(T);281      Type += "&";282    } else if (EnableOpenCLLong && T.consume_front("long long")) {283      Type += "O";284      ParseType(T);285    } else if (T.consume_front("long")) {286      Type += "L";287      ParseType(T);288    } else if (T.consume_front("signed")) {289      Type += "S";290      ParseType(T);291    } else if (T.consume_front("unsigned")) {292      Type += "U";293      ParseType(T);294    } else if (T.consume_front("_Complex")) {295      Type += "X";296      ParseType(T);297    } else if (T.consume_front("_Constant")) {298      Type += "I";299      ParseType(T);300    } else if (T.consume_front("T")) {301      if (Substitution.empty())302        PrintFatalError(Loc, "Not a template");303      ParseType(Substitution);304    } else if (auto IsExt = T.consume_front("_ExtVector");305               IsExt || T.consume_front("_Vector")) {306      // Clang extended vector types are mangled as follows:307      //308      // '_ExtVector<' <lanes> ',' <scalar type> '>'309 310      // Before parsing T(=<scalar type>), make sure the syntax of311      // `_ExtVector<N, T>` is correct...312      if (!T.consume_front("<"))313        PrintFatalError(Loc, "Expected '<' after '_ExtVector'");314      unsigned long long Lanes;315      if (consumeUnsignedInteger(T, 10, Lanes))316        PrintFatalError(Loc, "Expected number of lanes after '_ExtVector<'");317      Type += (IsExt ? "E" : "V") + std::to_string(Lanes);318      if (!T.consume_front(","))319        PrintFatalError(Loc,320                        "Expected ',' after number of lanes in '_ExtVector<'");321      if (!T.consume_back(">"))322        PrintFatalError(323            Loc, "Expected '>' after scalar type in '_ExtVector<N, type>'");324 325      // ...all good, we can check if we have a valid `<scalar type>`.326      ParseType(T);327    } else {328      auto ReturnTypeVal = StringSwitch<std::string>(T)329                               .Case("__builtin_va_list_ref", "A")330                               .Case("__builtin_va_list", "a")331                               .Case("__float128", "LLd")332                               .Case("__fp16", "h")333                               .Case("__hlsl_resource_t", "Qr")334                               .Case("__int128_t", "LLLi")335                               .Case("_Float16", "x")336                               .Case("__bf16", "y")337                               .Case("bool", "b")338                               .Case("char", "c")339                               .Case("constant_CFString", "F")340                               .Case("double", "d")341                               .Case("FILE", "P")342                               .Case("float", "f")343                               .Case("id", "G")344                               .Case("int", "i")345                               .Case("int32_t", "Zi")346                               .Case("int64_t", "Wi")347                               .Case("jmp_buf", "J")348                               .Case("msint32_t", "Ni")349                               .Case("msuint32_t", "UNi")350                               .Case("objc_super", "M")351                               .Case("pid_t", "p")352                               .Case("ptrdiff_t", "Y")353                               .Case("SEL", "H")354                               .Case("short", "s")355                               .Case("sigjmp_buf", "SJ")356                               .Case("size_t", "z")357                               .Case("ucontext_t", "K")358                               .Case("uint32_t", "UZi")359                               .Case("uint64_t", "UWi")360                               .Case("void", "v")361                               .Case("wchar_t", "w")362                               .Case("...", ".")363                               .Default("error");364      if (ReturnTypeVal == "error")365        PrintFatalError(Loc, "Unknown Type: " + T);366      Type += ReturnTypeVal;367    }368  }369 370  SMLoc Loc;371  StringRef Substitution;372  bool EnableOpenCLLong;373  std::string Type;374};375 376std::string renderAttributes(const Record *Builtin, BuiltinType BT) {377  std::string Attributes;378  raw_string_ostream OS(Attributes);379  if (Builtin->isSubClassOf("LibBuiltin")) {380    if (BT == BuiltinType::LibBuiltin) {381      OS << 'f';382    } else {383      OS << 'F';384      if (Builtin->getValueAsBit("OnlyBuiltinPrefixedAliasIsConstexpr"))385        OS << 'E';386    }387  }388 389  if (auto NS = Builtin->getValueAsOptionalString("Namespace")) {390    if (NS != "std")391      PrintFatalError(Builtin->getFieldLoc("Namespace"), "Unknown namespace: ");392    OS << "z";393  }394 395  for (const auto *Attr : Builtin->getValueAsListOfDefs("Attributes")) {396    OS << Attr->getValueAsString("Mangling");397    if (Attr->isSubClassOf("IndexedAttribute")) {398      OS << ':' << Attr->getValueAsInt("Index") << ':';399    } else if (Attr->isSubClassOf("MultiIndexAttribute")) {400      OS << '<';401      llvm::ListSeparator Sep(",");402      for (int64_t Index : Attr->getValueAsListOfInts("Indices"))403        OS << Sep << Index;404      OS << '>';405    }406  }407  return Attributes;408}409 410Builtin buildBuiltin(StringRef Substitution, const Record *BuiltinRecord,411                     Twine Spelling, BuiltinType BT) {412  Builtin B;413  B.BT = BT;414  B.Name = Spelling.str();415  B.Type = PrototypeParser(Substitution, BuiltinRecord).takeTypeString();416  B.Attributes = renderAttributes(BuiltinRecord, BT);417  B.BuiltinRecord = BuiltinRecord;418  return B;419}420 421struct TemplateInsts {422  std::vector<std::string> Substitution;423  std::vector<std::string> Affix;424  bool IsPrefix;425};426 427TemplateInsts getTemplateInsts(const Record *R) {428  TemplateInsts temp;429  auto Substitutions = R->getValueAsListOfStrings("Substitutions");430  auto Affixes = R->getValueAsListOfStrings("Affixes");431  temp.IsPrefix = R->getValueAsBit("AsPrefix");432 433  if (Substitutions.size() != Affixes.size())434    PrintFatalError(R->getLoc(), "Substitutions and affixes "435                                 "don't have the same lengths");436 437  for (auto [Affix, Substitution] : zip(Affixes, Substitutions)) {438    temp.Substitution.emplace_back(Substitution);439    temp.Affix.emplace_back(Affix);440  }441  return temp;442}443 444void collectBuiltins(const Record *BuiltinRecord,445                     SmallVectorImpl<Builtin> &Builtins) {446  TemplateInsts Templates = {};447  if (BuiltinRecord->isSubClassOf("Template")) {448    Templates = getTemplateInsts(BuiltinRecord);449  } else {450    Templates.Affix.emplace_back();451    Templates.Substitution.emplace_back();452  }453 454  for (auto [Substitution, Affix] :455       zip(Templates.Substitution, Templates.Affix)) {456    for (StringRef Spelling :457         BuiltinRecord->getValueAsListOfStrings("Spellings")) {458      auto FullSpelling =459          (Templates.IsPrefix ? Affix + Spelling : Spelling + Affix).str();460      BuiltinType BT = BuiltinType::Builtin;461      if (BuiltinRecord->isSubClassOf("AtomicBuiltin")) {462        BT = BuiltinType::AtomicBuiltin;463      } else if (BuiltinRecord->isSubClassOf("LangBuiltin")) {464        BT = BuiltinType::LangBuiltin;465      } else if (BuiltinRecord->isSubClassOf("TargetLibBuiltin")) {466        BT = BuiltinType::TargetLibBuiltin;467      } else if (BuiltinRecord->isSubClassOf("TargetBuiltin")) {468        BT = BuiltinType::TargetBuiltin;469      } else if (BuiltinRecord->isSubClassOf("LibBuiltin")) {470        BT = BuiltinType::LibBuiltin;471        if (BuiltinRecord->getValueAsBit("AddBuiltinPrefixedAlias"))472          Builtins.push_back(buildBuiltin(473              Substitution, BuiltinRecord,474              std::string("__builtin_") + FullSpelling, BuiltinType::Builtin));475      }476      Builtins.push_back(477          buildBuiltin(Substitution, BuiltinRecord, FullSpelling, BT));478    }479  }480}481} // namespace482 483void clang::EmitClangBuiltins(const RecordKeeper &Records, raw_ostream &OS) {484  emitSourceFileHeader("List of builtins that Clang recognizes", OS);485 486  SmallVector<Builtin> Builtins;487  // AtomicBuiltins are order dependent. Emit them first to make manual checking488  // easier and so we can build a special atomic builtin X-macro.489  for (const auto *BuiltinRecord :490       Records.getAllDerivedDefinitions("AtomicBuiltin"))491    collectBuiltins(BuiltinRecord, Builtins);492  unsigned NumAtomicBuiltins = Builtins.size();493 494  for (const auto *BuiltinRecord :495       Records.getAllDerivedDefinitions("Builtin")) {496    if (BuiltinRecord->isSubClassOf("AtomicBuiltin"))497      continue;498    // Prefixed builtins are also special and we emit them last so they can have499    // their own representation that skips the prefix.500    if (BuiltinRecord->getValueAsOptionalDef("RequiredNamePrefix"))501      continue;502 503    collectBuiltins(BuiltinRecord, Builtins);504  }505 506  // Now collect (and count) the prefixed builtins.507  unsigned NumPrefixedBuiltins = Builtins.size();508  const Record *FirstPrefix = nullptr;509  for (const auto *BuiltinRecord :510       Records.getAllDerivedDefinitions("Builtin")) {511    auto *Prefix = BuiltinRecord->getValueAsOptionalDef("RequiredNamePrefix");512    if (!Prefix)513      continue;514 515    if (!FirstPrefix)516      FirstPrefix = Prefix;517    assert(Prefix == FirstPrefix &&518           "Multiple distinct prefixes which is not currently supported!");519    assert(!BuiltinRecord->isSubClassOf("AtomicBuiltin") &&520           "Cannot require a name prefix for an atomic builtin.");521    collectBuiltins(BuiltinRecord, Builtins);522  }523  NumPrefixedBuiltins = Builtins.size() - NumPrefixedBuiltins;524 525  auto AtomicBuiltins = ArrayRef(Builtins).slice(0, NumAtomicBuiltins);526  auto UnprefixedBuiltins = ArrayRef(Builtins).drop_back(NumPrefixedBuiltins);527  auto PrefixedBuiltins = ArrayRef(Builtins).take_back(NumPrefixedBuiltins);528 529  // Collect strings into a table.530  StringToOffsetTable Table;531  Table.GetOrAddStringOffset("");532  for (const auto &B : Builtins) {533    Table.GetOrAddStringOffset(B.Name);534    Table.GetOrAddStringOffset(B.Type);535    Table.GetOrAddStringOffset(B.Attributes);536    if (B.BT == BuiltinType::TargetBuiltin)537      Table.GetOrAddStringOffset(B.BuiltinRecord->getValueAsString("Features"));538  }539 540  // Emit enumerators.541  OS << R"c++(542#ifdef GET_BUILTIN_ENUMERATORS543)c++";544  for (const auto &B : Builtins)545    B.EmitEnumerator(OS);546  OS << R"c++(547#endif // GET_BUILTIN_ENUMERATORS548)c++";549 550  // Emit a string table that can be referenced for these builtins.551  OS << R"c++(552#ifdef GET_BUILTIN_STR_TABLE553)c++";554  Table.EmitStringTableDef(OS, "BuiltinStrings");555  OS << R"c++(556#endif // GET_BUILTIN_STR_TABLE557)c++";558 559  // Emit a direct set of `Builtin::Info` initializers, first for the unprefixed560  // builtins and then for the prefixed builtins.561  OS << R"c++(562#ifdef GET_BUILTIN_INFOS563)c++";564  for (const auto &B : UnprefixedBuiltins)565    B.EmitInfo(OS, Table);566  OS << R"c++(567#endif // GET_BUILTIN_INFOS568)c++";569 570  OS << R"c++(571#ifdef GET_BUILTIN_PREFIXED_INFOS572)c++";573  for (const auto &B : PrefixedBuiltins)574    B.EmitInfo(OS, Table);575  OS << R"c++(576#endif // GET_BUILTIN_PREFIXED_INFOS577)c++";578 579  // Emit X-macros for the atomic builtins to support various custome patterns580  // used exclusively with those builtins.581  //582  // FIXME: We should eventually move this to a separate file so that users583  // don't need to include the full set of builtins.584  OS << R"c++(585#ifdef ATOMIC_BUILTIN586)c++";587  for (const auto &Builtin : AtomicBuiltins) {588    Builtin.EmitXMacro(OS);589  }590  OS << R"c++(591#endif // ATOMIC_BUILTIN592#undef ATOMIC_BUILTIN593)c++";594}595