Skip to content

Commit 463a2bd

Browse files
authored
[utils][TableGen] Treat clause aliases equally with names (#141763)
The code in DirectiveEmitter that generates clause parsers sorted clause names to ensure that longer names were tried before shorter ones, in cases where a shorter name may be a prefix of a longer one. This matters in the strict Fortran source format, since whitespace is ignored there. This sorting did not take into account clause aliases, which are just alternative names. These extra names were not protected in the same way, and were just appended immediately after the primary name. This patch generates a list of pairs Record+Name, where a given record can appear multiple times with different names. Sort that list and use it to generate parsers for each record. What used to be ``` ("fred" || "f") >> construct<SomeClause>{} || "foo" << construct<OtherClause>{} ``` is now ``` "fred" >> construct<SomeClause>{} || "foo" >> construct<OtherClause>{} || "f" >> construct<SomeClause>{} ```
1 parent a91b0d2 commit 463a2bd

File tree

2 files changed

+42
-37
lines changed

2 files changed

+42
-37
lines changed

llvm/test/TableGen/directive1.td

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ def TDLC_ClauseB : Clause<"clauseb"> {
3434
}
3535

3636
def TDLC_ClauseC : Clause<"clausec"> {
37+
let aliases = ["ccccccc"];
3738
let flangClass = "IntExpr";
3839
let isValueList = 1;
3940
}
@@ -260,7 +261,8 @@ def TDL_DirA : Directive<"dira"> {
260261
// IMPL-NEXT: TYPE_PARSER(
261262
// IMPL-NEXT: "clausec" >> construct<TdlClause>(construct<TdlClause::Clausec>(parenthesized(nonemptyList(Parser<IntExpr>{})))) ||
262263
// IMPL-NEXT: "clauseb" >> construct<TdlClause>(construct<TdlClause::Clauseb>(maybe(parenthesized(Parser<IntExpr>{})))) ||
263-
// IMPL-NEXT: "clausea" >> construct<TdlClause>(construct<TdlClause::Clausea>())
264+
// IMPL-NEXT: "clausea" >> construct<TdlClause>(construct<TdlClause::Clausea>()) ||
265+
// IMPL-NEXT: "ccccccc" >> construct<TdlClause>(construct<TdlClause::Clausec>(parenthesized(nonemptyList(Parser<IntExpr>{}))))
264266
// IMPL-NEXT: )
265267
// IMPL-EMPTY:
266268
// IMPL-NEXT: #endif // GEN_FLANG_CLAUSES_PARSER

llvm/utils/TableGen/Basic/DirectiveEmitter.cpp

Lines changed: 39 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,7 @@ static void emitLeafTable(const DirectiveLanguage &DirLang, raw_ostream &OS,
608608
std::vector<int> Ordering(Directives.size());
609609
std::iota(Ordering.begin(), Ordering.end(), 0);
610610

611-
sort(Ordering, [&](int A, int B) {
611+
llvm::sort(Ordering, [&](int A, int B) {
612612
auto &LeavesA = LeafTable[A];
613613
auto &LeavesB = LeafTable[B];
614614
int DirA = LeavesA[0], DirB = LeavesB[0];
@@ -1113,59 +1113,63 @@ static void generateFlangClauseParserKindMap(const DirectiveLanguage &DirLang,
11131113
<< " Parser clause\");\n";
11141114
}
11151115

1116-
static bool compareClauseName(const Record *R1, const Record *R2) {
1117-
Clause C1(R1);
1118-
Clause C2(R2);
1119-
return (C1.getName() > C2.getName());
1116+
using RecordWithText = std::pair<const Record *, StringRef>;
1117+
1118+
static bool compareRecordText(const RecordWithText &A,
1119+
const RecordWithText &B) {
1120+
return A.second > B.second;
1121+
}
1122+
1123+
static std::vector<RecordWithText>
1124+
getSpellingTexts(ArrayRef<const Record *> Records) {
1125+
std::vector<RecordWithText> List;
1126+
for (const Record *R : Records) {
1127+
Clause C(R);
1128+
List.push_back(std::make_pair(R, C.getName()));
1129+
llvm::transform(C.getAliases(), std::back_inserter(List),
1130+
[R](StringRef S) { return std::make_pair(R, S); });
1131+
}
1132+
return List;
11201133
}
11211134

11221135
// Generate the parser for the clauses.
11231136
static void generateFlangClausesParser(const DirectiveLanguage &DirLang,
11241137
raw_ostream &OS) {
11251138
std::vector<const Record *> Clauses = DirLang.getClauses();
1126-
// Sort clauses in reverse alphabetical order so with clauses with same
1127-
// beginning, the longer option is tried before.
1128-
sort(Clauses, compareClauseName);
1139+
// Sort clauses in the reverse alphabetical order with respect to their
1140+
// names and aliases, so that longer names are tried before shorter ones.
1141+
std::vector<std::pair<const Record *, StringRef>> Names =
1142+
getSpellingTexts(Clauses);
1143+
llvm::sort(Names, compareRecordText);
11291144
IfDefScope Scope("GEN_FLANG_CLAUSES_PARSER", OS);
11301145
StringRef Base = DirLang.getFlangClauseBaseClass();
11311146

1147+
unsigned LastIndex = Names.size() - 1;
11321148
OS << "\n";
1133-
unsigned Index = 0;
1134-
unsigned LastClauseIndex = Clauses.size() - 1;
11351149
OS << "TYPE_PARSER(\n";
1136-
for (const Clause Clause : Clauses) {
1137-
const std::vector<StringRef> &Aliases = Clause.getAliases();
1138-
if (Aliases.empty()) {
1139-
OS << " \"" << Clause.getName() << "\"";
1140-
} else {
1141-
OS << " ("
1142-
<< "\"" << Clause.getName() << "\"_tok";
1143-
for (StringRef Alias : Aliases) {
1144-
OS << " || \"" << Alias << "\"_tok";
1145-
}
1146-
OS << ")";
1147-
}
1150+
for (auto [Index, RecTxt] : llvm::enumerate(Names)) {
1151+
auto [R, N] = RecTxt;
1152+
Clause C(R);
11481153

1149-
StringRef FlangClass = Clause.getFlangClass();
1150-
OS << " >> construct<" << Base << ">(construct<" << Base
1151-
<< "::" << Clause.getFormattedParserClassName() << ">(";
1154+
StringRef FlangClass = C.getFlangClass();
1155+
OS << " \"" << N << "\" >> construct<" << Base << ">(construct<" << Base
1156+
<< "::" << C.getFormattedParserClassName() << ">(";
11521157
if (FlangClass.empty()) {
11531158
OS << "))";
1154-
if (Index != LastClauseIndex)
1159+
if (Index != LastIndex)
11551160
OS << " ||";
11561161
OS << "\n";
1157-
++Index;
11581162
continue;
11591163
}
11601164

1161-
if (Clause.isValueOptional())
1165+
if (C.isValueOptional())
11621166
OS << "maybe(";
11631167
OS << "parenthesized(";
1164-
if (Clause.isValueList())
1168+
if (C.isValueList())
11651169
OS << "nonemptyList(";
11661170

1167-
if (!Clause.getPrefix().empty())
1168-
OS << "\"" << Clause.getPrefix() << ":\" >> ";
1171+
if (!C.getPrefix().empty())
1172+
OS << "\"" << C.getPrefix() << ":\" >> ";
11691173

11701174
// The common Flang parser are used directly. Their name is identical to
11711175
// the Flang class with first letter as lowercase. If the Flang class is
@@ -1181,19 +1185,18 @@ static void generateFlangClausesParser(const DirectiveLanguage &DirLang,
11811185
.Case("ScalarLogicalExpr", "scalarLogicalExpr")
11821186
.Default(("Parser<" + FlangClass + ">{}").toStringRef(Scratch));
11831187
OS << Parser;
1184-
if (!Clause.getPrefix().empty() && Clause.isPrefixOptional())
1188+
if (!C.getPrefix().empty() && C.isPrefixOptional())
11851189
OS << " || " << Parser;
1186-
if (Clause.isValueList()) // close nonemptyList(.
1190+
if (C.isValueList()) // close nonemptyList(.
11871191
OS << ")";
11881192
OS << ")"; // close parenthesized(.
11891193

1190-
if (Clause.isValueOptional()) // close maybe(.
1194+
if (C.isValueOptional()) // close maybe(.
11911195
OS << ")";
11921196
OS << "))";
1193-
if (Index != LastClauseIndex)
1197+
if (Index != LastIndex)
11941198
OS << " ||";
11951199
OS << "\n";
1196-
++Index;
11971200
}
11981201
OS << ")\n";
11991202
}

0 commit comments

Comments
 (0)