-
Notifications
You must be signed in to change notification settings - Fork 14.4k
[llvm][TableGen] Add a !initialized predicate to allow testing for ? #117964
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-tablegen Author: Krzysztof Drewniak (krzysz00) ChangesThere are cases (like in an upcoming patch to MLIR's This commit adds the !initialized predicate, which is 1 on concrete, non-? values and 0 on ?. Full diff: https://github.com/llvm/llvm-project/pull/117964.diff 7 Files Affected:
diff --git a/llvm/docs/TableGen/ProgRef.rst b/llvm/docs/TableGen/ProgRef.rst
index 03fe1157b4042e..5f0d44a3171c7c 100644
--- a/llvm/docs/TableGen/ProgRef.rst
+++ b/llvm/docs/TableGen/ProgRef.rst
@@ -223,12 +223,13 @@ TableGen provides "bang operators" that have a wide variety of uses:
: !div !empty !eq !exists !filter
: !find !foldl !foreach !ge !getdagarg
: !getdagname !getdagop !gt !head !if
- : !interleave !isa !le !listconcat !listflatten
- : !listremove !listsplat !logtwo !lt !mul
- : !ne !not !or !range !repr
- : !setdagarg !setdagname !setdagop !shl !size
- : !sra !srl !strconcat !sub !subst
- : !substr !tail !tolower !toupper !xor
+ : !initialized !interleave !isa !le !listconcat
+ : !listflatten !listremove !listsplat !logtwo !lt
+ : !mul !ne !not !or !range
+ : !repr !setdagarg !setdagname !setdagop !shl
+ : !size !sra !srl !strconcat !sub
+ : !subst !substr !tail !tolower !toupper
+ : !xor
The ``!cond`` operator has a slightly different
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
global name, it is treated as a verbatim string of characters. The
left-hand-side operand is treated normally.
-Values can have a trailing paste operator, in which case the left-hand-side
+Values can have a trailing paste operator, in which case the left-hand-side
operand is concatenated to an empty string.
`Appendix B: Paste Operator Examples`_ presents examples of the behavior of
@@ -1815,6 +1816,10 @@ and non-0 as true.
``int``. If the result is not 0, the *then* expression is produced; otherwise
the *else* expression is produced.
+``!initialized(``\ *a*\ ``)``
+ This is produces a 1 if *a* is not the unitialized value (``?``) and 0
+ otherwise.
+
``!interleave(``\ *list*\ ``,`` *delim*\ ``)``
This operator concatenates the items in the *list*, interleaving the
*delim* string between each pair, and produces the resulting string.
diff --git a/llvm/include/llvm/TableGen/Record.h b/llvm/include/llvm/TableGen/Record.h
index e64b78c3c1e3b9..81a9257425783f 100644
--- a/llvm/include/llvm/TableGen/Record.h
+++ b/llvm/include/llvm/TableGen/Record.h
@@ -860,6 +860,7 @@ class UnOpInit : public OpInit, public FoldingSetNode {
LOG2,
REPR,
LISTFLATTEN,
+ INITIALIZED,
};
private:
diff --git a/llvm/lib/TableGen/Record.cpp b/llvm/lib/TableGen/Record.cpp
index feef51f3d203cd..33607005a787a5 100644
--- a/llvm/lib/TableGen/Record.cpp
+++ b/llvm/lib/TableGen/Record.cpp
@@ -917,6 +917,13 @@ const Init *UnOpInit::Fold(const Record *CurRec, bool IsFinal) const {
return NewInit;
break;
+ case INITIALIZED:
+ if (isa_and_nonnull<UnsetInit>(LHS))
+ return IntInit::get(RK, 0);
+ if (LHS->isConcrete())
+ return IntInit::get(RK, 1);
+ break;
+
case NOT:
if (const auto *LHSi = dyn_cast_or_null<IntInit>(
LHS->convertInitializerTo(IntRecTy::get(RK))))
@@ -1052,6 +1059,9 @@ std::string UnOpInit::getAsString() const {
case TOUPPER:
Result = "!toupper";
break;
+ case INITIALIZED:
+ Result = "!initialized";
+ break;
}
return Result + "(" + LHS->getAsString() + ")";
}
diff --git a/llvm/lib/TableGen/TGLexer.cpp b/llvm/lib/TableGen/TGLexer.cpp
index 1e93b2c160ba58..eee42511804f5e 100644
--- a/llvm/lib/TableGen/TGLexer.cpp
+++ b/llvm/lib/TableGen/TGLexer.cpp
@@ -633,6 +633,7 @@ tgtok::TokKind TGLexer::LexExclaim() {
.Case("listremove", tgtok::XListRemove)
.Case("range", tgtok::XRange)
.Case("strconcat", tgtok::XStrConcat)
+ .Case("initialized", tgtok::XInitialized)
.Case("interleave", tgtok::XInterleave)
.Case("substr", tgtok::XSubstr)
.Case("find", tgtok::XFind)
diff --git a/llvm/lib/TableGen/TGLexer.h b/llvm/lib/TableGen/TGLexer.h
index 9a6874c8975730..963d75e52cc8fd 100644
--- a/llvm/lib/TableGen/TGLexer.h
+++ b/llvm/lib/TableGen/TGLexer.h
@@ -135,6 +135,7 @@ enum TokKind {
XTail,
XSize,
XEmpty,
+ XInitialized,
XIf,
XCond,
XEq,
diff --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp
index e01342ffcd3c8f..176af09dd29dd4 100644
--- a/llvm/lib/TableGen/TGParser.cpp
+++ b/llvm/lib/TableGen/TGParser.cpp
@@ -969,7 +969,7 @@ const TypedInit *TGParser::ParseSliceElements(Record *CurRec, bool Single) {
/// RangePiece ::= INTVAL
/// RangePiece ::= INTVAL '...' INTVAL
/// RangePiece ::= INTVAL '-' INTVAL
-/// RangePiece ::= INTVAL INTVAL
+/// RangePiece ::= INTVAL INTVAL
// The last two forms are deprecated.
bool TGParser::ParseRangePiece(SmallVectorImpl<unsigned> &Ranges,
const TypedInit *FirstItem) {
@@ -1203,7 +1203,8 @@ const Init *TGParser::ParseOperation(Record *CurRec, const RecTy *ItemType) {
case tgtok::XEmpty:
case tgtok::XCast:
case tgtok::XRepr:
- case tgtok::XGetDagOp: { // Value ::= !unop '(' Value ')'
+ case tgtok::XGetDagOp:
+ case tgtok::XInitialized: { // Value ::= !unop '(' Value ')'
UnOpInit::UnaryOp Code;
const RecTy *Type = nullptr;
@@ -1291,6 +1292,11 @@ const Init *TGParser::ParseOperation(Record *CurRec, const RecTy *ItemType) {
}
Code = UnOpInit::GETDAGOP;
break;
+ case tgtok::XInitialized:
+ Lex.Lex(); // eat the operation
+ Code = UnOpInit::INITIALIZED;
+ Type = IntRecTy::get(Records);
+ break;
}
if (!consume(tgtok::l_paren)) {
TokError("expected '(' after unary operator");
@@ -1655,8 +1661,8 @@ const Init *TGParser::ParseOperation(Record *CurRec, const RecTy *ItemType) {
!ArgType->typeIsConvertibleTo(StringRecTy::get(Records)) &&
!ArgType->typeIsConvertibleTo(RecordRecTy::get(Records, {}))) {
Error(InitLoc, Twine("expected bit, bits, int, string, or record; "
- "got value of type '") + ArgType->getAsString() +
- "'");
+ "got value of type '") +
+ ArgType->getAsString() + "'");
return nullptr;
}
break;
@@ -1669,8 +1675,8 @@ const Init *TGParser::ParseOperation(Record *CurRec, const RecTy *ItemType) {
if (!ArgType->typeIsConvertibleTo(IntRecTy::get(Records)) &&
!ArgType->typeIsConvertibleTo(StringRecTy::get(Records))) {
Error(InitLoc, Twine("expected bit, bits, int, or string; "
- "got value of type '") + ArgType->getAsString() +
- "'");
+ "got value of type '") +
+ ArgType->getAsString() + "'");
return nullptr;
}
break;
@@ -2528,7 +2534,7 @@ const Init *TGParser::ParseOperationForEachFilter(Record *CurRec,
OutType = RHSt->getType()->getListTy();
} else if (Operation == tgtok::XFilter) {
OutType = InEltType->getListTy();
- }
+ }
return (TernOpInit::get((Operation == tgtok::XForEach) ? TernOpInit::FOREACH
: TernOpInit::FILTER,
@@ -3548,7 +3554,7 @@ bool TGParser::ParseBody(Record *CurRec) {
SMLoc SemiLoc = Lex.getLoc();
if (consume(tgtok::semi)) {
PrintError(SemiLoc, "A class or def body should not end with a semicolon");
- PrintNote("Semicolon ignored; remove to eliminate this error");
+ PrintNote("Semicolon ignored; remove to eliminate this error");
}
return false;
@@ -4218,7 +4224,7 @@ bool TGParser::ParseMultiClass() {
SMLoc SemiLoc = Lex.getLoc();
if (consume(tgtok::semi)) {
PrintError(SemiLoc, "A multiclass body should not end with a semicolon");
- PrintNote("Semicolon ignored; remove to eliminate this error");
+ PrintNote("Semicolon ignored; remove to eliminate this error");
}
}
diff --git a/llvm/test/TableGen/initialized.td b/llvm/test/TableGen/initialized.td
new file mode 100644
index 00000000000000..e1743909feb64f
--- /dev/null
+++ b/llvm/test/TableGen/initialized.td
@@ -0,0 +1,59 @@
+// RUN: llvm-tblgen %s | FileCheck %s
+
+// CHECK: class F<Y [[ARG:.+]] = ?> {
+// CHECK: string ret = !if(!initialized([[ARG]].str), [[ARG]].str, "N/A");
+// CHECK: }
+
+// CHECK-LABEL: def C
+// CHECK: bit c0 = 0
+// CHECK: bit c1 = 1
+// CHECK: bit c2 = 1
+def C {
+ bit c0 = !initialized(?);
+ bit c1 = !initialized(0);
+ bit c2 = !initialized(1);
+}
+
+class Y {
+ string str = ?;
+}
+
+class F<Y y> {
+ string ret = !if(!initialized(y.str), y.str, "N/A");
+}
+
+def Y0 : Y;
+def Y1 : Y {
+ let str = "foo";
+}
+
+// CHECK-LABEL: def FY0
+// CHECK: string ret = "N/A";
+// CHECK-LABEL: def FY1
+// CHECK: string ret = "foo";
+def FY0 : F<Y0>;
+def FY1 : F<Y1>;
+
+class G<Y y> {
+ list<string> v = [y.str];
+ bit isInit = !initialized(v);
+}
+
+// CHECK-LABEL: def GY0
+// CHECK: isInit = 1
+// CHECK-LABEL: def GY1
+// CHECK: isInit = 1
+def GY0 : G<Y0>;
+def GY1 : G<Y1>;
+
+class Thing;
+def aThing : Thing;
+class Propagate<Thing t> {
+ Thing ret = !if(!initialized(t), t, ?);
+}
+// CHECK-LABEL: def PropagateNothing
+// CHECK: Thing ret = ?
+// CHECK-LABEL: def PropagateThing
+// CHECK: Thing ret = aThing
+def PropagateNothing : Propagate<?>;
+def PropagateThing : Propagate<aThing>;
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think codewise GTM.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, Thanks!
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 ?.
Co-authored-by: Akshat Oke <[email protected]>
d972251
to
20deaa1
Compare
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 ?.