[llvm] [llvm][TableGen] Add a !initialized predicate to allow testing for ? (PR #117964)
Krzysztof Drewniak via llvm-commits
llvm-commits at lists.llvm.org
Sat Nov 30 23:02:35 PST 2024
https://github.com/krzysz00 updated https://github.com/llvm/llvm-project/pull/117964
>From f2a6438c2a15203856640b9771dd8cf8a06eea1e Mon Sep 17 00:00:00 2001
From: Krzysztof Drewniak <krzysdrewniak at gmail.com>
Date: Wed, 27 Nov 2024 20:08:48 -0800
Subject: [PATCH 1/3] [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 ?.
---
llvm/docs/TableGen/ProgRef.rst | 19 ++++++----
llvm/include/llvm/TableGen/Record.h | 1 +
llvm/lib/TableGen/Record.cpp | 10 +++++
llvm/lib/TableGen/TGLexer.cpp | 1 +
llvm/lib/TableGen/TGLexer.h | 1 +
llvm/lib/TableGen/TGParser.cpp | 24 +++++++-----
llvm/test/TableGen/initialized.td | 59 +++++++++++++++++++++++++++++
7 files changed, 99 insertions(+), 16 deletions(-)
create mode 100644 llvm/test/TableGen/initialized.td
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>;
>From 14370bff4b04288dda37c3a9a2e3a06179eb5f77 Mon Sep 17 00:00:00 2001
From: Krzysztof Drewniak <Krzysztof.Drewniak at amd.com>
Date: Sun, 1 Dec 2024 00:59:31 -0600
Subject: [PATCH 2/3] Adjust wording in documentation
Co-authored-by: Akshat Oke <Akshat.Oke at amd.com>
---
llvm/docs/TableGen/ProgRef.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/docs/TableGen/ProgRef.rst b/llvm/docs/TableGen/ProgRef.rst
index 5f0d44a3171c7c..cfe61382658ec4 100644
--- a/llvm/docs/TableGen/ProgRef.rst
+++ b/llvm/docs/TableGen/ProgRef.rst
@@ -1817,7 +1817,7 @@ and non-0 as true.
the *else* expression is produced.
``!initialized(``\ *a*\ ``)``
- This is produces a 1 if *a* is not the unitialized value (``?``) and 0
+ This operator produces 1 if *a* is not the uninitialized value (``?``) and 0
otherwise.
``!interleave(``\ *list*\ ``,`` *delim*\ ``)``
>From d972251bfc7afbf88d79043335d336dcf3f8df31 Mon Sep 17 00:00:00 2001
From: Krzysztof Drewniak <krzysdrewniak at gmail.com>
Date: Sat, 30 Nov 2024 23:02:12 -0800
Subject: [PATCH 3/3] Review comments
---
llvm/lib/TableGen/Record.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/lib/TableGen/Record.cpp b/llvm/lib/TableGen/Record.cpp
index 33607005a787a5..597ccb7ca144bb 100644
--- a/llvm/lib/TableGen/Record.cpp
+++ b/llvm/lib/TableGen/Record.cpp
@@ -918,7 +918,7 @@ const Init *UnOpInit::Fold(const Record *CurRec, bool IsFinal) const {
break;
case INITIALIZED:
- if (isa_and_nonnull<UnsetInit>(LHS))
+ if (isa<UnsetInit>(LHS))
return IntInit::get(RK, 0);
if (LHS->isConcrete())
return IntInit::get(RK, 1);
More information about the llvm-commits
mailing list