Add --dump-tree-dot to enable dumping Ast Tree .dot files (#3636)

This commit is contained in:
Marcel Chang 2022-10-01 23:05:33 +08:00 committed by GitHub
parent f1ba6cb517
commit 526e6b9fc7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 90 additions and 2 deletions

View File

@ -71,6 +71,7 @@ Ludwig Rogiers
Lukasz Dalek
Maarten De Braekeleer
Maciej Sobkowski
Marcel Chang
Marco Widmer
Mariusz Glebocki
Markus Krause

View File

@ -373,6 +373,12 @@ Summary:
<--dump-tree>` may be useful if the dump files are large and not
desired.
.. option:: --dump-tree-dot
Rarely needed. Enable dumping Ast .tree.dot debug files in Graphviz
Dot format. This option implies :vlopt:`--dump-tree`, unless
:vlopt:`--dumpi-tree` was passed explicitly.
.. option:: --dump-tree-addrids
Rarely needed - for developer use. Replace AST node addresses with

View File

@ -1137,6 +1137,16 @@ Similarly the ``NETLIST`` has a list of modules referred to by its
``op1p()`` pointer.
.tree.dot Output
----------------
``*.tree.dot`` files are dumps of the AST Tree in `Graphviz
<https://www.graphviz.org>`__ dot format. This can be used to
visualize the AST Tree. The vertices correspond to ``AstNode``
instances, and the edges represent the pointers (``op1p``,
``op2p``, etc) between the nodes.
Debugging with GDB
------------------

View File

@ -1141,6 +1141,46 @@ void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump, boo
}
}
static void drawChildren(std::ostream& os, const AstNode* thisp, const AstNode* childp, const std::string& childName) {
if (childp) {
os << "\tn" << cvtToHex(thisp) << " -> n" << cvtToHex(childp) << " ["
<< "label=\"" << childName << "\" color=red];\n";
for (const AstNode* nodep = childp; nodep; nodep = nodep->nextp()) {
nodep->dumpTreeDot(os);
if (nodep->nextp()) {
os << "\tn" << cvtToHex(nodep) << " -> n" << cvtToHex(nodep->nextp()) << " ["
<< "label=\"next\" color=red];\n";
os << "\t{rank=same; n" << cvtToHex(nodep) << ", n" << cvtToHex(nodep->nextp())
<< "}\n";
}
}
}
}
void AstNode::dumpTreeDot(std::ostream& os) const {
os << "\tn" << cvtToHex(this) << "\t["
<< "label=\"" << typeName() << "\\n" <<name()
<< "\"];\n";
drawChildren(os, this, m_op1p, "op1");
drawChildren(os, this, m_op2p, "op2");
drawChildren(os, this, m_op3p, "op3");
drawChildren(os, this, m_op4p, "op4");
}
void AstNode::dumpTreeDotFile(const string& filename, bool append, bool doDump) {
if (doDump) {
UINFO(2, "Dumping " << filename << endl);
const std::unique_ptr<std::ofstream> treedotp{V3File::new_ofstream(filename, append)};
if (treedotp->fail()) v3fatal("Can't write " << filename);
*treedotp << "digraph vTree{\n";
*treedotp << "\tgraph\t[label=\"" << filename + ".dot" << "\",\n";
*treedotp << "\t\t labelloc=t, labeljust=l,\n";
*treedotp << "\t\t //size=\"7.5,10\",\n" << "];\n";
dumpTreeDot(*treedotp);
*treedotp << "}\n";
}
}
void AstNode::v3errorEndFatal(std::ostringstream& str) const {
v3errorEnd(str);
assert(0); // LCOV_EXCL_LINE

View File

@ -1862,6 +1862,8 @@ public:
void dumpTreeFile(const string& filename, bool append = false, bool doDump = true,
bool doCheck = true);
static void dumpTreeFileGdb(const AstNode* nodep, const char* filenamep = nullptr);
void dumpTreeDot(std::ostream& os = std::cout) const;
void dumpTreeDotFile(const string& filename, bool append = false, bool doDump = true);
// METHODS - queries
// Changes control flow, disable some optimizations

View File

@ -93,8 +93,11 @@ string V3Global::digitsFilename(int number) {
}
void V3Global::dumpCheckGlobalTree(const string& stagename, int newNumber, bool doDump) {
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename(stagename + ".tree", newNumber), false,
doDump);
const string treeFilename = v3Global.debugFilename(stagename + ".tree", newNumber);
v3Global.rootp()->dumpTreeFile(treeFilename, false, doDump);
if (v3Global.opt.dumpTreeDot()) {
v3Global.rootp()->dumpTreeDotFile(treeFilename + ".dot", false, doDump);
}
if (v3Global.opt.stats()) V3Stats::statsStage(stagename);
}

View File

@ -820,6 +820,11 @@ void V3Options::notify() {
// Mark options as available
m_available = true;
// --dump-tree-dot will turn on tree dumping.
if (!m_dumpLevel.count("tree") && m_dumpLevel.count("tree-dot")) {
m_dumpLevel["tree"] = m_dumpLevel["tree-dot"];
}
}
//######################################################################

View File

@ -454,6 +454,7 @@ public:
bool decoration() const { return m_decoration; }
bool dpiHdrOnly() const { return m_dpiHdrOnly; }
bool dumpDefines() const { return m_dumpLevel.count("defines") && m_dumpLevel.at("defines"); }
bool dumpTreeDot() const { return m_dumpLevel.count("tree-dot") && m_dumpLevel.at("tree-dot"); }
bool exe() const { return m_exe; }
bool flatten() const { return m_flatten; }
bool gmake() const { return m_gmake; }

View File

@ -0,0 +1,20 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you
# can redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
scenarios(vlt => 1);
top_filename("t/t_EXAMPLE.v");
lint(
v_flags => ["--lint-only --dump-tree-dot"],
);
ok(1);
1;