[llvm] cacfac4 - [TableGen] New bang operator `!repr`. (#68716)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Oct 11 04:11:53 PDT 2023
Author: Francesco Petrogalli
Date: 2023-10-11T13:11:48+02:00
New Revision: cacfac416c959ab06dd4f7978f0f2a067b1cb283
URL: https://github.com/llvm/llvm-project/commit/cacfac416c959ab06dd4f7978f0f2a067b1cb283
DIFF: https://github.com/llvm/llvm-project/commit/cacfac416c959ab06dd4f7978f0f2a067b1cb283.diff
LOG: [TableGen] New bang operator `!repr`. (#68716)
The !repr operator represents the content of a variable or of a record
as a string.
This patch is based on code originally written by Adam Nemet, and on the
feedback received by the reviewers in
https://reviews.llvm.org/D157492.
Added:
llvm/test/TableGen/repr.td
Modified:
llvm/docs/TableGen/ProgRef.rst
llvm/include/llvm/TableGen/Record.h
llvm/lib/TableGen/Record.cpp
llvm/lib/TableGen/TGLexer.cpp
llvm/lib/TableGen/TGLexer.h
llvm/lib/TableGen/TGParser.cpp
Removed:
################################################################################
diff --git a/llvm/docs/TableGen/ProgRef.rst b/llvm/docs/TableGen/ProgRef.rst
index 92cf5d146ff2e05..45e25573b0e00f0 100644
--- a/llvm/docs/TableGen/ProgRef.rst
+++ b/llvm/docs/TableGen/ProgRef.rst
@@ -225,10 +225,10 @@ TableGen provides "bang operators" that have a wide variety of uses:
: !getdagname !getdagop !gt !head !if
: !interleave !isa !le !listconcat !listremove
: !listsplat !logtwo !lt !mul !ne
- : !not !or !range !setdagarg !setdagname
- : !setdagop !shl !size !sra !srl
- : !strconcat !sub !subst !substr !tail
- : !tolower !toupper !xor
+ : !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
diff erent
syntax compared to other bang operators, so it is defined separately:
@@ -1850,6 +1850,10 @@ and non-0 as true.
``!range(``\ *list*\ ``)``
Equivalent to ``!range(0, !size(list))``.
+``!repr(``\ *value*` ``)``
+ Represents *value* as a string. String format for the value is not
+ guaranteed to be stable. Intended for debugging purposes only.
+
``!setdagarg(``\ *dag*\ ``,``\ *key*\ ``,``\ *arg*\ ``)``
This operator produces a DAG node with the same operator and arguments as
*dag*, but replacing the value of the argument specified by the *key* with
diff --git a/llvm/include/llvm/TableGen/Record.h b/llvm/include/llvm/TableGen/Record.h
index 7d743d24f4801ba..5d6877cfacdcf19 100644
--- a/llvm/include/llvm/TableGen/Record.h
+++ b/llvm/include/llvm/TableGen/Record.h
@@ -845,7 +845,8 @@ class UnOpInit : public OpInit, public FoldingSetNode {
SIZE,
EMPTY,
GETDAGOP,
- LOG2
+ LOG2,
+ REPR
};
private:
diff --git a/llvm/lib/TableGen/Record.cpp b/llvm/lib/TableGen/Record.cpp
index 8709b176f825b9b..24b48b453e63e55 100644
--- a/llvm/lib/TableGen/Record.cpp
+++ b/llvm/lib/TableGen/Record.cpp
@@ -797,6 +797,22 @@ void UnOpInit::Profile(FoldingSetNodeID &ID) const {
Init *UnOpInit::Fold(Record *CurRec, bool IsFinal) const {
RecordKeeper &RK = getRecordKeeper();
switch (getOpcode()) {
+ case REPR:
+ if (LHS->isConcrete()) {
+ // If it is a Record, print the full content.
+ if (const auto *Def = dyn_cast<DefInit>(LHS)) {
+ std::string S;
+ raw_string_ostream OS(S);
+ OS << *Def->getDef();
+ OS.flush();
+ return StringInit::get(RK, S);
+ }
+ // Otherwise, print the value of the variable.
+ else {
+ return StringInit::get(RK, LHS->getAsString());
+ }
+ }
+ break;
case TOLOWER:
if (StringInit *LHSs = dyn_cast<StringInit>(LHS))
return StringInit::get(RK, LHSs->getValue().lower());
@@ -957,6 +973,9 @@ std::string UnOpInit::getAsString() const {
case EMPTY: Result = "!empty"; break;
case GETDAGOP: Result = "!getdagop"; break;
case LOG2 : Result = "!logtwo"; break;
+ case REPR:
+ Result = "!repr";
+ break;
case TOLOWER:
Result = "!tolower";
break;
diff --git a/llvm/lib/TableGen/TGLexer.cpp b/llvm/lib/TableGen/TGLexer.cpp
index 1730f5d88ac5aa7..d5140e91fce9e94 100644
--- a/llvm/lib/TableGen/TGLexer.cpp
+++ b/llvm/lib/TableGen/TGLexer.cpp
@@ -605,6 +605,7 @@ tgtok::TokKind TGLexer::LexExclaim() {
.Case("exists", tgtok::XExists)
.Case("tolower", tgtok::XToLower)
.Case("toupper", tgtok::XToUpper)
+ .Case("repr", tgtok::XRepr)
.Default(tgtok::Error);
return Kind != tgtok::Error ? Kind : ReturnError(Start-1, "Unknown operator");
diff --git a/llvm/lib/TableGen/TGLexer.h b/llvm/lib/TableGen/TGLexer.h
index 7c5594bb4da4d31..4429c91b7c9cf76 100644
--- a/llvm/lib/TableGen/TGLexer.h
+++ b/llvm/lib/TableGen/TGLexer.h
@@ -155,7 +155,8 @@ enum TokKind {
XGetDagName,
XSetDagArg,
XSetDagName,
- BANG_OPERATOR_LAST = XSetDagName,
+ XRepr,
+ BANG_OPERATOR_LAST = XRepr,
// String valued tokens.
STRING_VALUE_FIRST,
diff --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp
index 6990a469c6841d9..2e61925f55651ea 100644
--- a/llvm/lib/TableGen/TGParser.cpp
+++ b/llvm/lib/TableGen/TGParser.cpp
@@ -1168,6 +1168,7 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
case tgtok::XSize:
case tgtok::XEmpty:
case tgtok::XCast:
+ case tgtok::XRepr:
case tgtok::XGetDagOp: { // Value ::= !unop '(' Value ')'
UnOpInit::UnaryOp Code;
RecTy *Type = nullptr;
@@ -1185,6 +1186,11 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
return nullptr;
}
+ break;
+ case tgtok::XRepr:
+ Lex.Lex(); // eat the operation
+ Code = UnOpInit::REPR;
+ Type = StringRecTy::get(Records);
break;
case tgtok::XToLower:
Lex.Lex(); // eat the operation
diff --git a/llvm/test/TableGen/repr.td b/llvm/test/TableGen/repr.td
new file mode 100644
index 000000000000000..20635f3840122da
--- /dev/null
+++ b/llvm/test/TableGen/repr.td
@@ -0,0 +1,51 @@
+// RUN: llvm-tblgen %s | FileCheck %s
+
+class PrintString<string s> {
+ string S = s;
+}
+
+def op;
+def case_01 : PrintString<!repr((op op, op))>;
+// CHECK-LABEL: def case_01 { // PrintString
+// CHECK-NEXT: string S = "(op op, op)";
+// CHECK-NEXT: }
+
+def case_02 : PrintString<!repr(32)>;
+// CHECK-LABEL: def case_02 { // PrintString
+// CHECK-NEXT: string S = "32";
+// CHECK-NEXT: }
+
+multiclass Multi<int i, bits<3> b> {
+ defvar IncI = !repr(!add(i,1));
+ def _IncI : PrintString<IncI>;
+ def _b : PrintString<!repr(b)>;
+}
+
+defm case_03 : Multi<2, 0b111>;
+// CHECK-LABEL: def case_03_IncI { // PrintString
+// CHECK-NEXT: string S = "3";
+// CHECK-NEXT: }
+// CHECK-LABEL: def case_03_b { // PrintString
+// CHECK-NEXT: string S = "{ 1, 1, 1 }";
+// CHECK-NEXT: }
+
+def case_04 : PrintString<!repr(!foreach(i, [1,2,3], !mul(i,2)))>;
+// CHECK-LABEL: def case_04 { // PrintString
+// CHECK-NEXT: string S = "[2, 4, 6]";
+// CHECK-NEXT: }
+
+// Show the dumping of full records...
+def case_05 : PrintString<!repr(case_04)>;
+// CHECK-LABEL: def case_05 { // PrintString
+// CHECK-NEXT: string S = "case_04 { // PrintString
+// CHECK-NEXT: string S = "[2, 4, 6]";
+// CHECK-NEXT: }
+// CHECK-NEXT: ";
+// CHECK-NEXT: }
+
+// ... and how !repr
diff ers compared to !cast<string>.
+def case_06 : PrintString<!cast<string>(case_04)>;
+// CHECK-LABEL: def case_06 { // PrintString
+// CHECK-NEXT: string S = "case_04";
+// CHECK-NEXT: }
+
More information about the llvm-commits
mailing list