Add DFG 'regularize' pass, and improve variable removal (#4937)

This functionality used to be distributed in the removeVars pass and the
final dfgToAst conversion. Instead added a new 'regularize' pass to
convert DFGs into forms that can be trivially converted back to Ast, and
a new 'eliminateVars' pass to remove/repalce redundant variables. This
simplifies dfgToAst significantly and makes the code a bit easier to
follow.

The new 'regularize' pass will ensure that every sub-expression with
multiple uses is assigned to a temporary (unless it's a trivial memory
reference or constant), and will also eliminate or replace redundant
variables. Overall it is a performance neutral change but it does
enable some later improvements which required the graph to be in this
form, and this also happens to be the form required for the dfgToAst
conversion.
This commit is contained in:
Geza Lore
2024-03-02 19:49:29 +00:00
committed by GitHub
parent 0ec32ee404
commit 5e1fc6e24d
16 changed files with 360 additions and 328 deletions
+13 -35
View File
@@ -25,8 +25,6 @@
#include "V3AstUserAllocator.h"
#include "V3Dfg.h"
#include "V3DfgPasses.h"
#include "V3DfgPatternStats.h"
#include "V3File.h"
#include "V3Graph.h"
#include "V3UniqueNames.h"
@@ -242,7 +240,7 @@ void V3DfgOptimizer::optimize(AstNetlist* netlistp, const string& label) {
UINFO(2, __FUNCTION__ << ": " << endl);
// NODE STATE
// AstVar::user1 -> Used by V3DfgPasses::astToDfg and DfgPassed::dfgToAst
// AstVar::user1 -> Used by V3DfgPasses::astToDfg
// AstVar::user2 -> bool: Flag indicating referenced by AstVarXRef (set just below)
// AstVar::user3 -> bool: Flag indicating written by logic not representable as DFG
// (set by V3DfgPasses::astToDfg)
@@ -254,8 +252,6 @@ void V3DfgOptimizer::optimize(AstNetlist* netlistp, const string& label) {
V3DfgOptimizationContext ctx{label};
V3DfgPatternStats patternStats;
// Run the optimization phase
for (AstNode* nodep = netlistp->modulesp(); nodep; nodep = nodep->nextp()) {
// Only optimize proper modules
@@ -282,14 +278,6 @@ void V3DfgOptimizer::optimize(AstNetlist* netlistp, const string& label) {
// Quick sanity check
UASSERT_OBJ(dfg->size() == 0, nodep, "DfgGraph should have become empty");
// For each cyclic component
for (auto& component : cyclicComponents) {
if (dumpDfgLevel() >= 7) component->dumpDotFilePrefixed(ctx.prefix() + "source");
// TODO: Apply optimizations safe for cyclic graphs
// Add back under the main DFG (we will convert everything back in one go)
dfg->addGraph(*component);
}
// For each acyclic component
for (auto& component : acyclicComponents) {
if (dumpDfgLevel() >= 7) component->dumpDotFilePrefixed(ctx.prefix() + "source");
@@ -299,8 +287,18 @@ void V3DfgOptimizer::optimize(AstNetlist* netlistp, const string& label) {
dfg->addGraph(*component);
}
// Accumulate patterns from the optimized graph for reporting
if (v3Global.opt.stats()) patternStats.accumulate(*dfg);
// Eliminate redundant variables. Run this on the whole acyclic DFG. It needs to traverse
// the module to perform variable substitutions. Doing this by component would do
// redundant traversals and can be extremely slow in large modules with many components.
V3DfgPasses::eliminateVars(*dfg, ctx.m_eliminateVarsContext);
// For each cyclic component
for (auto& component : cyclicComponents) {
if (dumpDfgLevel() >= 7) component->dumpDotFilePrefixed(ctx.prefix() + "source");
// TODO: Apply optimizations safe for cyclic graphs
// Add back under the main DFG (we will convert everything back in one go)
dfg->addGraph(*component);
}
// Convert back to Ast
if (dumpDfgLevel() >= 8) dfg->dumpDotFilePrefixed(ctx.prefix() + "whole-optimized");
@@ -308,25 +306,5 @@ void V3DfgOptimizer::optimize(AstNetlist* netlistp, const string& label) {
UASSERT_OBJ(resultModp == modp, modp, "Should be the same module");
}
// Print the collected patterns
if (v3Global.opt.stats()) {
// Label to lowercase, without spaces
std::string ident = label;
std::transform(ident.begin(), ident.end(), ident.begin(), [](unsigned char c) { //
return c == ' ' ? '_' : std::tolower(c);
});
// File to dump to
const std::string filename = v3Global.opt.hierTopDataDir() + "/" + v3Global.opt.prefix()
+ "__stats_dfg_patterns__" + ident + ".txt";
// Open, write, close
std::ofstream* const ofp = V3File::new_ofstream(filename);
if (ofp->fail()) v3fatal("Can't write " << filename);
patternStats.dump(label, *ofp);
ofp->close();
VL_DO_DANGLING(delete ofp, ofp);
}
V3Global::dumpCheckGlobalTree("dfg-optimize", 0, dumpTreeEitherLevel() >= 3);
}