Skip to content

Commit cacfac4

Browse files
authored
[TableGen] New bang operator !repr. (llvm#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.
1 parent f635ab3 commit cacfac4

File tree

7 files changed

+89
-6
lines changed

7 files changed

+89
-6
lines changed

llvm/docs/TableGen/ProgRef.rst

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -225,10 +225,10 @@ TableGen provides "bang operators" that have a wide variety of uses:
225225
: !getdagname !getdagop !gt !head !if
226226
: !interleave !isa !le !listconcat !listremove
227227
: !listsplat !logtwo !lt !mul !ne
228-
: !not !or !range !setdagarg !setdagname
229-
: !setdagop !shl !size !sra !srl
230-
: !strconcat !sub !subst !substr !tail
231-
: !tolower !toupper !xor
228+
: !not !or !range !repr !setdagarg
229+
: !setdagname !setdagop !shl !size !sra
230+
: !srl !strconcat !sub !subst !substr
231+
: !tail !tolower !toupper !xor
232232

233233
The ``!cond`` operator has a slightly different
234234
syntax compared to other bang operators, so it is defined separately:
@@ -1850,6 +1850,10 @@ and non-0 as true.
18501850
``!range(``\ *list*\ ``)``
18511851
Equivalent to ``!range(0, !size(list))``.
18521852

1853+
``!repr(``\ *value*` ``)``
1854+
Represents *value* as a string. String format for the value is not
1855+
guaranteed to be stable. Intended for debugging purposes only.
1856+
18531857
``!setdagarg(``\ *dag*\ ``,``\ *key*\ ``,``\ *arg*\ ``)``
18541858
This operator produces a DAG node with the same operator and arguments as
18551859
*dag*, but replacing the value of the argument specified by the *key* with

llvm/include/llvm/TableGen/Record.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -845,7 +845,8 @@ class UnOpInit : public OpInit, public FoldingSetNode {
845845
SIZE,
846846
EMPTY,
847847
GETDAGOP,
848-
LOG2
848+
LOG2,
849+
REPR
849850
};
850851

851852
private:

llvm/lib/TableGen/Record.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -797,6 +797,22 @@ void UnOpInit::Profile(FoldingSetNodeID &ID) const {
797797
Init *UnOpInit::Fold(Record *CurRec, bool IsFinal) const {
798798
RecordKeeper &RK = getRecordKeeper();
799799
switch (getOpcode()) {
800+
case REPR:
801+
if (LHS->isConcrete()) {
802+
// If it is a Record, print the full content.
803+
if (const auto *Def = dyn_cast<DefInit>(LHS)) {
804+
std::string S;
805+
raw_string_ostream OS(S);
806+
OS << *Def->getDef();
807+
OS.flush();
808+
return StringInit::get(RK, S);
809+
}
810+
// Otherwise, print the value of the variable.
811+
else {
812+
return StringInit::get(RK, LHS->getAsString());
813+
}
814+
}
815+
break;
800816
case TOLOWER:
801817
if (StringInit *LHSs = dyn_cast<StringInit>(LHS))
802818
return StringInit::get(RK, LHSs->getValue().lower());
@@ -957,6 +973,9 @@ std::string UnOpInit::getAsString() const {
957973
case EMPTY: Result = "!empty"; break;
958974
case GETDAGOP: Result = "!getdagop"; break;
959975
case LOG2 : Result = "!logtwo"; break;
976+
case REPR:
977+
Result = "!repr";
978+
break;
960979
case TOLOWER:
961980
Result = "!tolower";
962981
break;

llvm/lib/TableGen/TGLexer.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,7 @@ tgtok::TokKind TGLexer::LexExclaim() {
605605
.Case("exists", tgtok::XExists)
606606
.Case("tolower", tgtok::XToLower)
607607
.Case("toupper", tgtok::XToUpper)
608+
.Case("repr", tgtok::XRepr)
608609
.Default(tgtok::Error);
609610

610611
return Kind != tgtok::Error ? Kind : ReturnError(Start-1, "Unknown operator");

llvm/lib/TableGen/TGLexer.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,8 @@ enum TokKind {
155155
XGetDagName,
156156
XSetDagArg,
157157
XSetDagName,
158-
BANG_OPERATOR_LAST = XSetDagName,
158+
XRepr,
159+
BANG_OPERATOR_LAST = XRepr,
159160

160161
// String valued tokens.
161162
STRING_VALUE_FIRST,

llvm/lib/TableGen/TGParser.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1168,6 +1168,7 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
11681168
case tgtok::XSize:
11691169
case tgtok::XEmpty:
11701170
case tgtok::XCast:
1171+
case tgtok::XRepr:
11711172
case tgtok::XGetDagOp: { // Value ::= !unop '(' Value ')'
11721173
UnOpInit::UnaryOp Code;
11731174
RecTy *Type = nullptr;
@@ -1185,6 +1186,11 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
11851186
return nullptr;
11861187
}
11871188

1189+
break;
1190+
case tgtok::XRepr:
1191+
Lex.Lex(); // eat the operation
1192+
Code = UnOpInit::REPR;
1193+
Type = StringRecTy::get(Records);
11881194
break;
11891195
case tgtok::XToLower:
11901196
Lex.Lex(); // eat the operation

llvm/test/TableGen/repr.td

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// RUN: llvm-tblgen %s | FileCheck %s
2+
3+
class PrintString<string s> {
4+
string S = s;
5+
}
6+
7+
def op;
8+
def case_01 : PrintString<!repr((op op, op))>;
9+
// CHECK-LABEL: def case_01 { // PrintString
10+
// CHECK-NEXT: string S = "(op op, op)";
11+
// CHECK-NEXT: }
12+
13+
def case_02 : PrintString<!repr(32)>;
14+
// CHECK-LABEL: def case_02 { // PrintString
15+
// CHECK-NEXT: string S = "32";
16+
// CHECK-NEXT: }
17+
18+
multiclass Multi<int i, bits<3> b> {
19+
defvar IncI = !repr(!add(i,1));
20+
def _IncI : PrintString<IncI>;
21+
def _b : PrintString<!repr(b)>;
22+
}
23+
24+
defm case_03 : Multi<2, 0b111>;
25+
// CHECK-LABEL: def case_03_IncI { // PrintString
26+
// CHECK-NEXT: string S = "3";
27+
// CHECK-NEXT: }
28+
// CHECK-LABEL: def case_03_b { // PrintString
29+
// CHECK-NEXT: string S = "{ 1, 1, 1 }";
30+
// CHECK-NEXT: }
31+
32+
def case_04 : PrintString<!repr(!foreach(i, [1,2,3], !mul(i,2)))>;
33+
// CHECK-LABEL: def case_04 { // PrintString
34+
// CHECK-NEXT: string S = "[2, 4, 6]";
35+
// CHECK-NEXT: }
36+
37+
// Show the dumping of full records...
38+
def case_05 : PrintString<!repr(case_04)>;
39+
// CHECK-LABEL: def case_05 { // PrintString
40+
// CHECK-NEXT: string S = "case_04 { // PrintString
41+
// CHECK-NEXT: string S = "[2, 4, 6]";
42+
// CHECK-NEXT: }
43+
// CHECK-NEXT: ";
44+
// CHECK-NEXT: }
45+
46+
// ... and how !repr differs compared to !cast<string>.
47+
def case_06 : PrintString<!cast<string>(case_04)>;
48+
// CHECK-LABEL: def case_06 { // PrintString
49+
// CHECK-NEXT: string S = "case_04";
50+
// CHECK-NEXT: }
51+

0 commit comments

Comments
 (0)