Skip to content

Commit 1fed9a0

Browse files
committed
[TableGen] Add bang-operators !getop and !setop.
Summary: These allow you to get and set the operator of a dag node, without affecting its list of arguments. `!getop` is slightly fiddly because in many contexts you need its return value to have a static type more specific than 'any record'. It works to say `!cast<BaseClass>(!getop(...))`, but it's cumbersome, so I made `!getop` take an optional type suffix itself, so that can be written as the shorter `!getop<BaseClass>(...)`. Reviewers: hfinkel, nhaehnle Reviewed By: nhaehnle Subscribers: hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D71191
1 parent afb13af commit 1fed9a0

File tree

8 files changed

+172
-10
lines changed

8 files changed

+172
-10
lines changed

llvm/docs/TableGen/LangIntro.rst

+28
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,34 @@ supported include:
183183
Example: !dag(op, [a1, a2, ?], ["name1", "name2", "name3"]) results in
184184
(op a1:$name1, a2:$name2, ?:$name3).
185185

186+
``!setop(dag, op)``
187+
Return a DAG node with the same arguments as ``dag``, but with its
188+
operator replaced with ``op``.
189+
190+
Example: ``!setop((foo 1, 2), bar)`` results in ``(bar 1, 2)``.
191+
192+
``!getop(dag)``
193+
194+
``!getop<type>(dag)``
195+
Return the operator of the given DAG node.
196+
Example: ``!getop((foo 1, 2))`` results in ``foo``.
197+
198+
The result of ``!getop`` can be used directly in a context where
199+
any record value at all is acceptable (typically placing it into
200+
another dag value). But in other contexts, it must be explicitly
201+
cast to a particular class type. The ``!getop<type>`` syntax is
202+
provided to make this easy.
203+
204+
For example, to assign the result to a class-typed value, you
205+
could write either of these:
206+
``BaseClass b = !getop<BaseClass>(someDag);``
207+
208+
``BaseClass b = !cast<BaseClass>(!getop(someDag));``
209+
210+
But to build a new dag node reusing the operator from another, no
211+
cast is necessary:
212+
``dag d = !dag(!getop(someDag), args, names);``
213+
186214
``!listconcat(a, b, ...)``
187215
A list value that is the result of concatenating the 'a' and 'b' lists.
188216
The lists must have the same element type.

llvm/docs/TableGen/LangRef.rst

+2-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ wide variety of meanings:
100100
:!or !empty !subst !foreach !strconcat
101101
:!cast !listconcat !size !foldl
102102
:!isa !dag !le !lt !ge
103-
:!gt !ne !mul !listsplat
103+
:!gt !ne !mul !listsplat !setop
104+
:!getop
104105

105106
TableGen also has !cond operator that needs a slightly different
106107
syntax compared to other "bang operators":

