Internals: Improve DFG dumping functions
This commit is contained in:
parent
e6e52dd60a
commit
7696b0651c
|
|
@ -259,7 +259,7 @@ DfgVertexVar* DfgGraph::makeNewVar(FileLine* flp, const std::string& name, AstNo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const string toDotId(const DfgVertex& vtx) { return '"' + cvtToHex(&vtx) + '"'; }
|
static const std::string toDotId(const DfgVertex& vtx) { return '"' + cvtToHex(&vtx) + '"'; }
|
||||||
|
|
||||||
// Dump one DfgVertex in Graphviz format
|
// Dump one DfgVertex in Graphviz format
|
||||||
static void dumpDotVertex(std::ostream& os, const DfgVertex& vtx) {
|
static void dumpDotVertex(std::ostream& os, const DfgVertex& vtx) {
|
||||||
|
|
@ -383,25 +383,20 @@ static void dumpDotVertex(std::ostream& os, const DfgVertex& vtx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dump one DfgEdge in Graphviz format
|
// Dump one DfgEdge in Graphviz format
|
||||||
static void dumpDotEdge(std::ostream& os, const DfgEdge& edge, const string& headlabel) {
|
static void dumpDotEdge(std::ostream& os, const DfgEdge& edge, size_t idx) {
|
||||||
os << toDotId(*edge.sourcep()) << " -> " << toDotId(*edge.sinkp());
|
if (!edge.sourcep()) return;
|
||||||
if (!headlabel.empty()) os << " [headlabel=\"" << headlabel << "\"]";
|
const DfgVertex& sink = *edge.sinkp(); // sink is never nullptr
|
||||||
|
os << toDotId(*edge.sourcep()) << " -> " << toDotId(sink);
|
||||||
|
if (sink.arity() > 1 || sink.is<DfgVertexSplice>()) {
|
||||||
|
os << " [headlabel=\"" << sink.srcName(idx) << "\"]";
|
||||||
|
}
|
||||||
os << '\n';
|
os << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dump one DfgVertex and all of its source DfgEdges in Graphviz format
|
void DfgGraph::dumpDot(std::ostream& os, const std::string& label,
|
||||||
static void dumpDotVertexAndSourceEdges(std::ostream& os, const DfgVertex& vtx) {
|
std::function<bool(const DfgVertex&)> p) const {
|
||||||
dumpDotVertex(os, vtx);
|
// This generates a graphviz dump, https://www.graphviz.org
|
||||||
vtx.forEachSourceEdge([&](const DfgEdge& edge, size_t idx) { //
|
|
||||||
if (edge.sourcep()) {
|
|
||||||
string headLabel;
|
|
||||||
if (vtx.arity() > 1 || vtx.is<DfgVertexSplice>()) headLabel = vtx.srcName(idx);
|
|
||||||
dumpDotEdge(os, edge, headLabel);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void DfgGraph::dumpDot(std::ostream& os, const string& label) const {
|
|
||||||
// Header
|
// Header
|
||||||
os << "digraph dfg {\n";
|
os << "digraph dfg {\n";
|
||||||
os << "graph [label=\"" << name();
|
os << "graph [label=\"" << name();
|
||||||
|
|
@ -409,31 +404,53 @@ void DfgGraph::dumpDot(std::ostream& os, const string& label) const {
|
||||||
os << "\", labelloc=t, labeljust=l]\n";
|
os << "\", labelloc=t, labeljust=l]\n";
|
||||||
os << "graph [rankdir=LR]\n";
|
os << "graph [rankdir=LR]\n";
|
||||||
|
|
||||||
// Emit all vertices
|
if (!p) {
|
||||||
forEachVertex([&](const DfgVertex& vtx) { dumpDotVertexAndSourceEdges(os, vtx); });
|
// Emit all vertices and edges
|
||||||
|
forEachVertex([&](const DfgVertex& vtx) {
|
||||||
|
dumpDotVertex(os, vtx);
|
||||||
|
vtx.forEachSourceEdge([&](const DfgEdge& e, size_t i) { dumpDotEdge(os, e, i); });
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Emit vertices that satify the predicate 'p'
|
||||||
|
forEachVertex([&](const DfgVertex& vtx) {
|
||||||
|
if (!p(vtx)) return;
|
||||||
|
dumpDotVertex(os, vtx);
|
||||||
|
vtx.forEachSourceEdge([&](const DfgEdge& e, size_t i) {
|
||||||
|
if (!e.sourcep() || !p(*e.sourcep())) return;
|
||||||
|
dumpDotEdge(os, e, i);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Footer
|
// Footer
|
||||||
os << "}\n";
|
os << "}\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void DfgGraph::dumpDotFile(const string& filename, const string& label) const {
|
std::string DfgGraph::dumpDotString(const std::string& label,
|
||||||
// This generates a file used by graphviz, https://www.graphviz.org
|
std::function<bool(const DfgVertex&)> p) const {
|
||||||
// "hardcoded" parameters:
|
std::stringstream ss;
|
||||||
|
dumpDot(ss, label, p);
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DfgGraph::dumpDotFile(const std::string& filename, const std::string& label,
|
||||||
|
std::function<bool(const DfgVertex&)> p) const {
|
||||||
const std::unique_ptr<std::ofstream> os{V3File::new_ofstream(filename)};
|
const std::unique_ptr<std::ofstream> os{V3File::new_ofstream(filename)};
|
||||||
if (os->fail()) v3fatal("Can't write file: " << filename);
|
if (os->fail()) v3fatal("Can't write file: " << filename);
|
||||||
dumpDot(*os.get(), label);
|
dumpDot(*os.get(), label, p);
|
||||||
os->close();
|
os->close();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DfgGraph::dumpDotFilePrefixed(const string& label) const {
|
void DfgGraph::dumpDotFilePrefixed(const std::string& label,
|
||||||
string filename = name();
|
std::function<bool(const DfgVertex&)> p) const {
|
||||||
|
std::string filename = name();
|
||||||
if (!label.empty()) filename += "-" + label;
|
if (!label.empty()) filename += "-" + label;
|
||||||
dumpDotFile(v3Global.debugFilename(filename) + ".dot", label);
|
dumpDotFile(v3Global.debugFilename(filename) + ".dot", label, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
// LCOV_EXCL_START // Debug function for developer use only
|
// LCOV_EXCL_START // Debug functions for developer use only
|
||||||
void DfgGraph::dumpDotUpstreamCone(const string& fileName, const DfgVertex& vtx,
|
void DfgGraph::dumpDotUpstreamCone(const std::string& fileName, const DfgVertex& vtx,
|
||||||
const string& name) const {
|
const std::string& name) const {
|
||||||
// Open output file
|
// Open output file
|
||||||
const std::unique_ptr<std::ofstream> os{V3File::new_ofstream(fileName)};
|
const std::unique_ptr<std::ofstream> os{V3File::new_ofstream(fileName)};
|
||||||
if (os->fail()) v3fatal("Can't write file: " << fileName);
|
if (os->fail()) v3fatal("Can't write file: " << fileName);
|
||||||
|
|
@ -465,7 +482,8 @@ void DfgGraph::dumpDotUpstreamCone(const string& fileName, const DfgVertex& vtx,
|
||||||
vtxp->forEachSource([&](const DfgVertex& src) { queue.push_back(&src); });
|
vtxp->forEachSource([&](const DfgVertex& src) { queue.push_back(&src); });
|
||||||
|
|
||||||
// Emit this vertex and all of its source edges
|
// Emit this vertex and all of its source edges
|
||||||
dumpDotVertexAndSourceEdges(*os, *vtxp);
|
dumpDotVertex(*os, *vtxp);
|
||||||
|
vtxp->forEachSourceEdge([&](const DfgEdge& e, size_t i) { dumpDotEdge(*os, e, i); });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Footer
|
// Footer
|
||||||
|
|
|
||||||
20
src/V3Dfg.h
20
src/V3Dfg.h
|
|
@ -746,17 +746,27 @@ public:
|
||||||
|
|
||||||
// Dump graph in Graphviz format into the given stream 'os'. 'label' is added to the name of
|
// Dump graph in Graphviz format into the given stream 'os'. 'label' is added to the name of
|
||||||
// the graph which is included in the output.
|
// the graph which is included in the output.
|
||||||
void dumpDot(std::ostream& os, const string& label = "") const VL_MT_DISABLED;
|
// If the predicate function 'p' is provided, only those vertices are dumped that satifty it.
|
||||||
|
void dumpDot(std::ostream& os, const std::string& label,
|
||||||
|
std::function<bool(const DfgVertex&)> p = {}) const VL_MT_DISABLED;
|
||||||
// Dump graph in Graphviz format into a new file with the given 'filename'. 'label' is added to
|
// Dump graph in Graphviz format into a new file with the given 'filename'. 'label' is added to
|
||||||
// the name of the graph which is included in the output.
|
// the name of the graph which is included in the output.
|
||||||
void dumpDotFile(const string& filename, const string& label = "") const VL_MT_DISABLED;
|
// If the predicate function 'p' is provided, only those vertices are dumped that satifty it.
|
||||||
|
void dumpDotFile(const std::string& filename, const std::string& label,
|
||||||
|
std::function<bool(const DfgVertex&)> p = {}) const VL_MT_DISABLED;
|
||||||
|
// Same as dumpDotFile, but returns the contents as a string.
|
||||||
|
std::string dumpDotString(const std::string& label,
|
||||||
|
std::function<bool(const DfgVertex&)> p = {}) const VL_MT_DISABLED;
|
||||||
// Dump graph in Graphviz format into a new automatically numbered debug file. 'label' is
|
// Dump graph in Graphviz format into a new automatically numbered debug file. 'label' is
|
||||||
// added to the name of the graph, which is included in the file name and the output.
|
// added to the name of the graph, which is included in the file name and the output.
|
||||||
void dumpDotFilePrefixed(const string& label = "") const VL_MT_DISABLED;
|
// If the predicate function 'p' is provided, only those vertices are dumped that satifty it.
|
||||||
|
void dumpDotFilePrefixed(const std::string& label,
|
||||||
|
std::function<bool(const DfgVertex&)> p = {}) const VL_MT_DISABLED;
|
||||||
|
|
||||||
// Dump upstream (source) logic cone starting from given vertex into a file with the given
|
// Dump upstream (source) logic cone starting from given vertex into a file with the given
|
||||||
// 'filename'. 'name' is the name of the graph, which is included in the output.
|
// 'filename'. 'name' is the name of the graph, which is included in the output.
|
||||||
void dumpDotUpstreamCone(const string& filename, const DfgVertex& vtx,
|
void dumpDotUpstreamCone(const std::string& filename, const DfgVertex& vtx,
|
||||||
const string& name = "") const VL_MT_DISABLED;
|
const std::string& name = "") const VL_MT_DISABLED;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Specializations of privateTypeTest
|
// Specializations of privateTypeTest
|
||||||
|
|
|
||||||
|
|
@ -1060,6 +1060,13 @@ V3DfgPasses::breakCycles(const DfgGraph& dfg, V3DfgContext& ctx) {
|
||||||
}
|
}
|
||||||
} while (nImprovements != prevNImprovements);
|
} while (nImprovements != prevNImprovements);
|
||||||
|
|
||||||
|
if (dumpDfgLevel() >= 9) {
|
||||||
|
const auto userDataInUse = res.userDataInUse();
|
||||||
|
V3DfgPasses::colorStronglyConnectedComponents(res);
|
||||||
|
res.dumpDotFilePrefixed(ctx.prefix() + "breakCycles-remaining",
|
||||||
|
[](const DfgVertex& vtx) { return vtx.getUser<uint64_t>(); });
|
||||||
|
}
|
||||||
|
|
||||||
// If an improvement was made, return the still cyclic improved graph
|
// If an improvement was made, return the still cyclic improved graph
|
||||||
if (nImprovements) {
|
if (nImprovements) {
|
||||||
UINFO(7, "Graph was improved " << nImprovements << " times");
|
UINFO(7, "Graph was improved " << nImprovements << " times");
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue