| 1 | //==--- Traits.td - Generate expression and type traits -------------------===// |
| 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-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #include "TableGenBackends.h" |
| 10 | #include "llvm/ADT/ArrayRef.h" |
| 11 | #include "llvm/ADT/STLExtras.h" |
| 12 | #include "llvm/ADT/StringRef.h" |
| 13 | #include "llvm/ADT/StringSwitch.h" |
| 14 | #include "llvm/Support/ErrorHandling.h" |
| 15 | #include "llvm/Support/raw_ostream.h" |
| 16 | #include "llvm/TableGen/Record.h" |
| 17 | #include "llvm/TableGen/TableGenBackend.h" |
| 18 | |
| 19 | using namespace llvm; |
| 20 | |
| 21 | namespace { |
| 22 | |
| 23 | std::vector<const Record *> |
| 24 | getAllDerivedDefsInDeclOrder(const RecordKeeper &Records, StringRef ClassName) { |
| 25 | std::vector<const Record *> Defs = |
| 26 | Records.getAllDerivedDefinitions(ClassName); |
| 27 | llvm::sort(C&: Defs, Comp: [](const Record *A, const Record *B) { |
| 28 | return A->getID() < B->getID(); |
| 29 | }); |
| 30 | return Defs; |
| 31 | } |
| 32 | |
| 33 | void emitKeyFlags(ArrayRef<const Record *> KeyFlags, raw_ostream &OS) { |
| 34 | assert(!KeyFlags.empty() && "KeyFlags should never be empty" ); |
| 35 | interleave( |
| 36 | c: KeyFlags, os&: OS, each_fn: [&](const Record *KeyFlag) { OS << KeyFlag->getName(); }, |
| 37 | separator: " | " ); |
| 38 | } |
| 39 | |
| 40 | StringRef recordKindToMacro(const Record *R) { |
| 41 | auto const Macro = |
| 42 | StringSwitch<StringRef>(R->getType()->getAsString()) |
| 43 | .Case(S: "UnaryTrait" , Value: "TYPE_TRAIT_1" ) |
| 44 | .Case(S: "BinaryTrait" , Value: "TYPE_TRAIT_2" ) |
| 45 | .Case(S: "VariadicTrait" , Value: "TYPE_TRAIT_N" ) |
| 46 | .Case(S: "ArrayTrait" , Value: "ARRAY_TYPE_TRAIT" ) |
| 47 | .Case(S: "ExpressionTrait" , Value: "EXPRESSION_TRAIT" ) |
| 48 | .Case(S: "UnaryExprOrTypeTrait" , Value: "UNARY_EXPR_OR_TYPE_TRAIT" ) |
| 49 | .Case(S: "CXX11UnaryExprOrTypeTrait" , Value: "CXX11_UNARY_EXPR_OR_TYPE_TRAIT" ) |
| 50 | .Case(S: "TransformTypeTrait" , Value: "TRANSFORM_TYPE_TRAIT_DEF" ) |
| 51 | .Case(S: "Alias" , Value: "ALIAS" ) |
| 52 | .Default(Value: "" ); |
| 53 | assert(!Macro.empty() && "unexpected record class" ); |
| 54 | return Macro; |
| 55 | } |
| 56 | |
| 57 | void emitMacro(const Record *R, raw_ostream &OS) { |
| 58 | OS << recordKindToMacro(R) << "(" ; |
| 59 | if (R->isSubClassOf(Name: "TransformTypeTrait" )) { |
| 60 | const StringRef StdName = R->getValueAsString(FieldName: "StdName" ); |
| 61 | OS << R->getName() << ", " << StdName; |
| 62 | } else if (R->isSubClassOf(Name: "Alias" )) { |
| 63 | const Record *Primary = R->getValueAsDef(FieldName: "Primary" ); |
| 64 | OS << "\"" << R->getValueAsString(FieldName: "Spelling" ) << "\", " |
| 65 | << Primary->getValueAsString(FieldName: "Spelling" ) << ", " ; |
| 66 | emitKeyFlags(KeyFlags: R->getValueAsListOfDefs(FieldName: "KeyFlags" ), OS); |
| 67 | } else { |
| 68 | OS << R->getValueAsString(FieldName: "Spelling" ) << ", " << R->getName() << ", " ; |
| 69 | emitKeyFlags(KeyFlags: R->getValueAsListOfDefs(FieldName: "KeyFlags" ), OS); |
| 70 | } |
| 71 | OS << ")\n" ; |
| 72 | } |
| 73 | |
| 74 | void emitMacroDefs(const RecordKeeper &Records, raw_ostream &OS) { |
| 75 | constexpr std::pair<StringRef, StringRef> MacroDefs[] = { |
| 76 | {"TYPE_TRAIT_1" , "(I,E,K)" }, |
| 77 | {"TYPE_TRAIT_2" , "(I,E,K)" }, |
| 78 | {"TYPE_TRAIT_N" , "(I,E,K)" }, |
| 79 | {"ARRAY_TYPE_TRAIT" , "(I,E,K)" }, |
| 80 | {"UNARY_EXPR_OR_TYPE_TRAIT" , "(I,E,K)" }, |
| 81 | {"CXX11_UNARY_EXPR_OR_TYPE_TRAIT" , "(I,E,K)" }, |
| 82 | {"EXPRESSION_TRAIT" , "(I,E,K)" }, |
| 83 | {"TRANSFORM_TYPE_TRAIT_DEF" , "(K, Trait)" }, |
| 84 | {"ALIAS" , "(X,Y,Z)" }}; |
| 85 | |
| 86 | for (const auto &[MacroName, MacroArgs] : MacroDefs) { |
| 87 | OS << "#ifndef " << MacroName << "\n" |
| 88 | << "#define " << MacroName << MacroArgs << "\n" |
| 89 | << "#endif\n" ; |
| 90 | } |
| 91 | |
| 92 | OS << '\n'; |
| 93 | |
| 94 | const auto Traits = getAllDerivedDefsInDeclOrder(Records, ClassName: "Trait" ); |
| 95 | const auto Aliases = getAllDerivedDefsInDeclOrder(Records, ClassName: "Alias" ); |
| 96 | for (const Record *R : concat<const Record *const>(Ranges: Traits, Ranges: Aliases)) |
| 97 | emitMacro(R, OS); |
| 98 | |
| 99 | for (const auto &[MacroName, _] : reverse(C: MacroDefs)) |
| 100 | OS << "#undef " << MacroName << "\n" ; |
| 101 | } |
| 102 | |
| 103 | template <typename RangeT> |
| 104 | void emitEnumerators(raw_ostream &OS, RangeT &&Range) { |
| 105 | for (const Record *R : Range) |
| 106 | OS << " " << R->getValueAsString(FieldName: "Prefix" ) << '_' << R->getName() << ",\n" ; |
| 107 | } |
| 108 | |
| 109 | void emitEnums(const RecordKeeper &Records, raw_ostream &OS) { |
| 110 | const auto UnaryTraits = getAllDerivedDefsInDeclOrder(Records, ClassName: "UnaryTrait" ); |
| 111 | const auto BinaryTraits = |
| 112 | getAllDerivedDefsInDeclOrder(Records, ClassName: "BinaryTrait" ); |
| 113 | const auto VariadicTraits = |
| 114 | getAllDerivedDefsInDeclOrder(Records, ClassName: "VariadicTrait" ); |
| 115 | |
| 116 | OS << "/// Names for traits that operate specifically on types.\n" |
| 117 | "enum TypeTrait {\n" ; |
| 118 | emitEnumerators(OS, Range: UnaryTraits); |
| 119 | OS << " UTT_Last = " << UnaryTraits.size() - 1 |
| 120 | << ", // UTT_Last == last UTT_XX in the enum.\n" ; |
| 121 | |
| 122 | emitEnumerators(OS, Range: BinaryTraits); |
| 123 | OS << " BTT_Last = " << UnaryTraits.size() + BinaryTraits.size() - 1 |
| 124 | << ", // BTT_Last == last BTT_XX in the enum.\n" ; |
| 125 | |
| 126 | emitEnumerators(OS, Range: VariadicTraits); |
| 127 | OS << " TT_Last = " |
| 128 | << UnaryTraits.size() + BinaryTraits.size() + VariadicTraits.size() - 1 |
| 129 | << " // TT_Last == last TT_XX in the enum.\n" |
| 130 | << "};\n\n" ; |
| 131 | |
| 132 | const auto ArrayTraits = getAllDerivedDefsInDeclOrder(Records, ClassName: "ArrayTrait" ); |
| 133 | OS << "/// Names for the array type traits.\n" |
| 134 | "enum ArrayTypeTrait {\n" ; |
| 135 | emitEnumerators(OS, Range: ArrayTraits); |
| 136 | OS << " ATT_Last = " << ArrayTraits.size() - 1 |
| 137 | << " // ATT_Last == last ATT\n" |
| 138 | << "};\n\n" ; |
| 139 | |
| 140 | const auto UETTs = |
| 141 | getAllDerivedDefsInDeclOrder(Records, ClassName: "UnaryExprOrTypeTrait" ); |
| 142 | const auto CXX11UETTs = |
| 143 | getAllDerivedDefsInDeclOrder(Records, ClassName: "CXX11UnaryExprOrTypeTrait" ); |
| 144 | OS << "/// Names for the \"expression or type\" traits.\n" |
| 145 | "enum UnaryExprOrTypeTrait {\n" ; |
| 146 | emitEnumerators(OS, Range: concat<const Record *const>(Ranges: UETTs, Ranges: CXX11UETTs)); |
| 147 | OS << " UETT_Last = " << UETTs.size() + CXX11UETTs.size() - 1 |
| 148 | << " // UETT_Last == last UETT_XX in the enum.\n" |
| 149 | << "};\n\n" ; |
| 150 | } |
| 151 | |
| 152 | template <typename RangeT> |
| 153 | void emitNamesAndSpellings(raw_ostream &OS, StringRef Name, RangeT Range) { |
| 154 | OS << "static constexpr const char *" << Name << "Names[] = {\n" ; |
| 155 | for (const Record *R : Range) { |
| 156 | OS << " \"" << R->getName() << "\",\n" ; |
| 157 | } |
| 158 | OS << "};\n\n" ; |
| 159 | |
| 160 | OS << "static constexpr const char *" << Name << "Spellings[] = {\n" ; |
| 161 | for (const Record *R : Range) { |
| 162 | OS << " \"" << R->getValueAsString(FieldName: "Spelling" ) << "\",\n" ; |
| 163 | } |
| 164 | OS << "};\n\n" ; |
| 165 | } |
| 166 | |
| 167 | void emitArrays(const RecordKeeper &Records, raw_ostream &OS) { |
| 168 | const auto UnaryTraits = getAllDerivedDefsInDeclOrder(Records, ClassName: "UnaryTrait" ); |
| 169 | const auto BinaryTraits = |
| 170 | getAllDerivedDefsInDeclOrder(Records, ClassName: "BinaryTrait" ); |
| 171 | const auto VariadicTraits = |
| 172 | getAllDerivedDefsInDeclOrder(Records, ClassName: "VariadicTrait" ); |
| 173 | |
| 174 | emitNamesAndSpellings( |
| 175 | OS, Name: "TypeTrait" , |
| 176 | Range: concat<const Record *const>(Ranges: UnaryTraits, Ranges: BinaryTraits, Ranges: VariadicTraits)); |
| 177 | |
| 178 | OS << "static constexpr const unsigned TypeTraitArities[] = {\n" ; |
| 179 | interleaveComma(c: UnaryTraits, os&: OS, each_fn: [&](auto) { OS << '1'; }); |
| 180 | if (!UnaryTraits.empty()) |
| 181 | OS << ",\n" ; |
| 182 | interleaveComma(c: BinaryTraits, os&: OS, each_fn: [&](auto) { OS << '2'; }); |
| 183 | if (!BinaryTraits.empty()) |
| 184 | OS << ",\n" ; |
| 185 | interleaveComma(c: VariadicTraits, os&: OS, each_fn: [&](auto) { OS << '0'; }); |
| 186 | OS << "\n};\n\n" ; |
| 187 | |
| 188 | emitNamesAndSpellings(OS, Name: "ArrayTypeTrait" , |
| 189 | Range: getAllDerivedDefsInDeclOrder(Records, ClassName: "ArrayTrait" )); |
| 190 | emitNamesAndSpellings( |
| 191 | OS, Name: "UnaryExprOrTypeTrait" , |
| 192 | Range: concat<const Record *const>( |
| 193 | Ranges: getAllDerivedDefsInDeclOrder(Records, ClassName: "UnaryExprOrTypeTrait" ), |
| 194 | Ranges: getAllDerivedDefsInDeclOrder(Records, ClassName: "CXX11UnaryExprOrTypeTrait" ))); |
| 195 | } |
| 196 | |
| 197 | void emitStdNameCases(const RecordKeeper &Records, raw_ostream &OS) { |
| 198 | for (const Record *R : getAllDerivedDefsInDeclOrder(Records, ClassName: "TypeTrait" )) { |
| 199 | const StringRef StdName = R->getValueAsString(FieldName: "StdName" ); |
| 200 | if (StdName.empty()) |
| 201 | continue; |
| 202 | |
| 203 | OS << " .Case(\"" << StdName |
| 204 | << "\", TypeTrait::" << R->getValueAsString(FieldName: "Prefix" ) << '_' |
| 205 | << R->getName() << ")\n" ; |
| 206 | } |
| 207 | } |
| 208 | |
| 209 | } // namespace |
| 210 | |
| 211 | void clang::EmitClangTraits(const RecordKeeper &Records, raw_ostream &OS) { |
| 212 | emitSourceFileHeader(Desc: "Type and expression traits" , OS, Record: Records); |
| 213 | OS << "#if defined(EMIT_ENUMS)\n" ; |
| 214 | emitEnums(Records, OS); |
| 215 | |
| 216 | OS << "#elif defined(EMIT_ARRAYS)\n" ; |
| 217 | emitArrays(Records, OS); |
| 218 | |
| 219 | OS << "#elif defined(EMIT_STD_NAME_CASES)\n" ; |
| 220 | emitStdNameCases(Records, OS); |
| 221 | |
| 222 | OS << "#else\n" ; |
| 223 | emitMacroDefs(Records, OS); |
| 224 | |
| 225 | OS << "#endif\n\n" |
| 226 | << R"( |
| 227 | #undef EMIT_ARRAYS |
| 228 | #undef EMIT_ENUMS |
| 229 | #undef EMIT_STD_NAME_CASES |
| 230 | |
| 231 | )" ; |
| 232 | } |
| 233 | |