[llvm] [llvm][TableGen] Add a !initialized predicate to allow testing for ? (PR #117964)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Nov 27 20:20:26 PST 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-tablegen
Author: Krzysztof Drewniak (krzysz00)
<details>
<summary>Changes</summary>
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 ?.
---
Full diff: https://github.com/llvm/llvm-project/pull/117964.diff
7 Files Affected:
- (modified) llvm/docs/TableGen/ProgRef.rst (+12-7)
- (modified) llvm/include/llvm/TableGen/Record.h (+1)
- (modified) llvm/lib/TableGen/Record.cpp (+10)
- (modified) llvm/lib/TableGen/TGLexer.cpp (+1)
- (modified) llvm/lib/TableGen/TGLexer.h (+1)
- (modified) llvm/lib/TableGen/TGParser.cpp (+15-9)
- (added) llvm/test/TableGen/initialized.td (+59)
``````````diff
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>;
``````````
</details>
https://github.com/llvm/llvm-project/pull/117964
More information about the llvm-commits
mailing list