blob: d02f3cf821e1d53957e02a616f97bbdf16c3f01e [file] [edit]
//==--- 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::EmitClangTraits(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
)";
}