Skip to content

Commit 02fae27

Browse files
committed
[llvm][TableGen] Add a !initialized predicate to allow testing for ?
There are cases (like in an upcoming patch to MLIR's `Property` class) where the ? value is a useful null value. However, existing predicates make ti difficult to test if the value in a record one is operating is ? or not. This commit adds the !initialized predicate, which is 1 on concrete, non-? values and 0 on ?.
1 parent 5e1f87e commit 02fae27

File tree

7 files changed

+99
-16
lines changed

7 files changed

+99
-16
lines changed

llvm/docs/TableGen/ProgRef.rst

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -223,12 +223,13 @@ TableGen provides "bang operators" that have a wide variety of uses:
223223
: !div !empty !eq !exists !filter
224224
: !find !foldl !foreach !ge !getdagarg
225225
: !getdagname !getdagop !gt !head !if
226-
: !interleave !isa !le !listconcat !listflatten
227-
: !listremove !listsplat !logtwo !lt !mul
228-
: !ne !not !or !range !repr
229-
: !setdagarg !setdagname !setdagop !shl !size
230-
: !sra !srl !strconcat !sub !subst
231-
: !substr !tail !tolower !toupper !xor
226+
: !initialized !interleave !isa !le !listconcat
227+
: !listflatten !listremove !listsplat !logtwo !lt
228+
: !mul !ne !not !or !range
229+
: !repr !setdagarg !setdagname !setdagop !shl
230+
: !size !sra !srl !strconcat !sub
231+
: !subst !substr !tail !tolower !toupper
232+
: !xor
232233

233234
The ``!cond`` operator has a slightly different
234235
syntax compared to other bang operators, so it is defined separately:
@@ -555,7 +556,7 @@ previous case, if the *right-hand-side* operand is an undefined name or a
555556
global name, it is treated as a verbatim string of characters. The
556557
left-hand-side operand is treated normally.
557558

558-
Values can have a trailing paste operator, in which case the left-hand-side
559+
Values can have a trailing paste operator, in which case the left-hand-side
559560
operand is concatenated to an empty string.
560561

561562
`Appendix B: Paste Operator Examples`_ presents examples of the behavior of
@@ -1815,6 +1816,10 @@ and non-0 as true.
18151816
``int``. If the result is not 0, the *then* expression is produced; otherwise
18161817
the *else* expression is produced.
18171818

1819+
``!initialized(``\ *a*\ ``)``
1820+
This is produces a 1 if *a* is not the unitialized value (``?``) and 0
1821+
otherwise.
1822+
18181823
``!interleave(``\ *list*\ ``,`` *delim*\ ``)``
18191824
This operator concatenates the items in the *list*, interleaving the
18201825
*delim* string between each pair, and produces the resulting string.

llvm/include/llvm/TableGen/Record.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -860,6 +860,7 @@ class UnOpInit : public OpInit, public FoldingSetNode {
860860
LOG2,
861861
REPR,
862862
LISTFLATTEN,
863+
INITIALIZED,
863864
};
864865

865866
private:

llvm/lib/TableGen/Record.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -917,6 +917,13 @@ const Init *UnOpInit::Fold(const Record *CurRec, bool IsFinal) const {
917917
return NewInit;
918918
break;
919919

920+
case INITIALIZED:
921+
if (isa_and_nonnull<UnsetInit>(LHS))
922+
return IntInit::get(RK, 0);
923+
if (LHS->isConcrete())
924+
return IntInit::get(RK, 1);
925+
break;
926+
920927
case NOT:
921928
if (const auto *LHSi = dyn_cast_or_null<IntInit>(
922929
LHS->convertInitializerTo(IntRecTy::get(RK))))
@@ -1052,6 +1059,9 @@ std::string UnOpInit::getAsString() const {
10521059
case TOUPPER:
10531060
Result = "!toupper";
10541061
break;
1062+
case INITIALIZED:
1063+
Result = "!initialized";
1064+
break;
10551065
}
10561066
return Result + "(" + LHS->getAsString() + ")";
10571067
}

llvm/lib/TableGen/TGLexer.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,7 @@ tgtok::TokKind TGLexer::LexExclaim() {
633633
.Case("listremove", tgtok::XListRemove)
634634
.Case("range", tgtok::XRange)
635635
.Case("strconcat", tgtok::XStrConcat)
636+
.Case("initialized", tgtok::XInitialized)
636637
.Case("interleave", tgtok::XInterleave)
637638
.Case("substr", tgtok::XSubstr)
638639
.Case("find", tgtok::XFind)

llvm/lib/TableGen/TGLexer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ enum TokKind {
135135
XTail,
136136
XSize,
137137
XEmpty,
138+
XInitialized,
138139
XIf,
139140
XCond,
140141
XEq,

llvm/lib/TableGen/TGParser.cpp

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -969,7 +969,7 @@ const TypedInit *TGParser::ParseSliceElements(Record *CurRec, bool Single) {
969969
/// RangePiece ::= INTVAL
970970
/// RangePiece ::= INTVAL '...' INTVAL
971971
/// RangePiece ::= INTVAL '-' INTVAL
972-
/// RangePiece ::= INTVAL INTVAL
972+
/// RangePiece ::= INTVAL INTVAL
973973
// The last two forms are deprecated.
974974
bool TGParser::ParseRangePiece(SmallVectorImpl<unsigned> &Ranges,
975975
const TypedInit *FirstItem) {
@@ -1203,7 +1203,8 @@ const Init *TGParser::ParseOperation(Record *CurRec, const RecTy *ItemType) {
12031203
case tgtok::XEmpty:
12041204
case tgtok::XCast:
12051205
case tgtok::XRepr:
1206-
case tgtok::XGetDagOp: { // Value ::= !unop '(' Value ')'
1206+
case tgtok::XGetDagOp:
1207+
case tgtok::XInitialized: { // Value ::= !unop '(' Value ')'
12071208
UnOpInit::UnaryOp Code;
12081209
const RecTy *Type = nullptr;
12091210

@@ -1291,6 +1292,11 @@ const Init *TGParser::ParseOperation(Record *CurRec, const RecTy *ItemType) {
12911292
}
12921293
Code = UnOpInit::GETDAGOP;
12931294
break;
1295+
case tgtok::XInitialized:
1296+
Lex.Lex(); // eat the operation
1297+
Code = UnOpInit::INITIALIZED;
1298+
Type = IntRecTy::get(Records);
1299+
break;
12941300
}
12951301
if (!consume(tgtok::l_paren)) {
12961302
TokError("expected '(' after unary operator");
@@ -1655,8 +1661,8 @@ const Init *TGParser::ParseOperation(Record *CurRec, const RecTy *ItemType) {
16551661
!ArgType->typeIsConvertibleTo(StringRecTy::get(Records)) &&
16561662
!ArgType->typeIsConvertibleTo(RecordRecTy::get(Records, {}))) {
16571663
Error(InitLoc, Twine("expected bit, bits, int, string, or record; "
1658-
"got value of type '") + ArgType->getAsString() +
1659-
"'");
1664+
"got value of type '") +
1665+
ArgType->getAsString() + "'");
16601666
return nullptr;
16611667
}
16621668
break;
@@ -1669,8 +1675,8 @@ const Init *TGParser::ParseOperation(Record *CurRec, const RecTy *ItemType) {
16691675
if (!ArgType->typeIsConvertibleTo(IntRecTy::get(Records)) &&
16701676
!ArgType->typeIsConvertibleTo(StringRecTy::get(Records))) {
16711677
Error(InitLoc, Twine("expected bit, bits, int, or string; "
1672-
"got value of type '") + ArgType->getAsString() +
1673-
"'");
1678+
"got value of type '") +
1679+
ArgType->getAsString() + "'");
16741680
return nullptr;
16751681
}
16761682
break;
@@ -2528,7 +2534,7 @@ const Init *TGParser::ParseOperationForEachFilter(Record *CurRec,
25282534
OutType = RHSt->getType()->getListTy();
25292535
} else if (Operation == tgtok::XFilter) {
25302536
OutType = InEltType->getListTy();
2531-
}
2537+
}
25322538

25332539
return (TernOpInit::get((Operation == tgtok::XForEach) ? TernOpInit::FOREACH
25342540
: TernOpInit::FILTER,
@@ -3548,7 +3554,7 @@ bool TGParser::ParseBody(Record *CurRec) {
35483554
SMLoc SemiLoc = Lex.getLoc();
35493555
if (consume(tgtok::semi)) {
35503556
PrintError(SemiLoc, "A class or def body should not end with a semicolon");
3551-
PrintNote("Semicolon ignored; remove to eliminate this error");
3557+
PrintNote("Semicolon ignored; remove to eliminate this error");
35523558
}
35533559

35543560
return false;
@@ -4218,7 +4224,7 @@ bool TGParser::ParseMultiClass() {
42184224
SMLoc SemiLoc = Lex.getLoc();
42194225
if (consume(tgtok::semi)) {
42204226
PrintError(SemiLoc, "A multiclass body should not end with a semicolon");
4221-
PrintNote("Semicolon ignored; remove to eliminate this error");
4227+
PrintNote("Semicolon ignored; remove to eliminate this error");
42224228
}
42234229
}
42244230

llvm/test/TableGen/initialized.td

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// RUN: llvm-tblgen %s | FileCheck %s
2+
3+
// CHECK: class F<Y [[ARG:.+]] = ?> {
4+
// CHECK: string ret = !if(!initialized([[ARG]].str), [[ARG]].str, "N/A");
5+
// CHECK: }
6+
7+
// CHECK-LABEL: def C
8+
// CHECK: bit c0 = 0
9+
// CHECK: bit c1 = 1
10+
// CHECK: bit c2 = 1
11+
def C {
12+
bit c0 = !initialized(?);
13+
bit c1 = !initialized(0);
14+
bit c2 = !initialized(1);
15+
}
16+
17+
class Y {
18+
string str = ?;
19+
}
20+
21+
class F<Y y> {
22+
string ret = !if(!initialized(y.str), y.str, "N/A");
23+
}
24+
25+
def Y0 : Y;
26+
def Y1 : Y {
27+
let str = "foo";
28+
}
29+
30+
// CHECK-LABEL: def FY0
31+
// CHECK: string ret = "N/A";
32+
// CHECK-LABEL: def FY1
33+
// CHECK: string ret = "foo";
34+
def FY0 : F<Y0>;
35+
def FY1 : F<Y1>;
36+
37+
class G<Y y> {
38+
list<string> v = [y.str];
39+
bit isInit = !initialized(v);
40+
}
41+
42+
// CHECK-LABEL: def GY0
43+
// CHECK: isInit = 1
44+
// CHECK-LABEL: def GY1
45+
// CHECK: isInit = 1
46+
def GY0 : G<Y0>;
47+
def GY1 : G<Y1>;
48+
49+
class Thing;
50+
def aThing : Thing;
51+
class Propagate<Thing t> {
52+
Thing ret = !if(!initialized(t), t, ?);
53+
}
54+
// CHECK-LABEL: def PropagateNothing
55+
// CHECK: Thing ret = ?
56+
// CHECK-LABEL: def PropagateThing
57+
// CHECK: Thing ret = aThing
58+
def PropagateNothing : Propagate<?>;
59+
def PropagateThing : Propagate<aThing>;

0 commit comments

Comments
 (0)