Skip to content

Commit dcc8f94

Browse files
committed
[TableGen] Add !setdagarg and !setdagname
- This patch proposes to add `!setdagarg` and `!setdagname` bang operators to produce a new DAG node after replacing the specified argument value/name from the given input DAG node. E.g., `!setdagarg((foo 1, 2), 0, "x")` produces `(foo "x", 2)` and `!setdagname((foo 1:$a, 2:$b), 1, "c")` produces `(foo 1:$a, 2:$c)`. Reviewed By: simon_tatham Differential Revision: https://reviews.llvm.org/D151842
1 parent 2011ad0 commit dcc8f94

File tree

7 files changed

+203
-47
lines changed

7 files changed

+203
-47
lines changed

llvm/docs/TableGen/ProgRef.rst

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -225,10 +225,10 @@ TableGen provides "bang operators" that have a wide variety of uses:
225225
: !getdagname !getdagop !gt !head !if
226226
: !interleave !isa !le !listconcat !listremove
227227
: !listsplat !logtwo !lt !mul !ne
228-
: !not !or !range !setdagop !shl
229-
: !size !sra !srl !strconcat !sub
230-
: !subst !substr !tail !tolower !toupper
231-
: !xor
228+
: !not !or !range !setdagarg !setdagname
229+
: !setdagop !shl !size !sra !srl
230+
: !strconcat !sub !subst !substr !tail
231+
: !tolower !toupper !xor
232232

233233
The ``!cond`` operator has a slightly different
234234
syntax compared to other bang operators, so it is defined separately:
@@ -1370,7 +1370,7 @@ DAG.
13701370

13711371
The following bang operators are useful for working with DAGs:
13721372
``!con``, ``!dag``, ``!empty``, ``!foreach``, ``!getdagarg``, ``!getdagname``,
1373-
``!getdagop``, ``!setdagop``, ``!size``.
1373+
``!getdagop``, ``!setdagarg``, ``!setdagname``, ``!setdagop``, ``!size``.
13741374

13751375
Defvar in a record body
13761376
-----------------------
@@ -1821,6 +1821,16 @@ and non-0 as true.
18211821
``!range(``\ *list*\ ``)``
18221822
Equivalent to ``!range(0, !size(list))``.
18231823

1824+
``!setdagarg(``\ *dag*\ ``,``\ *key*\ ``,``\ *arg*\ ``)``
1825+
This operator produces a DAG node with the same operator and arguments as
1826+
*dag*, but replacing the value of the argument specified by the *key* with
1827+
*arg*. That *key* could be either an integer index or a string name.
1828+
1829+
``!setdagname(``\ *dag*\ ``,``\ *key*\ ``,``\ *name*\ ``)``
1830+
This operator produces a DAG node with the same operator and arguments as
1831+
*dag*, but replacing the name of the argument specified by the *key* with
1832+
*name*. That *key* could be either an integer index or a string name.
1833+
18241834
``!setdagop(``\ *dag*\ ``,`` *op*\ ``)``
18251835
This operator produces a DAG node with the same arguments as *dag*, but with its
18261836
operator replaced with *op*.

