| //==--- Traits.td - Generate expression and type traits -------------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "TableGenBackends.h" | |
| #include "llvm/ADT/ArrayRef.h" | |
| #include "llvm/ADT/STLExtras.h" | |
| #include "llvm/ADT/StringRef.h" | |
| #include "llvm/ADT/StringSwitch.h" | |
| #include "llvm/Support/ErrorHandling.h" | |
| #include "llvm/Support/raw_ostream.h" | |
| #include "llvm/TableGen/Record.h" | |
| #include "llvm/TableGen/TableGenBackend.h" | |
| using namespace llvm; | |
| namespace { | |
| std::vector<const Record *> | |
| getAllDerivedDefsInDeclOrder(const RecordKeeper &Records, StringRef ClassName) { | |
| std::vector<const Record *> Defs = | |
| Records.getAllDerivedDefinitions(ClassName); | |
| llvm::sort(Defs, [](const Record *A, const Record *B) { | |
| return A->getID() < B->getID(); | |
| }); | |
| return Defs; | |
| } | |
| void emitKeyFlags(ArrayRef<const Record *> KeyFlags, raw_ostream &OS) { | |
| assert(!KeyFlags.empty() && "KeyFlags should never be empty"); | |
| interleave( | |
| KeyFlags, OS, [&](const Record *KeyFlag) { OS << KeyFlag->getName(); }, | |
| " | "); | |
| } | |
| StringRef recordKindToMacro(const Record *R) { | |
| auto const Macro = | |
| StringSwitch<StringRef>(R->getType()->getAsString()) | |
| .Case("UnaryTrait", "TYPE_TRAIT_1") | |
| .Case("BinaryTrait", "TYPE_TRAIT_2") | |
| .Case("VariadicTrait", "TYPE_TRAIT_N") | |
| .Case("ArrayTrait", "ARRAY_TYPE_TRAIT") | |
| .Case("ExpressionTrait", "EXPRESSION_TRAIT") | |
| .Case("UnaryExprOrTypeTrait", "UNARY_EXPR_OR_TYPE_TRAIT") | |
| .Case("CXX11UnaryExprOrTypeTrait", "CXX11_UNARY_EXPR_OR_TYPE_TRAIT") | |
| .Case("TransformTypeTrait", "TRANSFORM_TYPE_TRAIT_DEF") | |
| .Case("Alias", "ALIAS") | |
| .Default(""); | |
| assert(!Macro.empty() && "unexpected record class"); | |
| return Macro; | |
| } | |
| void emitTokenKey(const RecordKeeper &Records, raw_ostream &OS) { | |
| for (const Record *R : getAllDerivedDefsInDeclOrder(Records, "TokenKey")) { | |
| OS << " " << R->getName() << " = " << R->getValueAsInt("Value") << ",\n"; | |
| } | |
| } | |
| void emitMacro(const Record *R, raw_ostream &OS) { | |
| OS << recordKindToMacro(R) << "("; | |
| if (R->isSubClassOf("TransformTypeTrait")) { | |
| const StringRef StdName = R->getValueAsString("StdName"); | |
| OS << R->getName() << ", " << StdName; | |
| } else if (R->isSubClassOf("Alias")) { | |
| const Record *Primary = R->getValueAsDef("Primary"); | |
| OS << "\"" << R->getValueAsString("Spelling") << "\", " | |
| << Primary->getValueAsString("Spelling") << ", "; | |
| emitKeyFlags(R->getValueAsListOfDefs("KeyFlags"), OS); | |
| } else { | |
| OS << R->getValueAsString("Spelling") << ", " << R->getName() << ", "; | |
| emitKeyFlags(R->getValueAsListOfDefs("KeyFlags"), OS); | |
| } | |
| OS << ")\n"; | |
| } | |
| void emitMacroDefs(const RecordKeeper &Records, raw_ostream &OS) { | |
| constexpr std::pair<StringRef, StringRef> MacroDefs[] = { | |
| {"TYPE_TRAIT_1", "(I,E,K)"}, | |
| {"TYPE_TRAIT_2", "(I,E,K)"}, | |
| {"TYPE_TRAIT_N", "(I,E,K)"}, | |
| {"ARRAY_TYPE_TRAIT", "(I,E,K)"}, | |
| {"UNARY_EXPR_OR_TYPE_TRAIT", "(I,E,K)"}, | |
| {"CXX11_UNARY_EXPR_OR_TYPE_TRAIT", "(I,E,K)"}, | |
| {"EXPRESSION_TRAIT", "(I,E,K)"}, | |
| {"TRANSFORM_TYPE_TRAIT_DEF", "(K, Trait)"}, | |
| {"ALIAS", "(X,Y,Z)"}}; | |
| for (const auto &[MacroName, MacroArgs] : MacroDefs) { | |
| OS << "#ifndef " << MacroName << "\n" | |
| << "#define " << MacroName << MacroArgs << "\n" | |
| << "#endif\n"; | |
| } | |
| OS << '\n'; | |
| const auto Traits = getAllDerivedDefsInDeclOrder(Records, "Trait"); | |
| const auto Aliases = getAllDerivedDefsInDeclOrder(Records, "Alias"); | |
| for (const Record *R : concat<const Record *const>(Traits, Aliases)) | |
| emitMacro(R, OS); | |
| for (const auto &[MacroName, _] : reverse(MacroDefs)) | |
| OS << "#undef " << MacroName << "\n"; | |
| } | |
| template <typename RangeT> | |
| void emitEnumerators(raw_ostream &OS, RangeT &&Range) { | |
| for (const Record *R : Range) | |
| OS << " " << R->getValueAsString("Prefix") << '_' << R->getName() << ",\n"; | |
| } | |
| void emitEnums(const RecordKeeper &Records, raw_ostream &OS) { | |
| const auto UnaryTraits = getAllDerivedDefsInDeclOrder(Records, "UnaryTrait"); | |
| const auto BinaryTraits = | |
| getAllDerivedDefsInDeclOrder(Records, "BinaryTrait"); | |
| const auto VariadicTraits = | |
| getAllDerivedDefsInDeclOrder(Records, "VariadicTrait"); | |
| OS << "/// Names for traits that operate specifically on types.\n" | |
| "enum TypeTrait {\n"; | |
| emitEnumerators(OS, UnaryTraits); | |
| OS << " UTT_Last = " << UnaryTraits.size() - 1 | |
| << ", // UTT_Last == last UTT_XX in the enum.\n"; | |
| emitEnumerators(OS, BinaryTraits); | |
| OS << " BTT_Last = " << UnaryTraits.size() + BinaryTraits.size() - 1 | |
| << ", // BTT_Last == last BTT_XX in the enum.\n"; | |
| emitEnumerators(OS, VariadicTraits); | |
| OS << " TT_Last = " | |
| << UnaryTraits.size() + BinaryTraits.size() + VariadicTraits.size() - 1 | |
| << " // TT_Last == last TT_XX in the enum.\n" | |
| << "};\n\n"; | |
| const auto ArrayTraits = getAllDerivedDefsInDeclOrder(Records, "ArrayTrait"); | |
| OS << "/// Names for the array type traits.\n" | |
| "enum ArrayTypeTrait {\n"; | |
| emitEnumerators(OS, ArrayTraits); | |
| OS << " ATT_Last = " << ArrayTraits.size() - 1 | |
| << " // ATT_Last == last ATT\n" | |
| << "};\n\n"; | |
| const auto UETTs = | |
| getAllDerivedDefsInDeclOrder(Records, "UnaryExprOrTypeTrait"); | |
| const auto CXX11UETTs = | |
| getAllDerivedDefsInDeclOrder(Records, "CXX11UnaryExprOrTypeTrait"); | |
| OS << "/// Names for the \"expression or type\" traits.\n" | |
| "enum UnaryExprOrTypeTrait {\n"; | |
| emitEnumerators(OS, concat<const Record *const>(UETTs, CXX11UETTs)); | |
| OS << " UETT_Last = " << UETTs.size() + CXX11UETTs.size() - 1 | |
| << " // UETT_Last == last UETT_XX in the enum.\n" | |
| << "};\n\n"; | |
| const auto ExpressionTraits = | |
| getAllDerivedDefsInDeclOrder(Records, "ExpressionTrait"); | |
| OS << "/// Names for the expression traits.\n" | |
| "enum ExpressionTrait {\n"; | |
| emitEnumerators(OS, ExpressionTraits); | |
| OS << " ET_Last = " << ExpressionTraits.size() - 1 | |
| << " // ET_Last == last ET_XX in the enum.\n" | |
| << "};\n\n"; | |
| } | |
| template <typename RangeT> | |
| void emitNamesAndSpellings(raw_ostream &OS, StringRef Name, RangeT Range) { | |
| OS << "static constexpr const char *" << Name << "Names[] = {\n"; | |
| for (const Record *R : Range) { | |
| OS << " \"" << R->getName() << "\",\n"; | |
| } | |
| OS << "};\n\n"; | |
| OS << "static constexpr const char *" << Name << "Spellings[] = {\n"; | |
| for (const Record *R : Range) { | |
| OS << " \"" << R->getValueAsString("Spelling") << "\",\n"; | |
| } | |
| OS << "};\n\n"; | |
| } | |
| void emitArrays(const RecordKeeper &Records, raw_ostream &OS) { | |
| const auto UnaryTraits = getAllDerivedDefsInDeclOrder(Records, "UnaryTrait"); | |
| const auto BinaryTraits = | |
| getAllDerivedDefsInDeclOrder(Records, "BinaryTrait"); | |
| const auto VariadicTraits = | |
| getAllDerivedDefsInDeclOrder(Records, "VariadicTrait"); | |
| emitNamesAndSpellings( | |
| OS, "TypeTrait", | |
| concat<const Record *const>(UnaryTraits, BinaryTraits, VariadicTraits)); | |
| OS << "static constexpr const unsigned TypeTraitArities[] = {\n"; | |
| interleaveComma(UnaryTraits, OS, [&](auto) { OS << '1'; }); | |
| if (!UnaryTraits.empty()) | |
| OS << ",\n"; | |
| interleaveComma(BinaryTraits, OS, [&](auto) { OS << '2'; }); | |
| if (!BinaryTraits.empty()) | |
| OS << ",\n"; | |
| interleaveComma(VariadicTraits, OS, [&](auto) { OS << '0'; }); | |
| OS << "\n};\n\n"; | |
| emitNamesAndSpellings(OS, "ArrayTypeTrait", | |
| getAllDerivedDefsInDeclOrder(Records, "ArrayTrait")); | |
| emitNamesAndSpellings( | |
| OS, "UnaryExprOrTypeTrait", | |
| concat<const Record *const>( | |
| getAllDerivedDefsInDeclOrder(Records, "UnaryExprOrTypeTrait"), | |
| getAllDerivedDefsInDeclOrder(Records, "CXX11UnaryExprOrTypeTrait"))); | |
| emitNamesAndSpellings( | |
| OS, "ExpressionTrait", | |
| getAllDerivedDefsInDeclOrder(Records, "ExpressionTrait")); | |
| } | |
| void emitStdNameCases(const RecordKeeper &Records, raw_ostream &OS) { | |
| for (const Record *R : getAllDerivedDefsInDeclOrder(Records, "TypeTrait")) { | |
| const StringRef StdName = R->getValueAsString("StdName"); | |
| if (StdName.empty()) | |
| continue; | |
| OS << " .Case(\"" << StdName | |
| << "\", TypeTrait::" << R->getValueAsString("Prefix") << '_' | |
| << R->getName() << ")\n"; | |
| } | |
| } | |
| } // namespace | |
| void clang::EmitClangBuiltinTraits(const RecordKeeper &Records, | |
| raw_ostream &OS) { | |
| emitSourceFileHeader("Type and expression traits", OS, Records); | |
| OS << "#if defined(EMIT_TOKENKEY)\n"; | |
| emitTokenKey(Records, OS); | |
| OS << "#elif defined(EMIT_ENUMS)\n"; | |
| emitEnums(Records, OS); | |
| OS << "#elif defined(EMIT_ARRAYS)\n"; | |
| emitArrays(Records, OS); | |
| OS << "#elif defined(EMIT_STD_NAME_CASES)\n"; | |
| emitStdNameCases(Records, OS); | |
| OS << "#else\n"; | |
| emitMacroDefs(Records, OS); | |
| OS << "#endif\n\n" | |
| << R"( | |
| #undef EMIT_ARRAYS | |
| #undef EMIT_ENUMS | |
| #undef EMIT_STD_NAME_CASES | |
| #undef EMIT_TOKENKEY | |
| )"; | |
| } |