llvm/include/llvm/TableGen/Record.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -751,7 +751,7 @@ class OpInit : public TypedInit {
751751
///
752752
class UnOpInit : public OpInit, public FoldingSetNode {
753753
public:
754-
enum UnaryOp : uint8_t { CAST, HEAD, TAIL, SIZE, EMPTY };
754+
enum UnaryOp : uint8_t { CAST, HEAD, TAIL, SIZE, EMPTY, GETOP };
755755

756756
private:
757757
Init *LHS;
@@ -802,7 +802,7 @@ class BinOpInit : public OpInit, public FoldingSetNode {
802802
public:
803803
enum BinaryOp : uint8_t { ADD, MUL, AND, OR, SHL, SRA, SRL, LISTCONCAT,
804804
LISTSPLAT, STRCONCAT, CONCAT, EQ, NE, LE, LT, GE,
805-
GT };
805+
GT, SETOP };
806806

807807
private:
808808
Init *LHS, *RHS;

llvm/lib/TableGen/Record.cpp

+31
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,21 @@ Init *UnOpInit::Fold(Record *CurRec, bool IsFinal) const {
788788
if (StringInit *LHSs = dyn_cast<StringInit>(LHS))
789789
return IntInit::get(LHSs->getValue().empty());
790790
break;
791+
792+
case GETOP:
793+
if (DagInit *Dag = dyn_cast<DagInit>(LHS)) {
794+
DefInit *DI = DefInit::get(Dag->getOperatorAsDef({}));
795+
if (!DI->getType()->typeIsA(getType())) {
796+
PrintFatalError(CurRec->getLoc(),
797+
Twine("Expected type '") +
798+
getType()->getAsString() + "', got '" +
799+
DI->getType()->getAsString() + "' in: " +
800+
getAsString() + "\n");
801+
} else {
802+
return DI;
803+
}
804+
}
805+
break;
791806
}
792807
return const_cast<UnOpInit *>(this);
793808
}
@@ -809,6 +824,7 @@ std::string UnOpInit::getAsString() const {
809824
case TAIL: Result = "!tail"; break;
810825
case SIZE: Result = "!size"; break;
811826
case EMPTY: Result = "!empty"; break;
827+
case GETOP: Result = "!getop"; break;
812828
}
813829
return Result + "(" + LHS->getAsString() + ")";
814830
}
@@ -980,6 +996,20 @@ Init *BinOpInit::Fold(Record *CurRec) const {
980996

981997
break;
982998
}
999+
case SETOP: {
1000+
DagInit *Dag = dyn_cast<DagInit>(LHS);
1001+
DefInit *Op = dyn_cast<DefInit>(RHS);
1002+
if (Dag && Op) {
1003+
SmallVector<Init*, 8> Args;
1004+
SmallVector<StringInit*, 8> ArgNames;
1005+
for (unsigned i = 0, e = Dag->getNumArgs(); i != e; ++i) {
1006+
Args.push_back(Dag->getArg(i));
1007+
ArgNames.push_back(Dag->getArgName(i));
1008+
}
1009+
return DagInit::get(Op, nullptr, Args, ArgNames);
1010+
}
1011+
break;
1012+
}
9831013
case ADD:
9841014
case MUL:
9851015
case AND:
@@ -1042,6 +1072,7 @@ std::string BinOpInit::getAsString() const {
10421072
case LISTCONCAT: Result = "!listconcat"; break;
10431073
case LISTSPLAT: Result = "!listsplat"; break;
10441074
case STRCONCAT: Result = "!strconcat"; break;
1075+
case SETOP: Result = "!setop"; break;
10451076
}
10461077
return Result + "(" + LHS->getAsString() + ", " + RHS->getAsString() + ")";
10471078
}

