diff options
author | Francesco Petrogalli <francesco.petrogalli@apple.com> | 2023-10-19 09:26:36 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-10-19 09:26:36 +0200 |
commit | db9b6f4987394c56102d08566422a867cde01a6d (patch) | |
tree | 14649fec316dfde0f8c152650fe7ec7975479521 /llvm/lib/TableGen | |
parent | e63ab13c82e78f65baca48d5b5e4f6ea8d55dbc7 (diff) | |
download | llvm-db9b6f4987394c56102d08566422a867cde01a6d.zip llvm-db9b6f4987394c56102d08566422a867cde01a6d.tar.gz llvm-db9b6f4987394c56102d08566422a867cde01a6d.tar.bz2 |
[Tablegen] Add keyword `dump`. (#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.
Diffstat (limited to 'llvm/lib/TableGen')
-rw-r--r-- | llvm/lib/TableGen/Error.cpp | 7 | ||||
-rw-r--r-- | llvm/lib/TableGen/Record.cpp | 30 | ||||
-rw-r--r-- | llvm/lib/TableGen/TGLexer.cpp | 51 | ||||
-rw-r--r-- | llvm/lib/TableGen/TGLexer.h | 1 | ||||
-rw-r--r-- | llvm/lib/TableGen/TGParser.cpp | 68 | ||||
-rw-r--r-- | llvm/lib/TableGen/TGParser.h | 4 |
6 files changed, 130 insertions, 31 deletions
diff --git a/llvm/lib/TableGen/Error.cpp b/llvm/lib/TableGen/Error.cpp index ebe9129..dabb265 100644 --- a/llvm/lib/TableGen/Error.cpp +++ b/llvm/lib/TableGen/Error.cpp @@ -170,4 +170,11 @@ void CheckAssert(SMLoc Loc, Init *Condition, Init *Message) { } } +// Dump a message to stderr. +void dumpMessage(SMLoc Loc, Init *Message) { + auto *MessageInit = dyn_cast<StringInit>(Message); + assert(MessageInit && "no debug message to print"); + PrintNote(Loc, MessageInit->getValue()); +} + } // end namespace llvm diff --git a/llvm/lib/TableGen/Record.cpp b/llvm/lib/TableGen/Record.cpp index 24b48b4..6759690 100644 --- a/llvm/lib/TableGen/Record.cpp +++ b/llvm/lib/TableGen/Record.cpp @@ -806,9 +806,12 @@ Init *UnOpInit::Fold(Record *CurRec, bool IsFinal) const { OS << *Def->getDef(); OS.flush(); return StringInit::get(RK, S); - } - // Otherwise, print the value of the variable. - else { + } else { + // Otherwise, print the value of the variable. + // + // NOTE: we could recursively !repr the elements of a list, + // but that could produce a lot of output when printing a + // defset. return StringInit::get(RK, LHS->getAsString()); } } @@ -2272,6 +2275,9 @@ DefInit *VarDefInit::instantiate() { // Copy assertions from class to instance. NewRec->appendAssertions(Class); + // Copy dumps from class to instance. + NewRec->appendDumps(Class); + // Substitute and resolve template arguments ArrayRef<Init *> TArgs = Class->getTemplateArgs(); MapResolver R(NewRec); @@ -2306,6 +2312,9 @@ DefInit *VarDefInit::instantiate() { // Check the assertions. NewRec->checkRecordAssertions(); + // Check the assertions. + NewRec->emitRecordDumps(); + Def = DefInit::get(NewRec); } @@ -2863,6 +2872,11 @@ void Record::resolveReferences(Resolver &R, const RecordVal *SkipVal) { Value = Assertion.Message->resolveReferences(R); Assertion.Message = Value; } + // Resolve the dump expressions. + for (auto &Dump : Dumps) { + Init *Value = Dump.Message->resolveReferences(R); + Dump.Message = Value; + } } void Record::resolveReferences(Init *NewName) { @@ -3119,6 +3133,16 @@ void Record::checkRecordAssertions() { } } +void Record::emitRecordDumps() { + RecordResolver R(*this); + R.setFinal(true); + + for (const auto &Dump : getDumps()) { + Init *Message = Dump.Message->resolveReferences(R); + dumpMessage(Dump.Loc, Message); + } +} + // Report a warning if the record has unused template arguments. void Record::checkUnusedTemplateArgs() { for (const Init *TA : getTemplateArgs()) { diff --git a/llvm/lib/TableGen/TGLexer.cpp b/llvm/lib/TableGen/TGLexer.cpp index d5140e9..c811a67d 100644 --- a/llvm/lib/TableGen/TGLexer.cpp +++ b/llvm/lib/TableGen/TGLexer.cpp @@ -346,31 +346,32 @@ tgtok::TokKind TGLexer::LexIdentifier() { StringRef Str(IdentStart, CurPtr-IdentStart); tgtok::TokKind Kind = StringSwitch<tgtok::TokKind>(Str) - .Case("int", tgtok::Int) - .Case("bit", tgtok::Bit) - .Case("bits", tgtok::Bits) - .Case("string", tgtok::String) - .Case("list", tgtok::List) - .Case("code", tgtok::Code) - .Case("dag", tgtok::Dag) - .Case("class", tgtok::Class) - .Case("def", tgtok::Def) - .Case("true", tgtok::TrueVal) - .Case("false", tgtok::FalseVal) - .Case("foreach", tgtok::Foreach) - .Case("defm", tgtok::Defm) - .Case("defset", tgtok::Defset) - .Case("multiclass", tgtok::MultiClass) - .Case("field", tgtok::Field) - .Case("let", tgtok::Let) - .Case("in", tgtok::In) - .Case("defvar", tgtok::Defvar) - .Case("include", tgtok::Include) - .Case("if", tgtok::If) - .Case("then", tgtok::Then) - .Case("else", tgtok::ElseKW) - .Case("assert", tgtok::Assert) - .Default(tgtok::Id); + .Case("int", tgtok::Int) + .Case("bit", tgtok::Bit) + .Case("bits", tgtok::Bits) + .Case("string", tgtok::String) + .Case("list", tgtok::List) + .Case("code", tgtok::Code) + .Case("dag", tgtok::Dag) + .Case("class", tgtok::Class) + .Case("def", tgtok::Def) + .Case("true", tgtok::TrueVal) + .Case("false", tgtok::FalseVal) + .Case("foreach", tgtok::Foreach) + .Case("defm", tgtok::Defm) + .Case("defset", tgtok::Defset) + .Case("multiclass", tgtok::MultiClass) + .Case("field", tgtok::Field) + .Case("let", tgtok::Let) + .Case("in", tgtok::In) + .Case("defvar", tgtok::Defvar) + .Case("include", tgtok::Include) + .Case("if", tgtok::If) + .Case("then", tgtok::Then) + .Case("else", tgtok::ElseKW) + .Case("assert", tgtok::Assert) + .Case("dump", tgtok::Dump) + .Default(tgtok::Id); // A couple of tokens require special processing. switch (Kind) { diff --git a/llvm/lib/TableGen/TGLexer.h b/llvm/lib/TableGen/TGLexer.h index 4429c91..2e2aa59 100644 --- a/llvm/lib/TableGen/TGLexer.h +++ b/llvm/lib/TableGen/TGLexer.h @@ -98,6 +98,7 @@ enum TokKind { Defm, Defset, Defvar, + Dump, Foreach, If, Let, diff --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp index 2e61925..7d8f91c 100644 --- a/llvm/lib/TableGen/TGParser.cpp +++ b/llvm/lib/TableGen/TGParser.cpp @@ -313,6 +313,9 @@ bool TGParser::AddSubClass(Record *CurRec, SubClassReference &SubClass) { // Copy the subclass record's assertions to the new record. CurRec->appendAssertions(SC); + // Copy the subclass record's dumps to the new record. + CurRec->appendDumps(SC); + Init *Name; if (CurRec->isClass()) Name = VarInit::get(QualifiedNameOfImplicitName(*CurRec), @@ -376,7 +379,7 @@ bool TGParser::AddSubMultiClass(MultiClass *CurMC, /// Add a record, foreach loop, or assertion to the current context. bool TGParser::addEntry(RecordsEntry E) { - assert((!!E.Rec + !!E.Loop + !!E.Assertion) == 1 && + assert((!!E.Rec + !!E.Loop + !!E.Assertion + !!E.Dump) == 1 && "RecordsEntry has invalid number of items"); // If we are parsing a loop, add it to the loop's entries. @@ -404,6 +407,11 @@ bool TGParser::addEntry(RecordsEntry E) { return false; } + if (E.Dump) { + dumpMessage(E.Dump->Loc, E.Dump->Message); + return false; + } + // It must be a record, so finish it off. return addDefOne(std::move(E.Rec)); } @@ -498,6 +506,18 @@ bool TGParser::resolve(const std::vector<RecordsEntry> &Source, else CheckAssert(E.Assertion->Loc, Condition, Message); + } else if (E.Dump) { + MapResolver R; + for (const auto &S : Substs) + R.set(S.first, S.second); + Init *Message = E.Dump->Message->resolveReferences(R); + + if (Dest) + Dest->push_back( + std::make_unique<Record::DumpInfo>(E.Dump->Loc, Message)); + else + dumpMessage(E.Dump->Loc, Message); + } else { auto Rec = std::make_unique<Record>(*E.Rec); if (Loc) @@ -545,6 +565,9 @@ bool TGParser::addDefOne(std::unique_ptr<Record> Rec) { // Check the assertions. Rec->checkRecordAssertions(); + // Run the dumps. + Rec->emitRecordDumps(); + // If ObjectBody has template arguments, it's an error. assert(Rec->getTemplateArgs().empty() && "How'd this get template args?"); @@ -3405,6 +3428,7 @@ bool TGParser::ParseTemplateArgList(Record *CurRec) { /// BodyItem ::= Declaration ';' /// BodyItem ::= LET ID OptionalBitList '=' Value ';' /// BodyItem ::= Defvar +/// BodyItem ::= Dump /// BodyItem ::= Assert /// bool TGParser::ParseBodyItem(Record *CurRec) { @@ -3414,6 +3438,9 @@ bool TGParser::ParseBodyItem(Record *CurRec) { if (Lex.getCode() == tgtok::Defvar) return ParseDefvar(CurRec); + if (Lex.getCode() == tgtok::Dump) + return ParseDump(nullptr, CurRec); + if (Lex.getCode() != tgtok::Let) { if (!ParseDeclaration(CurRec, false)) return true; @@ -3510,6 +3537,10 @@ bool TGParser::ApplyLetStack(RecordsEntry &Entry) { if (Entry.Assertion) return false; + // Let bindings are not applied to dumps. + if (Entry.Dump) + return false; + for (auto &E : Entry.Loop->Entries) { if (ApplyLetStack(E)) return true; @@ -4090,13 +4121,14 @@ bool TGParser::ParseMultiClass() { while (Lex.getCode() != tgtok::r_brace) { switch (Lex.getCode()) { default: - return TokError("expected 'assert', 'def', 'defm', 'defvar', " + return TokError("expected 'assert', 'def', 'defm', 'defvar', 'dump', " "'foreach', 'if', or 'let' in multiclass body"); case tgtok::Assert: case tgtok::Def: case tgtok::Defm: case tgtok::Defvar: + case tgtok::Dump: case tgtok::Foreach: case tgtok::If: case tgtok::Let: @@ -4240,15 +4272,18 @@ bool TGParser::ParseDefm(MultiClass *CurMultiClass) { /// Object ::= Defset /// Object ::= Defvar /// Object ::= Assert +/// Object ::= Dump bool TGParser::ParseObject(MultiClass *MC) { switch (Lex.getCode()) { default: return TokError( - "Expected assert, class, def, defm, defset, foreach, if, or let"); + "Expected assert, class, def, defm, defset, dump, foreach, if, or let"); case tgtok::Assert: return ParseAssert(MC); case tgtok::Def: return ParseDef(MC); case tgtok::Defm: return ParseDefm(MC); case tgtok::Defvar: return ParseDefvar(); + case tgtok::Dump: + return ParseDump(MC); case tgtok::Foreach: return ParseForeach(MC); case tgtok::If: return ParseIf(MC); case tgtok::Let: return ParseTopLevelLet(MC); @@ -4359,3 +4394,30 @@ LLVM_DUMP_METHOD void MultiClass::dump() const { E.dump(); } #endif + +bool TGParser::ParseDump(MultiClass *CurMultiClass, Record *CurRec) { + // Location of the `dump` statement. + SMLoc Loc = Lex.getLoc(); + assert(Lex.getCode() == tgtok::Dump && "Unknown tok"); + Lex.Lex(); // eat the operation + + Init *Message = ParseValue(CurRec); + if (!Message) + return true; + + // Allow to use dump directly on `defvar` and `def`, by wrapping + // them with a `!repl`. + if (isa<DefInit>(Message)) + Message = UnOpInit::get(UnOpInit::REPR, Message, StringRecTy::get(Records)) + ->Fold(CurRec); + + if (!consume(tgtok::semi)) + return TokError("expected ';'"); + + if (CurRec) + CurRec->addDump(Loc, Message); + else + addEntry(std::make_unique<Record::DumpInfo>(Loc, Message)); + + return false; +} diff --git a/llvm/lib/TableGen/TGParser.h b/llvm/lib/TableGen/TGParser.h index d42cdad..c5365ff 100644 --- a/llvm/lib/TableGen/TGParser.h +++ b/llvm/lib/TableGen/TGParser.h @@ -41,6 +41,7 @@ struct RecordsEntry { std::unique_ptr<Record> Rec; std::unique_ptr<ForeachLoop> Loop; std::unique_ptr<Record::AssertionInfo> Assertion; + std::unique_ptr<Record::DumpInfo> Dump; void dump() const; @@ -49,6 +50,8 @@ struct RecordsEntry { RecordsEntry(std::unique_ptr<ForeachLoop> Loop) : Loop(std::move(Loop)) {} RecordsEntry(std::unique_ptr<Record::AssertionInfo> Assertion) : Assertion(std::move(Assertion)) {} + RecordsEntry(std::unique_ptr<Record::DumpInfo> Dump) + : Dump(std::move(Dump)) {} }; /// ForeachLoop - Record the iteration state associated with a for loop. @@ -262,6 +265,7 @@ private: // Parser methods. bool ParseDef(MultiClass *CurMultiClass); bool ParseDefset(); bool ParseDefvar(Record *CurRec = nullptr); + bool ParseDump(MultiClass *CurMultiClass, Record *CurRec = nullptr); bool ParseForeach(MultiClass *CurMultiClass); bool ParseIf(MultiClass *CurMultiClass); bool ParseIfBody(MultiClass *CurMultiClass, StringRef Kind); |