[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