llvm/include/llvm/TableGen/Record.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -918,7 +918,17 @@ class BinOpInit : public OpInit, public FoldingSetNode {
918918
/// !op (X, Y, Z) - Combine two inits.
919919
class TernOpInit : public OpInit, public FoldingSetNode {
920920
public:
921-
enum TernaryOp : uint8_t { SUBST, FOREACH, FILTER, IF, DAG, SUBSTR, FIND };
921+
enum TernaryOp : uint8_t {
922+
SUBST,
923+
FOREACH,
924+
FILTER,
925+
IF,
926+
DAG,
927+
SUBSTR,
928+
FIND,
929+
SETDAGARG,
930+
SETDAGNAME,
931+
};
922932

923933
private:
924934
Init *LHS, *MHS, *RHS;
@@ -1407,6 +1417,10 @@ class DagInit final : public TypedInit, public FoldingSetNode,
14071417
return getTrailingObjects<Init *>()[Num];
14081418
}
14091419

1420+
/// This method looks up the specified argument name and returns its argument
1421+
/// number or std::nullopt if that argument name does not exist.
1422+
std::optional<unsigned> getArgNo(StringRef Name) const;
1423+
14101424
StringInit *getArgName(unsigned Num) const {
14111425
assert(Num < NumArgNames && "Arg number out of range!");
14121426
return getTrailingObjects<StringInit *>()[Num];

llvm/lib/TableGen/Record.cpp

Lines changed: 93 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1109,6 +1109,39 @@ std::optional<bool> BinOpInit::CompareInit(unsigned Opc, Init *LHS,
11091109
return std::nullopt;
11101110
}
11111111

1112+
static std::optional<unsigned> getDagArgNoByKey(DagInit *Dag, Init *Key,
1113+
std::string &Error) {
1114+
// Accessor by index
1115+
if (IntInit *Idx = dyn_cast<IntInit>(Key)) {
1116+
int64_t Pos = Idx->getValue();
1117+
if (Pos < 0) {
1118+
// The index is negative.
1119+
Error =
1120+
(Twine("index ") + std::to_string(Pos) + Twine(" is negative")).str();
1121+
return std::nullopt;
1122+
}
1123+
if (Pos >= Dag->getNumArgs()) {
1124+
// The index is out-of-range.
1125+
Error = (Twine("index ") + std::to_string(Pos) +
1126+
" is out of range (dag has " +
1127+
std::to_string(Dag->getNumArgs()) + " arguments)")
1128+
.str();
1129+
return std::nullopt;
1130+
}
1131+
return Pos;
1132+
}
1133+
assert(isa<StringInit>(Key));
1134+
// Accessor by name
1135+
StringInit *Name = dyn_cast<StringInit>(Key);
1136+
auto ArgNo = Dag->getArgNo(Name->getValue());
1137+
if (!ArgNo) {
1138+
// The key is not found.
1139+
Error = (Twine("key '") + Name->getValue() + Twine("' is not found")).str();
1140+
return std::nullopt;
1141+
}
1142+
return *ArgNo;
1143+
}
1144+
11121145
Init *BinOpInit::Fold(Record *CurRec) const {
11131146
switch (getOpcode()) {
11141147
case CONCAT: {
@@ -1279,51 +1312,19 @@ Init *BinOpInit::Fold(Record *CurRec) const {
12791312
}
12801313
case GETDAGARG: {
12811314
DagInit *Dag = dyn_cast<DagInit>(LHS);
1282-
if (!Dag)
1283-
break;
1315+
if (Dag && isa<IntInit, StringInit>(RHS)) {
1316+
std::string Error;
1317+
auto ArgNo = getDagArgNoByKey(Dag, RHS, Error);
1318+
if (!ArgNo)
1319+
PrintFatalError(CurRec->getLoc(), "!getdagarg " + Error);
1320+
1321+
assert(*ArgNo < Dag->getNumArgs());
12841322

1285-
// Helper returning the specified argument.
1286-
auto getDagArgAsType = [](DagInit *Dag, unsigned Pos,
1287-
RecTy *Type) -> Init * {
1288-
assert(Pos < Dag->getNumArgs());
1289-
Init *Arg = Dag->getArg(Pos);
1323+
Init *Arg = Dag->getArg(*ArgNo);
12901324
if (auto *TI = dyn_cast<TypedInit>(Arg))
1291-
if (!TI->getType()->typeIsConvertibleTo(Type))
1325+
if (!TI->getType()->typeIsConvertibleTo(getType()))
12921326
return UnsetInit::get(Dag->getRecordKeeper());
12931327
return Arg;
1294-
};
1295-
1296-
// Accessor by index
1297-
if (IntInit *Idx = dyn_cast<IntInit>(RHS)) {
1298-
int64_t Pos = Idx->getValue();
1299-
if (Pos < 0) {
1300-
// The index is negative.
1301-
PrintFatalError(CurRec->getLoc(), Twine("!getdagarg index ") +
1302-
std::to_string(Pos) +
1303-
Twine(" is negative"));
1304-
}
1305-
if (Pos >= Dag->getNumArgs()) {
1306-
// The index is out-of-range.
1307-
PrintFatalError(CurRec->getLoc(),
1308-
Twine("!getdagarg index ") + std::to_string(Pos) +
1309-
" is out of range (dag has " +
1310-
std::to_string(Dag->getNumArgs()) + " arguments)");
1311-
}
1312-
return getDagArgAsType(Dag, Pos, getType());
1313-
}
1314-
// Accessor by name
1315-
if (StringInit *Key = dyn_cast<StringInit>(RHS)) {
1316-
for (unsigned i = 0, e = Dag->getNumArgs(); i < e; ++i) {
1317-
StringInit *ArgName = Dag->getArgName(i);
1318-
if (!ArgName || ArgName->getValue() != Key->getValue())
1319-
continue;
1320-
// Found
1321-
return getDagArgAsType(Dag, i, getType());
1322-
}
1323-
// The key is not found.
1324-
PrintFatalError(CurRec->getLoc(), Twine("!getdagarg key '") +
1325-
Key->getValue() +
1326-
Twine("' is not found"));
13271328
}
13281329
break;
13291330
}
@@ -1702,6 +1703,42 @@ Init *TernOpInit::Fold(Record *CurRec) const {
17021703
}
17031704
break;
17041705
}
1706+
1707+
case SETDAGARG: {
1708+
DagInit *Dag = dyn_cast<DagInit>(LHS);
1709+
if (Dag && isa<IntInit, StringInit>(MHS)) {
1710+
std::string Error;
1711+
auto ArgNo = getDagArgNoByKey(Dag, MHS, Error);
1712+
if (!ArgNo)
1713+
PrintFatalError(CurRec->getLoc(), "!setdagarg " + Error);
1714+
1715+
assert(*ArgNo < Dag->getNumArgs());
1716+
1717+
SmallVector<Init *, 8> Args(Dag->getArgs());
1718+
SmallVector<StringInit *, 8> Names(Dag->getArgNames());
1719+
Args[*ArgNo] = RHS;
1720+
return DagInit::get(Dag->getOperator(), Dag->getName(), Args, Names);
1721+
}
1722+
break;
1723+
}
1724+
1725+
case SETDAGNAME: {
1726+
DagInit *Dag = dyn_cast<DagInit>(LHS);
1727+
if (Dag && isa<IntInit, StringInit>(MHS)) {
1728+
std::string Error;
1729+
auto ArgNo = getDagArgNoByKey(Dag, MHS, Error);
1730+
if (!ArgNo)
1731+
PrintFatalError(CurRec->getLoc(), "!setdagname " + Error);
1732+
1733+
assert(*ArgNo < Dag->getNumArgs());
1734+
1735+
SmallVector<Init *, 8> Args(Dag->getArgs());
1736+
SmallVector<StringInit *, 8> Names(Dag->getArgNames());
1737+
Names[*ArgNo] = dyn_cast<StringInit>(RHS);
1738+
return DagInit::get(Dag->getOperator(), Dag->getName(), Args, Names);
1739+
}
1740+
break;
1741+
}
17051742
}
17061743

17071744
return const_cast<TernOpInit *>(this);
@@ -1748,6 +1785,12 @@ std::string TernOpInit::getAsString() const {
17481785
case SUBST: Result = "!subst"; break;
17491786
case SUBSTR: Result = "!substr"; break;
17501787
case FIND: Result = "!find"; break;
1788+
case SETDAGARG:
1789+
Result = "!setdagarg";
1790+
break;
1791+
case SETDAGNAME:
1792+
Result = "!setdagname";
1793+
break;
17511794
}
17521795
return (Result + "(" +
17531796
(UnquotedLHS ? LHS->getAsUnquotedString() : LHS->getAsString()) +
@@ -2462,6 +2505,15 @@ Record *DagInit::getOperatorAsDef(ArrayRef<SMLoc> Loc) const {
24622505
return nullptr;
24632506
}
24642507

2508+
std::optional<unsigned> DagInit::getArgNo(StringRef Name) const {
2509+
for (unsigned i = 0, e = getNumArgs(); i < e; ++i) {
2510+
StringInit *ArgName = getArgName(i);
2511+
if (ArgName && ArgName->getValue() == Name)
2512+
return i;
2513+
}
2514+
return std::nullopt;
2515+
}
2516+
24652517
Init *DagInit::resolveReferences(Resolver &R) const {
24662518
SmallVector<Init*, 8> NewArgs;
24672519
NewArgs.reserve(arg_size());

llvm/lib/TableGen/TGLexer.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,8 @@ tgtok::TokKind TGLexer::LexExclaim() {
594594
.Cases("getdagop", "getop", tgtok::XGetDagOp) // !getop is deprecated.
595595
.Case("getdagarg", tgtok::XGetDagArg)
596596
.Case("getdagname", tgtok::XGetDagName)
597+
.Case("setdagarg", tgtok::XSetDagArg)
598+
.Case("setdagname", tgtok::XSetDagName)
597599
.Case("exists", tgtok::XExists)
598600
.Case("tolower", tgtok::XToLower)
599601
.Case("toupper", tgtok::XToUpper)

llvm/lib/TableGen/TGLexer.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@ enum TokKind {
129129
XRange,
130130
XGetDagArg,
131131
XGetDagName,
132+
XSetDagArg,
133+
XSetDagName,
132134

133135
// Boolean literals.
134136
TrueVal,

llvm/lib/TableGen/TGParser.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1769,6 +1769,8 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
17691769
return ParseOperationForEachFilter(CurRec, ItemType);
17701770
}
17711771

1772+
case tgtok::XSetDagArg:
1773+
case tgtok::XSetDagName:
17721774
case tgtok::XDag:
17731775
case tgtok::XIf:
17741776
case tgtok::XSubst: { // Value ::= !ternop '(' Value ',' Value ',' Value ')'
@@ -1790,6 +1792,16 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
17901792
case tgtok::XSubst:
17911793
Code = TernOpInit::SUBST;
17921794
break;
1795+
case tgtok::XSetDagArg:
1796+
Code = TernOpInit::SETDAGARG;
1797+
Type = DagRecTy::get(Records);
1798+
ItemType = nullptr;
1799+
break;
1800+
case tgtok::XSetDagName:
1801+
Code = TernOpInit::SETDAGNAME;
1802+
Type = DagRecTy::get(Records);
1803+
ItemType = nullptr;
1804+
break;
17931805
}
17941806
if (!consume(tgtok::l_paren)) {
17951807
TokError("expected '(' after ternary operator");
@@ -1902,6 +1914,35 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
19021914
Type = RHSt->getType();
19031915
break;
19041916
}
1917+
case tgtok::XSetDagArg: {
1918+
TypedInit *MHSt = dyn_cast<TypedInit>(MHS);
1919+
if (!MHSt || !isa<IntRecTy, StringRecTy>(MHSt->getType())) {
1920+
Error(MHSLoc, Twine("expected integer index or string name, got ") +
1921+
(MHSt ? ("type '" + MHSt->getType()->getAsString())
1922+
: ("'" + MHS->getAsString())) +
1923+
"'");
1924+
return nullptr;
1925+
}
1926+
break;
1927+
}
1928+
case tgtok::XSetDagName: {
1929+
TypedInit *MHSt = dyn_cast<TypedInit>(MHS);
1930+
if (!MHSt || !isa<IntRecTy, StringRecTy>(MHSt->getType())) {
1931+
Error(MHSLoc, Twine("expected integer index or string name, got ") +
1932+
(MHSt ? ("type '" + MHSt->getType()->getAsString())
1933+
: ("'" + MHS->getAsString())) +
1934+
"'");
1935+
return nullptr;
1936+
}
1937+
TypedInit *RHSt = dyn_cast<TypedInit>(RHS);
1938+
// The name could be a string or unset.
1939+
if (RHSt && !isa<StringRecTy>(RHSt->getType())) {
1940+
Error(RHSLoc, Twine("expected string or unset name, got type '") +
1941+
RHSt->getType()->getAsString() + "'");
1942+
return nullptr;
1943+
}
1944+
break;
1945+
}
19051946
}
19061947
return (TernOpInit::get(Code, LHS, MHS, RHS, Type))->Fold(CurRec);
19071948
}
@@ -2787,6 +2828,8 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType,
27872828
case tgtok::XGetDagArg:
27882829
case tgtok::XGetDagName:
27892830
case tgtok::XSetDagOp: // Value ::= !binop '(' Value ',' Value ')'
2831+
case tgtok::XSetDagArg:
2832+
case tgtok::XSetDagName:
27902833
case tgtok::XIf:
27912834
case tgtok::XCond:
27922835
case tgtok::XFoldl:

llvm/test/TableGen/getsetop.td

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
// RUN: not llvm-tblgen -DERROR4 %s 2>&1 | FileCheck --check-prefix=ERROR4 %s
66
// RUN: not llvm-tblgen -DERROR5 %s 2>&1 | FileCheck --check-prefix=ERROR5 %s
77
// RUN: not llvm-tblgen -DERROR6 %s 2>&1 | FileCheck --check-prefix=ERROR6 %s
8+
// RUN: not llvm-tblgen -DERROR7 %s 2>&1 | FileCheck --check-prefix=ERROR7 %s
9+
// RUN: not llvm-tblgen -DERROR8 %s 2>&1 | FileCheck --check-prefix=ERROR8 %s
10+
// RUN: not llvm-tblgen -DERROR9 %s 2>&1 | FileCheck --check-prefix=ERROR9 %s
811

912
// !setop and !getop are deprecated in favor of !setdagop and !getdagop.
1013
// Two tests retain the old names just to be sure they are still supported.
@@ -114,4 +117,34 @@ def test {
114117
dag in6 = (foo alice:$a, bob:$b);
115118
// CHECK: Base base = bob;
116119
Base base = !getdagarg<Base>(in6, 1);
120+
121+
// CHECK: dag orig_set_val = (foo 1, 2:$a, "val":$b);
122+
dag orig_set_val = !setdagarg(orig, 2, "val");
123+
// CHECK: dag orig_set_val_by_name = (foo 1, 2:$a, "aval":$b);
124+
dag orig_set_val_by_name = !setdagarg(orig, "b", "aval");
125+
// CHECK: dag orig_set_dag_val = (foo 1, 2:$a, (bar foo:$p, qux:$q):$b);
126+
dag orig_set_dag_val = !setdagarg(orig, "b", (bar foo:$p, qux:$q));
127+
// CHECK: dag orig_clr_val = (foo 1, ?:$a, ?:$b);
128+
dag orig_clr_val = !setdagarg(orig, "a", ?);
129+
// CHECK: dag orig_set_name = (foo 1:$c, 2:$a, ?:$b);
130+
dag orig_set_name = !setdagname(orig, 0, "c");
131+
// CHECK: dag orig_clr_name = (foo 1, 2, ?:$b);
132+
dag orig_clr_name = !setdagname(orig, 1, ?);
133+
// CHECK: dag orig_rename = (foo 1, 2:$x, ?:$y);
134+
dag orig_rename = !setdagname(!setdagname(orig, "a", "x"), "b", "y");
135+
136+
#ifdef ERROR7
137+
// ERROR7: error: !setdagarg index -1 is negative
138+
dag orig_negative = !setdagarg(orig, -1, "val");
139+
#endif
140+
141+
#ifdef ERROR8
142+
// ERROR8: error: !setdagarg index 3 is out of range (dag has 3 arguments)
143+
dag orig_out_of_range = !setdagarg(orig, 3, "val");
144+
#endif
145+
146+
#ifdef ERROR9
147+
// ERROR9: error: expected integer index or string name, got type 'Base'
148+
dag orig_out_of_range = !setdagarg(orig, foo, (foo qux:$a));
149+
#endif
117150
}

0 commit comments

Comments
 (0)