Internals: Refactor Ast to Dfg conversion for reusability. (#6276)

This is mainly code motion, with minimal algorithmic changes to
facilitate reusing parts in future code. No functional change intended.
This commit is contained in:
Geza Lore 2025-08-08 22:53:12 +01:00 committed by GitHub
parent d1f851e1e1
commit 16d32cdd4a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 614 additions and 477 deletions

File diff suppressed because it is too large Load Diff

View File

@ -171,7 +171,7 @@ public:
private:
V3DfgDfgToAstContext(V3DfgContext& ctx, const std::string& label)
: V3DfgSubContext{ctx, label, "Dfg2Ast"} {}
: V3DfgSubContext{ctx, label, "DfgToAst"} {}
~V3DfgDfgToAstContext() { addStat("result equations", m_resultEquations); }
};
class V3DfgEliminateVarsContext final : public V3DfgSubContext {

View File

@ -262,7 +262,7 @@ class DataflowOptimize final {
// Attempt to convert cyclic components into acyclic ones
std::vector<std::unique_ptr<DfgGraph>> madeAcyclicComponents;
if (v3Global.opt.fDfgBreakCyckes()) {
if (v3Global.opt.fDfgBreakCycles()) {
for (auto it = cyclicComponents.begin(); it != cyclicComponents.end();) {
auto result = V3DfgPasses::breakCycles(**it, m_ctx);
if (!result.first) {
@ -335,7 +335,7 @@ class DataflowOptimize final {
UINFO(4, "Applying DFG optimization to module '" << modp->name() << "'");
++m_ctx.m_modules;
// Build the DFG of this module or netlist
const std::unique_ptr<DfgGraph> dfgp{V3DfgPasses::astToDfg(*modp, m_ctx)};
const std::unique_ptr<DfgGraph> dfgp = V3DfgPasses::astToDfg(*modp, m_ctx);
// Actually process the graph
optimize(*dfgp);
// Convert back to Ast
@ -345,7 +345,7 @@ class DataflowOptimize final {
// Post V3Scope application. Run on whole netlist.
UINFO(4, "Applying DFG optimization to entire netlist");
// Build the DFG of the entire netlist
const std::unique_ptr<DfgGraph> dfgp{V3DfgPasses::astToDfg(*netlistp, m_ctx)};
const std::unique_ptr<DfgGraph> dfgp = V3DfgPasses::astToDfg(*netlistp, m_ctx);
// Actually process the graph
optimize(*dfgp);
// Convert back to Ast

View File

@ -139,6 +139,11 @@ void V3DfgPasses::removeUnused(DfgGraph& dfg) {
vtxp->unlinkDelete(dfg);
}
// Remove unused and undriven variable vertices
for (DfgVertexVar* const vtxp : dfg.varVertices().unlinkable()) {
if (!vtxp->hasSinks() && !vtxp->srcp()) VL_DO_DANGLING(vtxp->unlinkDelete(dfg), vtxp);
}
// Finally remove unused constants
for (DfgConst* const vtxp : dfg.constVertices().unlinkable()) {
if (!vtxp->hasSinks()) VL_DO_DANGLING(vtxp->unlinkDelete(dfg), vtxp);

View File

@ -33,10 +33,10 @@ namespace V3DfgPasses {
// Construct a DfGGraph representing the combinational logic in the given AstModule. The logic
// that is represented by the graph is removed from the given AstModule. Returns the
// constructed DfgGraph.
DfgGraph* astToDfg(AstModule&, V3DfgContext&) VL_MT_DISABLED;
std::unique_ptr<DfgGraph> astToDfg(AstModule&, V3DfgContext&) VL_MT_DISABLED;
// Same as above, but for the entire netlist, after V3Scope
DfgGraph* astToDfg(AstNetlist&, V3DfgContext&) VL_MT_DISABLED;
std::unique_ptr<DfgGraph> astToDfg(AstNetlist&, V3DfgContext&) VL_MT_DISABLED;
// Attempt to make the given cyclic graph into an acyclic, or "less cyclic"
// equivalent. If the returned pointer is null, then no improvement was

View File

@ -736,7 +736,7 @@ public:
bool fConstBitOpTree() const { return m_fConstBitOpTree; }
bool fConstEager() const { return m_fConstEager; }
bool fDedupe() const { return m_fDedupe; }
bool fDfgBreakCyckes() const { return m_fDfgBreakCycles; }
bool fDfgBreakCycles() const { return m_fDfgBreakCycles; }
bool fDfgPeephole() const { return m_fDfgPeephole; }
bool fDfgPreInline() const { return m_fDfgPreInline; }
bool fDfgPostInline() const { return m_fDfgPostInline; }

View File

@ -1250,6 +1250,9 @@ def write_dfg_ast_to_dfg(filename):
continue
fh.write("void visit(Ast{t}* nodep) override {{\n".format(t=node.name))
fh.write(
' UASSERT_OBJ(m_converting, nodep, "AstToDfg visit called without m_converting");\n'
)
fh.write(' UASSERT_OBJ(!nodep->user2p(), nodep, "Already has Dfg vertex");\n\n')
fh.write(" if (unhandled(nodep)) return;\n\n")
for i in range(node.arity):
@ -1259,8 +1262,8 @@ def write_dfg_ast_to_dfg(filename):
' UASSERT_OBJ(nodep->op{j}p()->user2p(), nodep, "Child {j} missing Dfg vertex");\n'
.format(j=i + 1))
fh.write("\n")
fh.write(" Dfg{t}* const vtxp = makeVertex<Dfg{t}>(nodep, *m_dfgp);\n".format(
t=node.name))
fh.write(
" Dfg{t}* const vtxp = makeVertex<Dfg{t}>(nodep, m_dfg);\n".format(t=node.name))
fh.write(" if (!vtxp) {\n")
fh.write(" m_foundUnhandled = true;\n")
fh.write(" ++m_ctx.m_nonRepNode;\n")
@ -1271,7 +1274,6 @@ def write_dfg_ast_to_dfg(filename):
" vtxp->relinkSource<{i}>(nodep->op{j}p()->user2u().to<DfgVertex*>());\n".
format(i=i, j=i + 1))
fh.write("\n")
fh.write(" m_uncommittedVertices.push_back(vtxp);\n")
fh.write(" nodep->user2p(vtxp);\n")
fh.write("}\n")

View File

@ -50,15 +50,15 @@
t/t_dfg_multidriver_dfg_bad.v:31:14: ... Location of first driver
31 | assign v = j;
| ^
t/t_dfg_multidriver_dfg_bad.v:32:17: ... Location of other driver
t/t_dfg_multidriver_dfg_bad.v:32:13: ... Location of other driver
32 | assign v[1] = i;
| ^
| ^
t/t_dfg_multidriver_dfg_bad.v:30:18: ... Only the first driver will be respected
%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:34:18: Elements [0:0] of signal 'w' have multiple combinational drivers
: ... note: In instance 't'
t/t_dfg_multidriver_dfg_bad.v:35:17: ... Location of first driver
t/t_dfg_multidriver_dfg_bad.v:35:13: ... Location of first driver
35 | assign w[0] = i;
| ^
| ^
t/t_dfg_multidriver_dfg_bad.v:36:14: ... Location of other driver
36 | assign w = j;
| ^