Skip to content

Commit d576537

Browse files
committed
[TableGen] Add a !listremove() bang operator
This patch proposes to add a !listremove() bang operator to allow us to prune list entries by removing any entries from the first list arg that are also contained in the second list arg. The particular use case I have in mind is for improved analysis of x86 scheduler models for which I'm hoping to start using the CodeGenProcModel 'Unsupported' features lists, which lists the ISA features a particular model DOESN'T support - with such a diverse and growing list of x86 ISAs, I don't want to have to update all these lists with every ISA change to every model - so I'm intending to keep a single central list of all x86 features, and then have the each model "remove" the features that it supports via a !listremove() - leaving just the unsupported ones. Differential Revision: https://reviews.llvm.org/D139642
1 parent f3379fe commit d576537

File tree

8 files changed

+152
-54
lines changed

8 files changed

+152
-54
lines changed

llvm/docs/TableGen/ProgRef.rst

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -223,10 +223,10 @@ TableGen provides "bang operators" that have a wide variety of uses:
223223
: !div !empty !eq !filter !find
224224
: !foldl !foreach !ge !getdagop !gt
225225
: !head !if !interleave !isa !le
226-
: !listconcat !listsplat !logtwo !lt !mul
227-
: !ne !not !or !setdagop !shl
228-
: !size !sra !srl !strconcat !sub
229-
: !subst !substr !tail !xor
226+
: !listconcat !listremove !listsplat !logtwo !lt
227+
: !mul !ne !not !or !setdagop
228+
: !shl !size !sra !srl !strconcat
229+
: !sub !subst !substr !tail !xor
230230

231231
The ``!cond`` operator has a slightly different
232232
syntax compared to other bang operators, so it is defined separately:
@@ -1740,6 +1740,10 @@ and non-0 as true.
17401740
This operator concatenates the list arguments *list1*, *list2*, etc., and
17411741
produces the resulting list. The lists must have the same element type.
17421742

1743+
``!listremove(``\ *list1*\ ``,`` *list2*\ ``)``
1744+
This operator returns a copy of *list1* removing all elements that also occur in
1745+
*list2*. The lists must have the same element type.
1746+
17431747
``!listsplat(``\ *value*\ ``,`` *count*\ ``)``
17441748
This operator produces a list of length *count* whose elements are all
17451749
equal to the *value*. For example, ``!listsplat(42, 3)`` results in

