aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/TableGen
diff options
context:
space:
mode:
authorFrancesco Petrogalli <francesco.petrogalli@apple.com>2023-10-19 09:26:36 +0200
committerGitHub <noreply@github.com>2023-10-19 09:26:36 +0200
commitdb9b6f4987394c56102d08566422a867cde01a6d (patch)
tree14649fec316dfde0f8c152650fe7ec7975479521 /llvm/lib/TableGen
parente63ab13c82e78f65baca48d5b5e4f6ea8d55dbc7 (diff)
downloadllvm-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.cpp7
-rw-r--r--llvm/lib/TableGen/Record.cpp30
-rw-r--r--llvm/lib/TableGen/TGLexer.cpp51
-rw-r--r--llvm/lib/TableGen/TGLexer.h1
-rw-r--r--llvm/lib/TableGen/TGParser.cpp68
-rw-r--r--llvm/lib/TableGen/TGParser.h4
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);