llvm/lib/TableGen/TGLexer.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,8 @@ tgtok::TokKind TGLexer::LexExclaim() {
559559
.Case("listconcat", tgtok::XListConcat)
560560
.Case("listsplat", tgtok::XListSplat)
561561
.Case("strconcat", tgtok::XStrConcat)
562+
.Case("setop", tgtok::XSetOp)
563+
.Case("getop", tgtok::XGetOp)
562564
.Default(tgtok::Error);
563565

564566
return Kind != tgtok::Error ? Kind : ReturnError(Start-1, "Unknown operator");

llvm/lib/TableGen/TGLexer.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ namespace tgtok {
5151
// !keywords.
5252
XConcat, XADD, XMUL, XAND, XOR, XSRA, XSRL, XSHL, XListConcat, XListSplat,
5353
XStrConcat, XCast, XSubst, XForEach, XFoldl, XHead, XTail, XSize, XEmpty,
54-
XIf, XCond, XEq, XIsA, XDag, XNe, XLe, XLt, XGe, XGt,
54+
XIf, XCond, XEq, XIsA, XDag, XNe, XLe, XLt, XGe, XGt, XSetOp, XGetOp,
5555

5656
// Integer value.
5757
IntVal,

llvm/lib/TableGen/TGParser.cpp

+45-6
Original file line numberDiff line numberDiff line change
@@ -905,7 +905,8 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
905905
case tgtok::XTail:
906906
case tgtok::XSize:
907907
case tgtok::XEmpty:
908-
case tgtok::XCast: { // Value ::= !unop '(' Value ')'
908+
case tgtok::XCast:
909+
case tgtok::XGetOp: { // Value ::= !unop '(' Value ')'
909910
UnOpInit::UnaryOp Code;
910911
RecTy *Type = nullptr;
911912

@@ -941,6 +942,28 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
941942
Code = UnOpInit::EMPTY;
942943
Type = IntRecTy::get();
943944
break;
945+
case tgtok::XGetOp:
946+
Lex.Lex(); // eat the operation
947+
if (Lex.getCode() == tgtok::less) {
948+
// Parse an optional type suffix, so that you can say
949+
// !getop<BaseClass>(someDag) as a shorthand for
950+
// !cast<BaseClass>(!getop(someDag)).
951+
Type = ParseOperatorType();
952+
953+
if (!Type) {
954+
TokError("did not get type for unary operator");
955+
return nullptr;
956+
}
957+
958+
if (!isa<RecordRecTy>(Type)) {
959+
TokError("type for !getop must be a record type");
960+
// but keep parsing, to consume the operand
961+
}
962+
} else {
963+
Type = RecordRecTy::get({});
964+
}
965+
Code = UnOpInit::GETOP;
966+
break;
944967
}
945968
if (Lex.getCode() != tgtok::l_paren) {
946969
TokError("expected '(' after unary operator");
@@ -1055,7 +1078,8 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
10551078
case tgtok::XGt:
10561079
case tgtok::XListConcat:
10571080
case tgtok::XListSplat:
1058-
case tgtok::XStrConcat: { // Value ::= !binop '(' Value ',' Value ')'
1081+
case tgtok::XStrConcat:
1082+
case tgtok::XSetOp: { // Value ::= !binop '(' Value ',' Value ')'
10591083
tgtok::TokKind OpTok = Lex.getCode();
10601084
SMLoc OpLoc = Lex.getLoc();
10611085
Lex.Lex(); // eat the operation
@@ -1080,6 +1104,7 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
10801104
case tgtok::XListConcat: Code = BinOpInit::LISTCONCAT; break;
10811105
case tgtok::XListSplat: Code = BinOpInit::LISTSPLAT; break;
10821106
case tgtok::XStrConcat: Code = BinOpInit::STRCONCAT; break;
1107+
case tgtok::XSetOp: Code = BinOpInit::SETOP; break;
10831108
}
10841109

10851110
RecTy *Type = nullptr;
@@ -1088,6 +1113,7 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
10881113
default:
10891114
llvm_unreachable("Unhandled code!");
10901115
case tgtok::XConcat:
1116+
case tgtok::XSetOp:
10911117
Type = DagRecTy::get();
10921118
ArgType = DagRecTy::get();
10931119
break;
@@ -1146,7 +1172,6 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
11461172
InitList.push_back(ParseValue(CurRec, ArgType));
11471173
if (!InitList.back()) return nullptr;
11481174

1149-
// All BinOps require their arguments to be of compatible types.
11501175
RecTy *ListType = cast<TypedInit>(InitList.back())->getType();
11511176
if (!ArgType) {
11521177
ArgType = ListType;
@@ -1212,6 +1237,18 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
12121237
ArgType = Resolved;
12131238
}
12141239

1240+
// Deal with BinOps whose arguments have different types, by
1241+
// rewriting ArgType in between them.
1242+
switch (Code) {
1243+
case BinOpInit::SETOP:
1244+
// After parsing the first dag argument, switch to expecting
1245+
// a record, with no restriction on its superclasses.
1246+
ArgType = RecordRecTy::get({});
1247+
break;
1248+
default:
1249+
break;
1250+
}
1251+
12151252
if (Lex.getCode() != tgtok::comma)
12161253
break;
12171254
Lex.Lex(); // eat the ','
@@ -2025,7 +2062,7 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType,
20252062
case tgtok::l_paren: { // Value ::= '(' IDValue DagArgList ')'
20262063
Lex.Lex(); // eat the '('
20272064
if (Lex.getCode() != tgtok::Id && Lex.getCode() != tgtok::XCast &&
2028-
Lex.getCode() != tgtok::question) {
2065+
Lex.getCode() != tgtok::question && Lex.getCode() != tgtok::XGetOp) {
20292066
TokError("expected identifier in dag init");
20302067
return nullptr;
20312068
}
@@ -2063,7 +2100,8 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType,
20632100
case tgtok::XTail:
20642101
case tgtok::XSize:
20652102
case tgtok::XEmpty:
2066-
case tgtok::XCast: // Value ::= !unop '(' Value ')'
2103+
case tgtok::XCast:
2104+
case tgtok::XGetOp: // Value ::= !unop '(' Value ')'
20672105
case tgtok::XIsA:
20682106
case tgtok::XConcat:
20692107
case tgtok::XDag:
@@ -2082,7 +2120,8 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType,
20822120
case tgtok::XGt:
20832121
case tgtok::XListConcat:
20842122
case tgtok::XListSplat:
2085-
case tgtok::XStrConcat: // Value ::= !binop '(' Value ',' Value ')'
2123+
case tgtok::XStrConcat:
2124+
case tgtok::XSetOp: // Value ::= !binop '(' Value ',' Value ')'
20862125
case tgtok::XIf:
20872126
case tgtok::XCond:
20882127
case tgtok::XFoldl:

llvm/test/TableGen/getsetop.td

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// RUN: llvm-tblgen %s | FileCheck %s
2+
// RUN: not llvm-tblgen -DERROR1 %s 2>&1 | FileCheck --check-prefix=ERROR1 %s
3+
// RUN: not llvm-tblgen -DERROR2 %s 2>&1 | FileCheck --check-prefix=ERROR2 %s
4+
// RUN: not llvm-tblgen -DERROR3 %s 2>&1 | FileCheck --check-prefix=ERROR3 %s
5+
6+
class Base;
7+
class OtherBase;
8+
9+
def foo: Base;
10+
def bar: Base;
11+
def qux: OtherBase;
12+
13+
def test {
14+
dag orig = (foo 1, 2:$a, $b);
15+
dag another = (qux "hello", $world);
16+
17+
// CHECK: dag replaceWithBar = (bar 1, 2:$a, ?:$b);
18+
dag replaceWithBar = !setop(orig, bar);
19+
20+
// CHECK: dag replaceWithBaz = (qux 1, 2:$a, ?:$b);
21+
dag replaceWithBaz = !setop(orig, qux);
22+
23+
// CHECK: Base getopWithCast = foo;
24+
Base getopWithCast = !getop<Base>(orig);
25+
26+
// CHECK: dag getopToSetop = (foo "hello", ?:$world);
27+
dag getopToSetop = !setop(another, !getop(orig));
28+
29+
// CHECK: dag getopToBangDag = (foo 1:$a, 2:$b, 3:$c);
30+
dag getopToBangDag = !dag(!getop(orig), [1, 2, 3], ["a", "b", "c"]);
31+
32+
// CHECK: dag getopToDagInit = (foo "it worked");
33+
dag getopToDagInit = (!getop(orig) "it worked");
34+
35+
#ifdef ERROR1
36+
// !getop(...) has a static type of 'any record at all, with no
37+
// required superclasses'. That's too general to use in an
38+
// assignment whose LHS demands an instance of Base, so we expect a
39+
// static (parse-time) type-checking error.
40+
41+
// ERROR1: error: Value 'noCast' of type 'Base' is incompatible with initializer '!getop(orig)' of type '{}'
42+
Base noCast = !getop(orig);
43+
#endif
44+
45+
#ifdef ERROR2
46+
// Here, we expect a _dynamic_ type error, when it turns out at
47+
// evaluation time that the operator of 'another' is a record that
48+
// isn't an instance of the specified base class.
49+
50+
// ERROR2: error: Expected type 'Base', got 'OtherBase' in: !getop((qux "hello", ?:$world))
51+
Base badCast = !getop<Base>(another);
52+
#endif
53+
54+
#ifdef ERROR3
55+
// Obviously, you shouldn't be able to give any type to !getop that
56+
// isn't a class type.
57+
58+
// ERROR3: error: type for !getop must be a record type
59+
int ridiculousCast = !getop<int>(orig);
60+
#endif
61+
}

0 commit comments

Comments
 (0)