llvm/include/llvm/TableGen/Record.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -847,6 +847,7 @@ class BinOpInit : public OpInit, public FoldingSetNode {
847847
SRL,
848848
LISTCONCAT,
849849
LISTSPLAT,
850+
LISTREMOVE,
850851
STRCONCAT,
851852
INTERLEAVE,
852853
CONCAT,
@@ -900,6 +901,8 @@ class BinOpInit : public OpInit, public FoldingSetNode {
900901
Init *getLHS() const { return LHS; }
901902
Init *getRHS() const { return RHS; }
902903

904+
std::optional<bool> CompareInit(unsigned Opc, Init *LHS, Init *RHS) const;
905+
903906
// Fold - If possible, fold this to a simpler init. Return this if not
904907
// possible to fold.
905908
Init *Fold(Record *CurRec) const;

llvm/lib/TableGen/Record.cpp

Lines changed: 102 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1037,7 +1037,83 @@ Init *BinOpInit::getListConcat(TypedInit *LHS, Init *RHS) {
10371037
return BinOpInit::get(BinOpInit::LISTCONCAT, LHS, RHS, LHS->getType());
10381038
}
10391039

1040-
Init *BinOpInit::Fold(Record *CurRec) const {
1040+
std::optional<bool> BinOpInit::CompareInit(unsigned Opc, Init *LHS, Init *RHS) const {
1041+
// First see if we have two bit, bits, or int.
1042+
IntInit *LHSi = dyn_cast_or_null<IntInit>(
1043+
LHS->convertInitializerTo(IntRecTy::get(getRecordKeeper())));
1044+
IntInit *RHSi = dyn_cast_or_null<IntInit>(
1045+
RHS->convertInitializerTo(IntRecTy::get(getRecordKeeper())));
1046+
1047+
if (LHSi && RHSi) {
1048+
bool Result;
1049+
switch (Opc) {
1050+
case EQ:
1051+
Result = LHSi->getValue() == RHSi->getValue();
1052+
break;
1053+
case NE:
1054+
Result = LHSi->getValue() != RHSi->getValue();
1055+
break;
1056+
case LE:
1057+
Result = LHSi->getValue() <= RHSi->getValue();
1058+
break;
1059+
case LT:
1060+
Result = LHSi->getValue() < RHSi->getValue();
1061+
break;
1062+
case GE:
1063+
Result = LHSi->getValue() >= RHSi->getValue();
1064+
break;
1065+
case GT:
1066+
Result = LHSi->getValue() > RHSi->getValue();
1067+
break;
1068+
default:
1069+
llvm_unreachable("unhandled comparison");
1070+
}
1071+
return Result;
1072+
}
1073+
1074+
// Next try strings.
1075+
StringInit *LHSs = dyn_cast<StringInit>(LHS);
1076+
StringInit *RHSs = dyn_cast<StringInit>(RHS);
1077+
1078+
if (LHSs && RHSs) {
1079+
bool Result;
1080+
switch (Opc) {
1081+
case EQ:
1082+
Result = LHSs->getValue() == RHSs->getValue();
1083+
break;
1084+
case NE:
1085+
Result = LHSs->getValue() != RHSs->getValue();
1086+
break;
1087+
case LE:
1088+
Result = LHSs->getValue() <= RHSs->getValue();
1089+
break;
1090+
case LT:
1091+
Result = LHSs->getValue() < RHSs->getValue();
1092+
break;
1093+
case GE:
1094+
Result = LHSs->getValue() >= RHSs->getValue();
1095+
break;
1096+
case GT:
1097+
Result = LHSs->getValue() > RHSs->getValue();
1098+
break;
1099+
default:
1100+
llvm_unreachable("unhandled comparison");
1101+
}
1102+
return Result;
1103+
}
1104+
1105+
// Finally, !eq and !ne can be used with records.
1106+
if (Opc == EQ || Opc == NE) {
1107+
DefInit *LHSd = dyn_cast<DefInit>(LHS);
1108+
DefInit *RHSd = dyn_cast<DefInit>(RHS);
1109+
if (LHSd && RHSd)
1110+
return (Opc == EQ) ? LHSd == RHSd : LHSd != RHSd;
1111+
}
1112+
1113+
return std::nullopt;
1114+
}
1115+
1116+
Init *BinOpInit::Fold(Record *CurRec) const {
10411117
switch (getOpcode()) {
10421118
case CONCAT: {
10431119
DagInit *LHSs = dyn_cast<DagInit>(LHS);
@@ -1091,6 +1167,28 @@ Init *BinOpInit::Fold(Record *CurRec) const {
10911167
}
10921168
break;
10931169
}
1170+
case LISTREMOVE: {
1171+
ListInit *LHSs = dyn_cast<ListInit>(LHS);
1172+
ListInit *RHSs = dyn_cast<ListInit>(RHS);
1173+
if (LHSs && RHSs) {
1174+
SmallVector<Init *, 8> Args;
1175+
for (Init *EltLHS : *LHSs) {
1176+
bool Found = false;
1177+
for (Init *EltRHS : *RHSs) {
1178+
if (std::optional<bool> Result = CompareInit(EQ, EltLHS, EltRHS)) {
1179+
if (*Result) {
1180+
Found = true;
1181+
break;
1182+
}
1183+
}
1184+
}
1185+
if (!Found)
1186+
Args.push_back(EltLHS);
1187+
}
1188+
return ListInit::get(Args, LHSs->getElementType());
1189+
}
1190+
break;
1191+
}
10941192
case STRCONCAT: {
10951193
StringInit *LHSs = dyn_cast<StringInit>(LHS);
10961194
StringInit *RHSs = dyn_cast<StringInit>(RHS);
@@ -1118,53 +1216,8 @@ Init *BinOpInit::Fold(Record *CurRec) const {
11181216
case LT:
11191217
case GE:
11201218
case GT: {
1121-
// First see if we have two bit, bits, or int.
1122-
IntInit *LHSi = dyn_cast_or_null<IntInit>(
1123-
LHS->convertInitializerTo(IntRecTy::get(getRecordKeeper())));
1124-
IntInit *RHSi = dyn_cast_or_null<IntInit>(
1125-
RHS->convertInitializerTo(IntRecTy::get(getRecordKeeper())));
1126-
1127-
if (LHSi && RHSi) {
1128-
bool Result;
1129-
switch (getOpcode()) {
1130-
case EQ: Result = LHSi->getValue() == RHSi->getValue(); break;
1131-
case NE: Result = LHSi->getValue() != RHSi->getValue(); break;
1132-
case LE: Result = LHSi->getValue() <= RHSi->getValue(); break;
1133-
case LT: Result = LHSi->getValue() < RHSi->getValue(); break;
1134-
case GE: Result = LHSi->getValue() >= RHSi->getValue(); break;
1135-
case GT: Result = LHSi->getValue() > RHSi->getValue(); break;
1136-
default: llvm_unreachable("unhandled comparison");
1137-
}
1138-
return BitInit::get(getRecordKeeper(), Result);
1139-
}
1140-
1141-
// Next try strings.
1142-
StringInit *LHSs = dyn_cast<StringInit>(LHS);
1143-
StringInit *RHSs = dyn_cast<StringInit>(RHS);
1144-
1145-
if (LHSs && RHSs) {
1146-
bool Result;
1147-
switch (getOpcode()) {
1148-
case EQ: Result = LHSs->getValue() == RHSs->getValue(); break;
1149-
case NE: Result = LHSs->getValue() != RHSs->getValue(); break;
1150-
case LE: Result = LHSs->getValue() <= RHSs->getValue(); break;
1151-
case LT: Result = LHSs->getValue() < RHSs->getValue(); break;
1152-
case GE: Result = LHSs->getValue() >= RHSs->getValue(); break;
1153-
case GT: Result = LHSs->getValue() > RHSs->getValue(); break;
1154-
default: llvm_unreachable("unhandled comparison");
1155-
}
1156-
return BitInit::get(getRecordKeeper(), Result);
1157-
}
1158-
1159-
// Finally, !eq and !ne can be used with records.
1160-
if (getOpcode() == EQ || getOpcode() == NE) {
1161-
DefInit *LHSd = dyn_cast<DefInit>(LHS);
1162-
DefInit *RHSd = dyn_cast<DefInit>(RHS);
1163-
if (LHSd && RHSd)
1164-
return BitInit::get(getRecordKeeper(),
1165-
(getOpcode() == EQ) ? LHSd == RHSd : LHSd != RHSd);
1166-
}
1167-
1219+
if (std::optional<bool> Result = CompareInit(getOpcode(), LHS, RHS))
1220+
return BitInit::get(getRecordKeeper(), *Result);
11681221
break;
11691222
}
11701223
case SETDAGOP: {
@@ -1260,6 +1313,7 @@ std::string BinOpInit::getAsString() const {
12601313
case GT: Result = "!gt"; break;
12611314
case LISTCONCAT: Result = "!listconcat"; break;
12621315
case LISTSPLAT: Result = "!listsplat"; break;
1316+
case LISTREMOVE: Result = "!listremove"; break;
12631317
case STRCONCAT: Result = "!strconcat"; break;
12641318
case INTERLEAVE: Result = "!interleave"; break;
12651319
case SETDAGOP: Result = "!setdagop"; break;

llvm/lib/TableGen/TGLexer.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,7 @@ tgtok::TokKind TGLexer::LexExclaim() {
584584
.Case("filter", tgtok::XFilter)
585585
.Case("listconcat", tgtok::XListConcat)
586586
.Case("listsplat", tgtok::XListSplat)
587+
.Case("listremove", tgtok::XListRemove)
587588
.Case("strconcat", tgtok::XStrConcat)
588589
.Case("interleave", tgtok::XInterleave)
589590
.Case("substr", tgtok::XSubstr)

llvm/lib/TableGen/TGLexer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ namespace tgtok {
5656
XSHL, XListConcat, XListSplat, XStrConcat, XInterleave, XSubstr, XFind,
5757
XCast, XSubst, XForEach, XFilter, XFoldl, XHead, XTail, XSize, XEmpty, XIf,
5858
XCond, XEq, XIsA, XDag, XNe, XLe, XLt, XGe, XGt, XSetDagOp, XGetDagOp,
59-
XExists,
59+
XExists, XListRemove,
6060

6161
// Boolean literals.
6262
TrueVal, FalseVal,

llvm/lib/TableGen/TGParser.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1179,6 +1179,7 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
11791179
case tgtok::XGt:
11801180
case tgtok::XListConcat:
11811181
case tgtok::XListSplat:
1182+
case tgtok::XListRemove:
11821183
case tgtok::XStrConcat:
11831184
case tgtok::XInterleave:
11841185
case tgtok::XSetDagOp: { // Value ::= !binop '(' Value ',' Value ')'
@@ -1208,6 +1209,7 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
12081209
case tgtok::XGt: Code = BinOpInit::GT; break;
12091210
case tgtok::XListConcat: Code = BinOpInit::LISTCONCAT; break;
12101211
case tgtok::XListSplat: Code = BinOpInit::LISTSPLAT; break;
1212+
case tgtok::XListRemove: Code = BinOpInit::LISTREMOVE; break;
12111213
case tgtok::XStrConcat: Code = BinOpInit::STRCONCAT; break;
12121214
case tgtok::XInterleave: Code = BinOpInit::INTERLEAVE; break;
12131215
case tgtok::XSetDagOp: Code = BinOpInit::SETDAGOP; break;
@@ -1246,12 +1248,16 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
12461248
// ArgType for the comparison operators is not yet known.
12471249
break;
12481250
case tgtok::XListConcat:
1249-
// We don't know the list type until we parse the first argument
1251+
// We don't know the list type until we parse the first argument.
12501252
ArgType = ItemType;
12511253
break;
12521254
case tgtok::XListSplat:
12531255
// Can't do any typechecking until we parse the first argument.
12541256
break;
1257+
case tgtok::XListRemove:
1258+
// We don't know the list type until we parse the first argument.
1259+
ArgType = ItemType;
1260+
break;
12551261
case tgtok::XStrConcat:
12561262
Type = StringRecTy::get(Records);
12571263
ArgType = StringRecTy::get(Records);
@@ -1329,6 +1335,13 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
13291335
}
13301336
ArgType = nullptr; // Broken invariant: types not identical.
13311337
break;
1338+
case BinOpInit::LISTREMOVE:
1339+
if (!isa<ListRecTy>(ArgType)) {
1340+
Error(InitLoc, Twine("expected a list, got value of type '") +
1341+
ArgType->getAsString() + "'");
1342+
return nullptr;
1343+
}
1344+
break;
13321345
case BinOpInit::EQ:
13331346
case BinOpInit::NE:
13341347
if (!ArgType->typeIsConvertibleTo(IntRecTy::get(Records)) &&
@@ -1423,6 +1436,9 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
14231436
// listsplat returns a list of type of the *first* argument.
14241437
if (Code == BinOpInit::LISTSPLAT)
14251438
Type = cast<TypedInit>(InitList.front())->getType()->getListTy();
1439+
// listremove returns a list with type of the argument.
1440+
if (Code == BinOpInit::LISTREMOVE)
1441+
Type = ArgType;
14261442

14271443
// We allow multiple operands to associative operators like !strconcat as
14281444
// shorthand for nesting them.
@@ -2154,6 +2170,7 @@ Init *TGParser::ParseOperationCond(Record *CurRec, RecTy *ItemType) {
21542170
/// SimpleValue ::= SRLTOK '(' Value ',' Value ')'
21552171
/// SimpleValue ::= LISTCONCATTOK '(' Value ',' Value ')'
21562172
/// SimpleValue ::= LISTSPLATTOK '(' Value ',' Value ')'
2173+
/// SimpleValue ::= LISTREMOVETOK '(' Value ',' Value ')'
21572174
/// SimpleValue ::= STRCONCATTOK '(' Value ',' Value ')'
21582175
/// SimpleValue ::= COND '(' [Value ':' Value,]+ ')'
21592176
///
@@ -2453,6 +2470,7 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType,
24532470
case tgtok::XGt:
24542471
case tgtok::XListConcat:
24552472
case tgtok::XListSplat:
2473+
case tgtok::XListRemove:
24562474
case tgtok::XStrConcat:
24572475
case tgtok::XInterleave:
24582476
case tgtok::XSetDagOp: // Value ::= !binop '(' Value ',' Value ')'

llvm/test/TableGen/listremove.td

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// RUN: llvm-tblgen %s | FileCheck %s
2+
3+
// CHECK: class X {
4+
// CHECK: list<string> T0 = ["foo", "bar"];
5+
// CHECK: list<string> T1 = ["foo", "bar"];
6+
// CHECK: list<string> T2 = ["bar"];
7+
// CHECK: list<string> T3 = ["foo"];
8+
// CHECK: list<string> T4 = [];
9+
// CHECK: }
10+
11+
class X {
12+
list<string> T0 = !listremove(["foo", "bar"], []);
13+
list<string> T1 = !listremove(["foo", "bar"], ["baz"]);
14+
list<string> T2 = !listremove(["foo", "bar"], ["foo"]);
15+
list<string> T3 = !listremove(["foo", "bar"], ["bar", "bar"]);
16+
list<string> T4 = !listremove(["foo", "bar"], ["bar", "foo"]);
17+
}

llvm/utils/kate/llvm-tablegen.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
<item> !strconcat </item>
3232
<item> !cast </item>
3333
<item> !listconcat </item>
34+
<item> !listreplace </item>
3435
<item> !listsplat </item>
3536
<item> !size </item>
3637
<item> !foldl </item>

0 commit comments

Comments
 (0)