Skip to content

Commit db9b6f4

Browse files
authored
[Tablegen] Add keyword dump. (llvm#68793)
The keyword is intended for debugging purpose. It prints a message to stderr. 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 e63ab13 commit db9b6f4

File tree

10 files changed

+280
-36
lines changed

10 files changed

+280
-36
lines changed

llvm/docs/TableGen/ProgRef.rst

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -202,10 +202,10 @@ TableGen has the following reserved keywords, which cannot be used as
202202
identifiers::
203203

204204
assert bit bits class code
205-
dag def else false foreach
206-
defm defset defvar field if
207-
in include int let list
208-
multiclass string then true
205+
dag def dump else false
206+
foreach defm defset defvar field
207+
if in include int let
208+
list multiclass string then true
209209

210210
.. warning::
211211
The ``field`` reserved word is deprecated, except when used with the
@@ -571,7 +571,7 @@ files.
571571
TableGenFile: (`Statement` | `IncludeDirective`
572572
:| `PreprocessorDirective`)*
573573
Statement: `Assert` | `Class` | `Def` | `Defm` | `Defset` | `Defvar`
574-
:| `Foreach` | `If` | `Let` | `MultiClass`
574+
:| `Dump` | `Foreach` | `If` | `Let` | `MultiClass`
575575

576576
The following sections describe each of these top-level statements.
577577

@@ -1275,6 +1275,29 @@ be nested.
12751275
This loop defines records named ``R0``, ``R1``, ``R2``, and ``R3``, along
12761276
with ``F0``, ``F1``, ``F2``, and ``F3``.
12771277

1278+
``dump`` --- print messages to stderr
1279+
-------------------------------------
1280+
1281+
A ``dump`` statement prints the input string to standard error
1282+
output. It is intended for debugging purpose.
1283+
1284+
* At top level, the message is printed immediately.
1285+
1286+
* Within a record/class/multiclass, `dump` gets evaluated at each
1287+
instantiation point of the containing record.
1288+
1289+
.. productionlist::
1290+
Dump: "dump" `string` ";"
1291+
1292+
For example, it can be used in combination with `!repr` to investigate
1293+
the values passed to a multiclass:
1294+
1295+
.. code-block:: text
1296+
1297+
multiclass MC<dag s> {
1298+
dump "s = " # !repr(s);
1299+
}
1300+
12781301
12791302
``if`` --- select statements based on a test
12801303
--------------------------------------------

llvm/include/llvm/TableGen/Error.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ void PrintError(const RecordVal *RecVal, const Twine &Msg);
4343
[[noreturn]] void PrintFatalError(const RecordVal *RecVal, const Twine &Msg);
4444

4545
void CheckAssert(SMLoc Loc, Init *Condition, Init *Message);
46+
void dumpMessage(SMLoc Loc, Init *Message);
4647

4748
extern SourceMgr SrcMgr;
4849
extern unsigned ErrorsPrinted;

llvm/include/llvm/TableGen/Record.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1641,6 +1641,15 @@ class Record {
16411641
: Loc(Loc), Condition(Condition), Message(Message) {}
16421642
};
16431643

1644+
struct DumpInfo {
1645+
SMLoc Loc;
1646+
Init *Message;
1647+
1648+
// User-defined constructor to support std::make_unique(). It can be
1649+
// removed in C++20 when braced initialization is supported.
1650+
DumpInfo(SMLoc Loc, Init *Message) : Loc(Loc), Message(Message) {}
1651+
};
1652+
16441653
private:
16451654
Init *Name;
16461655
// Location where record was instantiated, followed by the location of
@@ -1652,6 +1661,7 @@ class Record {
16521661
SmallVector<Init *, 0> TemplateArgs;
16531662
SmallVector<RecordVal, 0> Values;
16541663
SmallVector<AssertionInfo, 0> Assertions;
1664+
SmallVector<DumpInfo, 0> Dumps;
16551665

16561666
// All superclasses in the inheritance forest in post-order (yes, it
16571667
// must be a forest; diamond-shaped inheritance is not allowed).
@@ -1742,6 +1752,7 @@ class Record {
17421752
ArrayRef<RecordVal> getValues() const { return Values; }
17431753

17441754
ArrayRef<AssertionInfo> getAssertions() const { return Assertions; }
1755+
ArrayRef<DumpInfo> getDumps() const { return Dumps; }
17451756

17461757
ArrayRef<std::pair<Record *, SMRange>> getSuperClasses() const {
17471758
return SuperClasses;
@@ -1802,11 +1813,18 @@ class Record {
18021813
Assertions.push_back(AssertionInfo(Loc, Condition, Message));
18031814
}
18041815

1816+
void addDump(SMLoc Loc, Init *Message) {
1817+
Dumps.push_back(DumpInfo(Loc, Message));
1818+
}
1819+
18051820
void appendAssertions(const Record *Rec) {
18061821
Assertions.append(Rec->Assertions);
18071822
}
18081823

1824+
void appendDumps(const Record *Rec) { Dumps.append(Rec->Dumps); }
1825+
18091826
void checkRecordAssertions();
1827+
void emitRecordDumps();
18101828
void checkUnusedTemplateArgs();
18111829

18121830
bool isSubClassOf(const Record *R) const {

llvm/lib/TableGen/Error.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,4 +170,11 @@ void CheckAssert(SMLoc Loc, Init *Condition, Init *Message) {
170170
}
171171
}
172172

173+
// Dump a message to stderr.
174+
void dumpMessage(SMLoc Loc, Init *Message) {
175+
auto *MessageInit = dyn_cast<StringInit>(Message);
176+
assert(MessageInit && "no debug message to print");
177+
PrintNote(Loc, MessageInit->getValue());
178+
}
179+
173180
} // end namespace llvm

llvm/lib/TableGen/Record.cpp

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -806,9 +806,12 @@ Init *UnOpInit::Fold(Record *CurRec, bool IsFinal) const {
806806
OS << *Def->getDef();
807807
OS.flush();
808808
return StringInit::get(RK, S);
809-
}
810-
// Otherwise, print the value of the variable.
811-
else {
809+
} else {
810+
// Otherwise, print the value of the variable.
811+
//
812+
// NOTE: we could recursively !repr the elements of a list,
813+
// but that could produce a lot of output when printing a
814+
// defset.
812815
return StringInit::get(RK, LHS->getAsString());
813816
}
814817
}
@@ -2272,6 +2275,9 @@ DefInit *VarDefInit::instantiate() {
22722275
// Copy assertions from class to instance.
22732276
NewRec->appendAssertions(Class);
22742277

2278+
// Copy dumps from class to instance.
2279+
NewRec->appendDumps(Class);
2280+
22752281
// Substitute and resolve template arguments
22762282
ArrayRef<Init *> TArgs = Class->getTemplateArgs();
22772283
MapResolver R(NewRec);
@@ -2306,6 +2312,9 @@ DefInit *VarDefInit::instantiate() {
23062312
// Check the assertions.
23072313
NewRec->checkRecordAssertions();
23082314

2315+
// Check the assertions.
2316+
NewRec->emitRecordDumps();
2317+
23092318
Def = DefInit::get(NewRec);
23102319
}
23112320

@@ -2863,6 +2872,11 @@ void Record::resolveReferences(Resolver &R, const RecordVal *SkipVal) {
28632872
Value = Assertion.Message->resolveReferences(R);
28642873
Assertion.Message = Value;
28652874
}
2875+
// Resolve the dump expressions.
2876+
for (auto &Dump : Dumps) {
2877+
Init *Value = Dump.Message->resolveReferences(R);
2878+
Dump.Message = Value;
2879+
}
28662880
}
28672881

28682882
void Record::resolveReferences(Init *NewName) {
@@ -3119,6 +3133,16 @@ void Record::checkRecordAssertions() {
31193133
}
31203134
}
31213135

3136+
void Record::emitRecordDumps() {
3137+
RecordResolver R(*this);
3138+
R.setFinal(true);
3139+
3140+
for (const auto &Dump : getDumps()) {
3141+
Init *Message = Dump.Message->resolveReferences(R);
3142+
dumpMessage(Dump.Loc, Message);
3143+
}
3144+
}
3145+
31223146
// Report a warning if the record has unused template arguments.
31233147
void Record::checkUnusedTemplateArgs() {
31243148
for (const Init *TA : getTemplateArgs()) {

llvm/lib/TableGen/TGLexer.cpp

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -346,31 +346,32 @@ tgtok::TokKind TGLexer::LexIdentifier() {
346346
StringRef Str(IdentStart, CurPtr-IdentStart);
347347

348348
tgtok::TokKind Kind = StringSwitch<tgtok::TokKind>(Str)
349-
.Case("int", tgtok::Int)
350-
.Case("bit", tgtok::Bit)
351-
.Case("bits", tgtok::Bits)
352-
.Case("string", tgtok::String)
353-
.Case("list", tgtok::List)
354-
.Case("code", tgtok::Code)
355-
.Case("dag", tgtok::Dag)
356-
.Case("class", tgtok::Class)
357-
.Case("def", tgtok::Def)
358-
.Case("true", tgtok::TrueVal)
359-
.Case("false", tgtok::FalseVal)
360-
.Case("foreach", tgtok::Foreach)
361-
.Case("defm", tgtok::Defm)
362-
.Case("defset", tgtok::Defset)
363-
.Case("multiclass", tgtok::MultiClass)
364-
.Case("field", tgtok::Field)
365-
.Case("let", tgtok::Let)
366-
.Case("in", tgtok::In)
367-
.Case("defvar", tgtok::Defvar)
368-
.Case("include", tgtok::Include)
369-
.Case("if", tgtok::If)
370-
.Case("then", tgtok::Then)
371-
.Case("else", tgtok::ElseKW)
372-
.Case("assert", tgtok::Assert)
373-
.Default(tgtok::Id);
349+
.Case("int", tgtok::Int)
350+
.Case("bit", tgtok::Bit)
351+
.Case("bits", tgtok::Bits)
352+
.Case("string", tgtok::String)
353+
.Case("list", tgtok::List)
354+
.Case("code", tgtok::Code)
355+
.Case("dag", tgtok::Dag)
356+
.Case("class", tgtok::Class)
357+
.Case("def", tgtok::Def)
358+
.Case("true", tgtok::TrueVal)
359+
.Case("false", tgtok::FalseVal)
360+
.Case("foreach", tgtok::Foreach)
361+
.Case("defm", tgtok::Defm)
362+
.Case("defset", tgtok::Defset)
363+
.Case("multiclass", tgtok::MultiClass)
364+
.Case("field", tgtok::Field)
365+
.Case("let", tgtok::Let)
366+
.Case("in", tgtok::In)
367+
.Case("defvar", tgtok::Defvar)
368+
.Case("include", tgtok::Include)
369+
.Case("if", tgtok::If)
370+
.Case("then", tgtok::Then)
371+
.Case("else", tgtok::ElseKW)
372+
.Case("assert", tgtok::Assert)
373+
.Case("dump", tgtok::Dump)
374+
.Default(tgtok::Id);
374375

375376
// A couple of tokens require special processing.
376377
switch (Kind) {

llvm/lib/TableGen/TGLexer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ enum TokKind {
9898
Defm,
9999
Defset,
100100
Defvar,
101+
Dump,
101102
Foreach,
102103
If,
103104
Let,

0 commit comments

Comments
 (0)