diff options
Diffstat (limited to 'llvm/utils/TableGen/Basic/DirectiveEmitter.cpp')
| -rw-r--r-- | llvm/utils/TableGen/Basic/DirectiveEmitter.cpp | 264 |
1 files changed, 164 insertions, 100 deletions
diff --git a/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp b/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp index 3d1795c5a6ff..177eecebce9a 100644 --- a/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp +++ b/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp @@ -24,6 +24,7 @@ #include "llvm/TableGen/TableGenBackend.h" #include <numeric> +#include <string> #include <vector> using namespace llvm; @@ -76,6 +77,19 @@ static std::string getIdentifierName(const Record *Rec, StringRef Prefix) { return Prefix.str() + BaseRecord(Rec).getFormattedName(); } +using RecordWithSpelling = std::pair<const Record *, Spelling::Value>; + +static std::vector<RecordWithSpelling> +getSpellings(ArrayRef<const Record *> Records) { + std::vector<RecordWithSpelling> List; + for (const Record *R : Records) { + BaseRecord Rec(R); + llvm::transform(Rec.getSpellings(), std::back_inserter(List), + [R](Spelling::Value V) { return std::make_pair(R, V); }); + } + return List; +} + static void generateEnumExports(ArrayRef<const Record *> Records, raw_ostream &OS, StringRef Enum, StringRef Prefix) { @@ -147,7 +161,7 @@ static void generateEnumBitmask(ArrayRef<const Record *> Records, // Generate enums for values that clauses can take. // Also generate function declarations for get<Enum>Name(StringRef Str). -static void generateEnumClauseVal(ArrayRef<const Record *> Records, +static void generateClauseEnumVal(ArrayRef<const Record *> Records, raw_ostream &OS, const DirectiveLanguage &DirLang, std::string &EnumHelperFuncs) { @@ -166,8 +180,8 @@ static void generateEnumClauseVal(ArrayRef<const Record *> Records, OS << "\n"; OS << "enum class " << Enum << " {\n"; - for (const ClauseVal CVal : ClauseVals) - OS << " " << CVal.getRecordName() << "=" << CVal.getValue() << ",\n"; + for (const EnumVal Val : ClauseVals) + OS << " " << Val.getRecordName() << "=" << Val.getValue() << ",\n"; OS << "};\n"; if (DirLang.hasMakeEnumAvailableInNamespace()) { @@ -193,10 +207,11 @@ static bool hasDuplicateClauses(ArrayRef<const Record *> Clauses, StringSet<> &CrtClauses) { bool HasError = false; for (const VersionedClause VerClause : Clauses) { - const auto InsRes = CrtClauses.insert(VerClause.getClause().getName()); + StringRef Name = VerClause.getClause().getRecordName(); + const auto InsRes = CrtClauses.insert(Name); if (!InsRes.second) { - PrintError("Clause " + VerClause.getClause().getRecordName() + - " already defined on directive " + Directive.getRecordName()); + PrintError("Clause " + Name + " already defined on directive " + + Directive.getRecordName()); HasError = true; } } @@ -267,11 +282,13 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) { if (DirLang.hasEnableBitmaskEnumInNamespace()) OS << "#include \"llvm/ADT/BitmaskEnum.h\"\n"; + OS << "#include \"llvm/ADT/StringRef.h\"\n"; + OS << "#include \"llvm/Frontend/Directive/Spelling.h\"\n"; OS << "#include \"llvm/Support/Compiler.h\"\n"; OS << "#include <cstddef>\n"; // for size_t + OS << "#include <utility>\n"; // for std::pair OS << "\n"; OS << "namespace llvm {\n"; - OS << "class StringRef;\n"; // Open namespaces defined in the directive language SmallVector<StringRef, 2> Namespaces; @@ -306,29 +323,39 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) { DirLang.getClausePrefix(), DirLang.hasMakeEnumAvailableInNamespace()); - // Emit ClauseVal enumeration + // Emit ClauseVals enumeration std::string EnumHelperFuncs; - generateEnumClauseVal(DirLang.getClauses(), OS, DirLang, EnumHelperFuncs); + generateClauseEnumVal(DirLang.getClauses(), OS, DirLang, EnumHelperFuncs); // Generic function signatures OS << "\n"; OS << "// Enumeration helper functions\n"; - OS << "LLVM_ABI Directive get" << Lang << "DirectiveKind(StringRef Str);\n"; + + OS << "LLVM_ABI std::pair<Directive, directive::VersionRange> get" << Lang + << "DirectiveKindAndVersions(StringRef Str);\n"; + + OS << "inline Directive get" << Lang << "DirectiveKind(StringRef Str) {\n"; + OS << " return get" << Lang << "DirectiveKindAndVersions(Str).first;\n"; + OS << "}\n"; OS << "\n"; - // For OpenMP the signature is - // getOpenMPDirectiveName(Directive D, unsigned V) - OS << "LLVM_ABI StringRef get" << DirLang.getName() - << "DirectiveName(Directive D"; - if (DirLang.getCppNamespace() == "omp") - OS << ", unsigned = 0"; - OS << ");\n"; + OS << "LLVM_ABI StringRef get" << Lang + << "DirectiveName(Directive D, unsigned Ver = 0);\n"; OS << "\n"; - OS << "LLVM_ABI Clause get" << Lang << "ClauseKind(StringRef Str);\n"; + OS << "LLVM_ABI std::pair<Clause, directive::VersionRange> get" << Lang + << "ClauseKindAndVersions(StringRef Str);\n"; OS << "\n"; - OS << "LLVM_ABI StringRef get" << Lang << "ClauseName(Clause C);\n"; + + OS << "inline Clause get" << Lang << "ClauseKind(StringRef Str) {\n"; + OS << " return get" << Lang << "ClauseKindAndVersions(Str).first;\n"; + OS << "}\n"; + OS << "\n"; + + OS << "LLVM_ABI StringRef get" << Lang + << "ClauseName(Clause C, unsigned Ver = 0);\n"; OS << "\n"; + OS << "/// Return true if \\p C is a valid clause for \\p D in version \\p " << "Version.\n"; OS << "LLVM_ABI bool isAllowedClauseForDirective(Directive D, " @@ -353,31 +380,60 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) { OS << "#endif // LLVM_" << Lang << "_INC\n"; } +// Given a list of spellings (for a given clause/directive), order them +// in a way that allows the use of binary search to locate a spelling +// for a specified version. +static std::vector<Spelling::Value> +orderSpellings(ArrayRef<Spelling::Value> Spellings) { + std::vector<Spelling::Value> List(Spellings.begin(), Spellings.end()); + + llvm::stable_sort(List, + [](const Spelling::Value &A, const Spelling::Value &B) { + return A.Versions < B.Versions; + }); + return List; +} + // Generate function implementation for get<Enum>Name(StringRef Str) static void generateGetName(ArrayRef<const Record *> Records, raw_ostream &OS, StringRef Enum, const DirectiveLanguage &DirLang, StringRef Prefix) { StringRef Lang = DirLang.getName(); std::string Qual = getQualifier(DirLang); - // For OpenMP the "Directive" signature is - // getOpenMPDirectiveName(Directive D, unsigned V) OS << "\n"; OS << "llvm::StringRef " << Qual << "get" << Lang << Enum << "Name(" << Qual - << Enum << " Kind"; - if (DirLang.getCppNamespace() == "omp" && Enum == "Directive") - OS << ", unsigned"; - OS << ") {\n"; + << Enum << " Kind, unsigned Version) {\n"; OS << " switch (Kind) {\n"; for (const Record *R : Records) { - OS << " case " << getIdentifierName(R, Prefix) << ":\n"; - OS << " return \"" << BaseRecord(R).getName() << "\";\n"; + BaseRecord Rec(R); + std::string Ident = getIdentifierName(R, Prefix); + OS << " case " << Ident << ":"; + std::vector<Spelling::Value> Spellings(orderSpellings(Rec.getSpellings())); + assert(Spellings.size() != 0 && "No spellings for this item"); + if (Spellings.size() == 1) { + OS << "\n"; + OS << " return \"" << Spellings.front().Name << "\";\n"; + } else { + OS << " {\n"; + std::string SpellingsName = Ident + "_spellings"; + OS << " static constexpr llvm::directive::Spelling " << SpellingsName + << "[] = {\n"; + for (auto &S : Spellings) { + OS << " {\"" << S.Name << "\", {" << S.Versions.Min << ", " + << S.Versions.Max << "}},\n"; + } + OS << " };\n"; + OS << " return llvm::directive::FindName(" << SpellingsName + << ", Version);\n"; + OS << " }\n"; + } } OS << " }\n"; // switch OS << " llvm_unreachable(\"Invalid " << Lang << " " << Enum << " kind\");\n"; OS << "}\n"; } -// Generate function implementation for get<Enum>Kind(StringRef Str) +// Generate function implementation for get<Enum>KindAndVersions(StringRef Str) static void generateGetKind(ArrayRef<const Record *> Records, raw_ostream &OS, StringRef Enum, const DirectiveLanguage &DirLang, StringRef Prefix, bool ImplicitAsUnknown) { @@ -394,27 +450,42 @@ static void generateGetKind(ArrayRef<const Record *> Records, raw_ostream &OS, std::string Qual = getQualifier(DirLang); std::string DefaultName = getIdentifierName(*DefaultIt, Prefix); + // std::pair<<Enum>, VersionRange> + // get<DirLang><Enum>KindAndVersions(StringRef Str); OS << "\n"; - OS << Qual << Enum << " " << Qual << "get" << DirLang.getName() << Enum - << "Kind(llvm::StringRef Str) {\n"; - OS << " return StringSwitch<" << Enum << ">(Str)\n"; + OS << "std::pair<" << Qual << Enum << ", llvm::directive::VersionRange> " + << Qual << "get" << DirLang.getName() << Enum + << "KindAndVersions(llvm::StringRef Str) {\n"; + OS << " directive::VersionRange All; // Default-initialized to \"all " + "versions\"\n"; + OS << " return StringSwitch<std::pair<" << Enum << ", " + << "directive::VersionRange>>(Str)\n"; + + directive::VersionRange All; for (const Record *R : Records) { BaseRecord Rec(R); - if (ImplicitAsUnknown && R->getValueAsBit("isImplicit")) { - OS << " .Case(\"" << Rec.getName() << "\"," << DefaultName << ")\n"; - } else { - OS << " .Case(\"" << Rec.getName() << "\"," - << getIdentifierName(R, Prefix) << ")\n"; + std::string Ident = ImplicitAsUnknown && R->getValueAsBit("isImplicit") + ? DefaultName + : getIdentifierName(R, Prefix); + + for (auto &[Name, Versions] : Rec.getSpellings()) { + OS << " .Case(\"" << Name << "\", {" << Ident << ", "; + if (Versions.Min == All.Min && Versions.Max == All.Max) + OS << "All})\n"; + else + OS << "{" << Versions.Min << ", " << Versions.Max << "}})\n"; } } - OS << " .Default(" << DefaultName << ");\n"; + OS << " .Default({" << DefaultName << ", All});\n"; OS << "}\n"; } -// Generate function implementation for get<ClauseVal>Kind(StringRef Str) -static void generateGetKindClauseVal(const DirectiveLanguage &DirLang, - raw_ostream &OS) { +// Generate function implementations for +// <enumClauseValue> get<enumClauseValue>(StringRef Str) and +// StringRef get<enumClauseValue>Name(<enumClauseValue>) +static void generateGetClauseVal(const DirectiveLanguage &DirLang, + raw_ostream &OS) { StringRef Lang = DirLang.getName(); std::string Qual = getQualifier(DirLang); @@ -428,7 +499,7 @@ static void generateGetKindClauseVal(const DirectiveLanguage &DirLang, }); if (DefaultIt == ClauseVals.end()) { - PrintError("At least one val in Clause " + C.getFormattedName() + + PrintError("At least one val in Clause " + C.getRecordName() + " must be defined as default."); return; } @@ -436,8 +507,8 @@ static void generateGetKindClauseVal(const DirectiveLanguage &DirLang, StringRef Enum = C.getEnumName(); if (Enum.empty()) { - PrintError("enumClauseValue field not set in Clause" + - C.getFormattedName() + "."); + PrintError("enumClauseValue field not set in Clause" + C.getRecordName() + + "."); return; } @@ -445,10 +516,9 @@ static void generateGetKindClauseVal(const DirectiveLanguage &DirLang, OS << Qual << Enum << " " << Qual << "get" << Enum << "(llvm::StringRef Str) {\n"; OS << " return StringSwitch<" << Enum << ">(Str)\n"; - for (const auto &CV : ClauseVals) { - ClauseVal CVal(CV); - OS << " .Case(\"" << CVal.getFormattedName() << "\"," << CV->getName() - << ")\n"; + for (const EnumVal Val : ClauseVals) { + OS << " .Case(\"" << Val.getFormattedName() << "\"," + << Val.getRecordName() << ")\n"; } OS << " .Default(" << DefaultName << ");\n"; OS << "}\n"; @@ -457,10 +527,9 @@ static void generateGetKindClauseVal(const DirectiveLanguage &DirLang, OS << "llvm::StringRef " << Qual << "get" << Lang << Enum << "Name(" << Qual << Enum << " x) {\n"; OS << " switch (x) {\n"; - for (const auto &CV : ClauseVals) { - ClauseVal CVal(CV); - OS << " case " << CV->getName() << ":\n"; - OS << " return \"" << CVal.getFormattedName() << "\";\n"; + for (const EnumVal Val : ClauseVals) { + OS << " case " << Val.getRecordName() << ":\n"; + OS << " return \"" << Val.getFormattedName() << "\";\n"; } OS << " }\n"; // switch OS << " llvm_unreachable(\"Invalid " << Lang << " " << Enum @@ -599,7 +668,10 @@ static void emitLeafTable(const DirectiveLanguage &DirLang, raw_ostream &OS, // (such as "end declare target"). DenseSet<int> EndDirectives; for (auto [Rec, Id] : DirId) { - if (Directive(Rec).getName().starts_with_insensitive("end ")) + // FIXME: This will need to recognize different spellings for different + // versions. + StringRef Name = Directive(Rec).getSpellingForIdentifier(); + if (Name.starts_with_insensitive("end ")) EndDirectives.insert(Id); } @@ -608,12 +680,13 @@ static void emitLeafTable(const DirectiveLanguage &DirLang, raw_ostream &OS, std::vector<int> Ordering(Directives.size()); std::iota(Ordering.begin(), Ordering.end(), 0); - sort(Ordering, [&](int A, int B) { + llvm::sort(Ordering, [&](int A, int B) { auto &LeavesA = LeafTable[A]; auto &LeavesB = LeafTable[B]; int DirA = LeavesA[0], DirB = LeavesB[0]; // First of all, end directives compare greater than non-end directives. - int IsEndA = EndDirectives.count(DirA), IsEndB = EndDirectives.count(DirB); + bool IsEndA = EndDirectives.contains(DirA); + bool IsEndB = EndDirectives.contains(DirB); if (IsEndA != IsEndB) return IsEndA < IsEndB; if (LeavesA[1] == 0 && LeavesB[1] == 0) @@ -653,7 +726,7 @@ static void emitLeafTable(const DirectiveLanguage &DirLang, raw_ostream &OS, // Emit a marker where the first "end directive" is. auto FirstE = find_if(Ordering, [&](int RowIdx) { - return EndDirectives.count(LeafTable[RowIdx][0]); + return EndDirectives.contains(LeafTable[RowIdx][0]); }); OS << "[[maybe_unused]] static auto " << TableName << "EndDirective = " << TableName << " + " @@ -710,7 +783,7 @@ static void generateGetDirectiveAssociation(const DirectiveLanguage &DirLang, }; auto ErrorPrefixFor = [&](Directive D) -> std::string { - return (Twine("Directive '") + D.getName() + "' in namespace '" + + return (Twine("Directive '") + D.getRecordName() + "' in namespace '" + DirLang.getCppNamespace() + "' ") .str(); }; @@ -752,7 +825,6 @@ static void generateGetDirectiveAssociation(const DirectiveLanguage &DirLang, // Compute the association from leaf constructs. std::vector<const Record *> Leaves = D.getLeafConstructs(); if (Leaves.empty()) { - errs() << D.getName() << '\n'; PrintFatalError(ErrorPrefixFor(D) + "requests association to be computed from leaves, " "but it has no leaves"); @@ -839,7 +911,7 @@ static void generateGetDirectiveLanguages(const DirectiveLanguage &DirLang, D.getSourceLanguages(), OS, [&](const Record *L) { StringRef N = L->getValueAsString("name"); - OS << "SourceLanguage::" << BaseRecord::formatName(N); + OS << "SourceLanguage::" << BaseRecord::getSnakeName(N); }, " | "); OS << ";\n"; @@ -899,7 +971,7 @@ static void generateDirectiveClauseSets(const DirectiveLanguage &DirLang, for (const Directive Dir : DirLang.getDirectives()) { OS << "\n"; - OS << "// Sets for " << Dir.getName() << "\n"; + OS << "// Sets for " << Dir.getSpellingForIdentifier() << "\n"; generateClauseSet(Dir.getAllowedClauses(), OS, "allowedClauses_", Dir, DirLang, FE); @@ -1034,8 +1106,11 @@ static void generateFlangClauseUnparse(const DirectiveLanguage &DirLang, for (const Clause Clause : DirLang.getClauses()) { if (Clause.skipFlangUnparser()) continue; + // The unparser doesn't know the effective version, so just pick some + // spelling. + StringRef SomeSpelling = Clause.getSpellingForIdentifier(); std::string Parser = Clause.getFormattedParserClassName(); - std::string Upper = Clause.getName().upper(); + std::string Upper = SomeSpelling.upper(); if (!Clause.getFlangClass().empty()) { if (Clause.isValueOptional() && Clause.getDefaultValue().empty()) { @@ -1113,59 +1188,45 @@ static void generateFlangClauseParserKindMap(const DirectiveLanguage &DirLang, << " Parser clause\");\n"; } -static bool compareClauseName(const Record *R1, const Record *R2) { - Clause C1(R1); - Clause C2(R2); - return (C1.getName() > C2.getName()); -} - // Generate the parser for the clauses. static void generateFlangClausesParser(const DirectiveLanguage &DirLang, raw_ostream &OS) { std::vector<const Record *> Clauses = DirLang.getClauses(); - // Sort clauses in reverse alphabetical order so with clauses with same - // beginning, the longer option is tried before. - sort(Clauses, compareClauseName); + // Sort clauses in the reverse alphabetical order with respect to their + // names and aliases, so that longer names are tried before shorter ones. + std::vector<RecordWithSpelling> Names = getSpellings(Clauses); + llvm::sort(Names, [](const auto &A, const auto &B) { + return A.second.Name > B.second.Name; + }); IfDefScope Scope("GEN_FLANG_CLAUSES_PARSER", OS); StringRef Base = DirLang.getFlangClauseBaseClass(); + unsigned LastIndex = Names.size() - 1; OS << "\n"; - unsigned Index = 0; - unsigned LastClauseIndex = Clauses.size() - 1; OS << "TYPE_PARSER(\n"; - for (const Clause Clause : Clauses) { - const std::vector<StringRef> &Aliases = Clause.getAliases(); - if (Aliases.empty()) { - OS << " \"" << Clause.getName() << "\""; - } else { - OS << " (" - << "\"" << Clause.getName() << "\"_tok"; - for (StringRef Alias : Aliases) { - OS << " || \"" << Alias << "\"_tok"; - } - OS << ")"; - } + for (auto [Index, RecSp] : llvm::enumerate(Names)) { + auto [R, S] = RecSp; + Clause C(R); - StringRef FlangClass = Clause.getFlangClass(); - OS << " >> construct<" << Base << ">(construct<" << Base - << "::" << Clause.getFormattedParserClassName() << ">("; + StringRef FlangClass = C.getFlangClass(); + OS << " \"" << S.Name << "\" >> construct<" << Base << ">(construct<" + << Base << "::" << C.getFormattedParserClassName() << ">("; if (FlangClass.empty()) { OS << "))"; - if (Index != LastClauseIndex) + if (Index != LastIndex) OS << " ||"; OS << "\n"; - ++Index; continue; } - if (Clause.isValueOptional()) + if (C.isValueOptional()) OS << "maybe("; OS << "parenthesized("; - if (Clause.isValueList()) + if (C.isValueList()) OS << "nonemptyList("; - if (!Clause.getPrefix().empty()) - OS << "\"" << Clause.getPrefix() << ":\" >> "; + if (!C.getPrefix().empty()) + OS << "\"" << C.getPrefix() << ":\" >> "; // The common Flang parser are used directly. Their name is identical to // the Flang class with first letter as lowercase. If the Flang class is @@ -1181,19 +1242,18 @@ static void generateFlangClausesParser(const DirectiveLanguage &DirLang, .Case("ScalarLogicalExpr", "scalarLogicalExpr") .Default(("Parser<" + FlangClass + ">{}").toStringRef(Scratch)); OS << Parser; - if (!Clause.getPrefix().empty() && Clause.isPrefixOptional()) + if (!C.getPrefix().empty() && C.isPrefixOptional()) OS << " || " << Parser; - if (Clause.isValueList()) // close nonemptyList(. + if (C.isValueList()) // close nonemptyList(. OS << ")"; OS << ")"; // close parenthesized(. - if (Clause.isValueOptional()) // close maybe(. + if (C.isValueOptional()) // close maybe(. OS << ")"; OS << "))"; - if (Index != LastClauseIndex) + if (Index != LastIndex) OS << " ||"; OS << "\n"; - ++Index; } OS << ")\n"; } @@ -1302,7 +1362,10 @@ void emitDirectivesBasicImpl(const DirectiveLanguage &DirLang, StringRef DPrefix = DirLang.getDirectivePrefix(); StringRef CPrefix = DirLang.getClausePrefix(); - OS << "\n#include \"llvm/Support/ErrorHandling.h\"\n"; + OS << "\n"; + OS << "#include \"llvm/Frontend/Directive/Spelling.h\"\n"; + OS << "#include \"llvm/Support/ErrorHandling.h\"\n"; + OS << "#include <utility>\n"; // getDirectiveKind(StringRef Str) generateGetKind(DirLang.getDirectives(), OS, "Directive", DirLang, DPrefix, @@ -1318,8 +1381,9 @@ void emitDirectivesBasicImpl(const DirectiveLanguage &DirLang, // getClauseName(Clause Kind) generateGetName(DirLang.getClauses(), OS, "Clause", DirLang, CPrefix); - // get<ClauseVal>Kind(StringRef Str) - generateGetKindClauseVal(DirLang, OS); + // <enumClauseValue> get<enumClauseValue>(StringRef Str) ; string -> value + // StringRef get<enumClauseValue>Name(<enumClauseValue>) ; value -> string + generateGetClauseVal(DirLang, OS); // isAllowedClauseForDirective(Directive D, Clause C, unsigned Version) generateIsAllowedClause(DirLang, OS); |
