Refactor DFG context objects (#6232)

- Move All DFG context objects to V3DfgContext.h
- Add separate object for ast2dfg and dfg2ast passes
- Factor out commonalities

No functional change
This commit is contained in:
Geza Lore 2025-07-26 20:37:01 +01:00 committed by GitHub
parent 94ef630490
commit 504884b7d5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 321 additions and 230 deletions

View File

@ -72,10 +72,11 @@ set(HEADERS
V3Descope.h
V3Dfg.h
V3DfgCache.h
V3DfgContext.h
V3DfgOptimizer.h
V3DfgPasses.h
V3DfgPatternStats.h
V3DfgPeephole.h
V3DfgPeepholePatterns.h
V3DfgVertices.h
V3DiagSarif.h
V3DupFinder.h

View File

@ -97,7 +97,7 @@ class AstToDfgVisitor final : public VNVisitor {
// STATE
DfgGraph* const m_dfgp; // The graph being built
V3DfgOptimizationContext& m_ctx; // The optimization context for stats
V3DfgAstToDfgContext& m_ctx; // The context for stats
bool m_foundUnhandled = false; // Found node not implemented as DFG or not implemented 'visit'
std::vector<DfgVertex*> m_uncommittedVertices; // Vertices that we might decide to revert
bool m_converting = false; // We are trying to convert some logic at the moment
@ -886,7 +886,7 @@ class AstToDfgVisitor final : public VNVisitor {
}
// CONSTRUCTOR
explicit AstToDfgVisitor(RootType& root, V3DfgOptimizationContext& ctx)
explicit AstToDfgVisitor(RootType& root, V3DfgAstToDfgContext& ctx)
: m_dfgp{makeDfg(root)}
, m_ctx{ctx} {
// Build the DFG
@ -922,15 +922,15 @@ class AstToDfgVisitor final : public VNVisitor {
}
public:
static DfgGraph* apply(RootType& root, V3DfgOptimizationContext& ctx) {
static DfgGraph* apply(RootType& root, V3DfgAstToDfgContext& ctx) {
return AstToDfgVisitor{root, ctx}.m_dfgp;
}
};
DfgGraph* V3DfgPasses::astToDfg(AstModule& module, V3DfgOptimizationContext& ctx) {
return AstToDfgVisitor</* T_Scoped: */ false>::apply(module, ctx);
DfgGraph* V3DfgPasses::astToDfg(AstModule& module, V3DfgContext& ctx) {
return AstToDfgVisitor</* T_Scoped: */ false>::apply(module, ctx.m_ast2DfgContext);
}
DfgGraph* V3DfgPasses::astToDfg(AstNetlist& netlist, V3DfgOptimizationContext& ctx) {
return AstToDfgVisitor</* T_Scoped: */ true>::apply(netlist, ctx);
DfgGraph* V3DfgPasses::astToDfg(AstNetlist& netlist, V3DfgContext& ctx) {
return AstToDfgVisitor</* T_Scoped: */ true>::apply(netlist, ctx.m_ast2DfgContext);
}

View File

@ -1109,8 +1109,8 @@ public:
}
};
std::pair<std::unique_ptr<DfgGraph>, bool>
V3DfgPasses::breakCycles(const DfgGraph& dfg, V3DfgOptimizationContext& ctx) {
std::pair<std::unique_ptr<DfgGraph>, bool> //
V3DfgPasses::breakCycles(const DfgGraph& dfg, V3DfgContext& ctx) {
// Shorthand for dumping graph at given dump level
const auto dump = [&](int level, const DfgGraph& dfg, const std::string& name) {
if (dumpDfgLevel() >= level) dfg.dumpDotFilePrefixed(ctx.prefix() + "breakCycles-" + name);

286
src/V3DfgContext.h Normal file
View File

@ -0,0 +1,286 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: Persistent context for DFG algorithms
//
// Code available from: https://verilator.org
//
//*************************************************************************
//
// Copyright 2003-2025 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
//
//*************************************************************************
//
// Various context objects hold data that need to persist across invocations
// of a DFG algorithms.
//
//*************************************************************************
#ifndef VERILATOR_V3DFGCONTEXT_H_
#define VERILATOR_V3DFGCONTEXT_H_
#include "config_build.h"
#include "verilatedos.h"
#include "V3DfgPatternStats.h"
#include "V3DfgPeepholePatterns.h"
#include "V3File.h"
#include "V3Stats.h"
#include "V3String.h"
class V3DfgContext;
//////////////////////////////////////////////////////////////////////////////
// Base class for all context objects
//////////////////////////////////////////////////////////////////////////////
class V3DfgSubContext VL_NOT_FINAL {
V3DfgContext& m_ctx; // The whole context
const std::string m_label; // Label to add to stats, etc.
const std::string m_name; // Pass/algorithm name, to be used in statistics
protected:
VL_DEFINE_DEBUG_FUNCTIONS;
V3DfgSubContext(V3DfgContext& ctx, const std::string& label, const char* name)
: m_ctx{ctx}
, m_label{label}
, m_name{name} {}
void addStat(const std::string& what, double value) {
V3Stats::addStat("Optimizations, DFG " + m_label + " " + m_name + ", " + what, value);
}
public:
inline const std::string& prefix() const;
const std::string& label() const { return m_label; }
};
//////////////////////////////////////////////////////////////////////////////
// Contexts for various algorithms - keep sorted
//////////////////////////////////////////////////////////////////////////////
class V3DfgAstToDfgContext final : public V3DfgSubContext {
// Only V3DfgContext can create an instance
friend class V3DfgContext;
public:
// STATE
VDouble0 m_coalescedAssignments; // Number of partial assignments coalesced
VDouble0 m_inputEquations; // Number of input combinational equations
VDouble0 m_representable; // Number of combinational equations representable
VDouble0 m_nonRepDType; // Equations non-representable due to data type
VDouble0 m_nonRepImpure; // Equations non-representable due to impure node
VDouble0 m_nonRepTiming; // Equations non-representable due to timing control
VDouble0 m_nonRepLhs; // Equations non-representable due to lhs
VDouble0 m_nonRepNode; // Equations non-representable due to node type
VDouble0 m_nonRepUnknown; // Equations non-representable due to unknown node
VDouble0 m_nonRepVarRef; // Equations non-representable due to variable reference
VDouble0 m_nonRepWidth; // Equations non-representable due to width mismatch
private:
V3DfgAstToDfgContext(V3DfgContext& ctx, const std::string& label)
: V3DfgSubContext{ctx, label, "AstToDfg"} {}
~V3DfgAstToDfgContext() {
addStat("coalesced assignments", m_coalescedAssignments);
addStat("input equations", m_inputEquations);
addStat("representable", m_representable);
addStat("non-representable (dtype)", m_nonRepDType);
addStat("non-representable (impure)", m_nonRepImpure);
addStat("non-representable (timing)", m_nonRepTiming);
addStat("non-representable (lhs)", m_nonRepLhs);
addStat("non-representable (node)", m_nonRepNode);
addStat("non-representable (unknown)", m_nonRepUnknown);
addStat("non-representable (var ref)", m_nonRepVarRef);
addStat("non-representable (width)", m_nonRepWidth);
// Check the stats are consistent
UASSERT(m_representable //
+ m_nonRepDType //
+ m_nonRepImpure //
+ m_nonRepTiming //
+ m_nonRepLhs //
+ m_nonRepNode //
+ m_nonRepUnknown //
+ m_nonRepVarRef //
+ m_nonRepWidth //
== m_inputEquations,
"Inconsistent statistics");
}
};
class V3DfgBinToOneHotContext final : public V3DfgSubContext {
// Only V3DfgContext can create an instance
friend class V3DfgContext;
public:
// STATE
VDouble0 m_decodersCreated; // Number of bianry to one-hot decoders created
private:
V3DfgBinToOneHotContext(V3DfgContext& ctx, const std::string& label)
: V3DfgSubContext{ctx, label, "BinToOneHot"} {}
~V3DfgBinToOneHotContext() { addStat("decoders created", m_decodersCreated); }
};
class V3DfgBreakCyclesContext final : public V3DfgSubContext {
// Only V3DfgContext can create an instance
friend class V3DfgContext;
public:
// STATE
VDouble0 m_nFixed; // Number of graphs that became acyclic
VDouble0 m_nImproved; // Number of graphs that were imporoved but still cyclic
VDouble0 m_nUnchanged; // Number of graphs that were left unchanged
VDouble0 m_nTrivial; // Number of graphs that were not changed
VDouble0 m_nImprovements; // Number of changes made to graphs
private:
V3DfgBreakCyclesContext(V3DfgContext& ctx, const std::string& label)
: V3DfgSubContext{ctx, label, "BreakCycles"} {}
~V3DfgBreakCyclesContext() {
addStat("made acyclic", m_nFixed);
addStat("improved", m_nImproved);
addStat("left unchanged", m_nUnchanged);
addStat("trivial", m_nTrivial);
addStat("changes applied", m_nImprovements);
}
};
class V3DfgCseContext final : public V3DfgSubContext {
// Only V3DfgContext can create an instance
friend class V3DfgContext;
public:
// STATE
VDouble0 m_eliminated; // Number of common sub-expressions eliminated
private:
V3DfgCseContext(V3DfgContext& ctx, const std::string& label)
: V3DfgSubContext{ctx, label, "CSE"} {}
~V3DfgCseContext() { addStat("expressions eliminated", m_eliminated); }
};
class V3DfgDfgToAstContext final : public V3DfgSubContext {
// Only V3DfgContext can create an instance
friend class V3DfgContext;
public:
// STATE
VDouble0 m_resultEquations; // Number of result combinational equations
private:
V3DfgDfgToAstContext(V3DfgContext& ctx, const std::string& label)
: V3DfgSubContext{ctx, label, "Dfg2Ast"} {}
~V3DfgDfgToAstContext() { addStat("result equations", m_resultEquations); }
};
class V3DfgEliminateVarsContext final : public V3DfgSubContext {
// Only V3DfgContext can create an instance
friend class V3DfgContext;
public:
// STATE
VDouble0 m_varsReplaced; // Number of variables replaced
VDouble0 m_varsRemoved; // Number of variables removed
private:
V3DfgEliminateVarsContext(V3DfgContext& ctx, const std::string& label)
: V3DfgSubContext{ctx, label, "EliminateVars"} {}
~V3DfgEliminateVarsContext() {
addStat("variables replaced", m_varsReplaced);
addStat("variables removed", m_varsRemoved);
}
};
class V3DfgPeepholeContext final : public V3DfgSubContext {
// Only V3DfgContext can create an instance
friend class V3DfgContext;
public:
// STATE
// Enable flags for each optimization
std::array<bool, VDfgPeepholePattern::_ENUM_END> m_enabled;
// Count of applications for each optimization (for statistics)
std::array<VDouble0, VDfgPeepholePattern::_ENUM_END> m_count;
private:
V3DfgPeepholeContext(V3DfgContext& ctx, const std::string& label) VL_MT_DISABLED;
~V3DfgPeepholeContext() VL_MT_DISABLED;
};
class V3DfgRegularizeContext final : public V3DfgSubContext {
// Only V3DfgContext can create an instance
friend class V3DfgContext;
public:
// STATE
VDouble0 m_temporariesIntroduced; // Number of temporaries introduced
private:
V3DfgRegularizeContext(V3DfgContext& ctx, const std::string& label)
: V3DfgSubContext{ctx, label, "Regularize"} {}
~V3DfgRegularizeContext() { addStat("temporaries introduced", m_temporariesIntroduced); }
};
//////////////////////////////////////////////////////////////////////////////
// Top level V3DfgContext
//////////////////////////////////////////////////////////////////////////////
class V3DfgContext final {
const std::string m_label; // Label to add to stats, etc.
const std::string m_prefix; // Prefix to add to file dumps (derived from label)
public:
// STATE
// Global statistics
VDouble0 m_modules; // Number of modules optimized
// Sub contexts - keep sorted by type
V3DfgAstToDfgContext m_ast2DfgContext{*this, m_label};
V3DfgBinToOneHotContext m_binToOneHotContext{*this, m_label};
V3DfgBreakCyclesContext m_breakCyclesContext{*this, m_label};
V3DfgCseContext m_cseContext0{*this, m_label + " 1st"};
V3DfgCseContext m_cseContext1{*this, m_label + " 2nd"};
V3DfgDfgToAstContext m_dfg2AstContext{*this, m_label};
V3DfgEliminateVarsContext m_eliminateVarsContext{*this, m_label};
V3DfgPeepholeContext m_peepholeContext{*this, m_label};
V3DfgRegularizeContext m_regularizeContext{*this, m_label};
// Node pattern collector
V3DfgPatternStats m_patternStats;
// CONSTRUCTOR
explicit V3DfgContext(const std::string& label)
: m_label{label}
, m_prefix{VString::removeWhitespace(label) + "-"} {}
~V3DfgContext() {
const string prefix = "Optimizations, DFG " + label() + " General, ";
V3Stats::addStat(prefix + "modules", m_modules);
// 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
const std::unique_ptr<std::ofstream> ofp{V3File::new_ofstream(filename)};
if (ofp->fail()) v3fatal("Can't write file: " << filename);
m_patternStats.dump(label(), *ofp);
}
}
// ACCESSORS
const std::string& label() const { return m_label; }
const std::string& prefix() const { return m_prefix; }
};
const std::string& V3DfgSubContext::prefix() const { return m_ctx.prefix(); }
#endif //VERILATOR_V3DFGCONTEXT_H_

View File

@ -138,7 +138,7 @@ class DfgToAstVisitor final : DfgVisitor {
// STATE
AstModule* const m_modp; // The parent/result module - This is nullptr when T_Scoped
V3DfgOptimizationContext& m_ctx; // The optimization context for stats
V3DfgDfgToAstContext& m_ctx; // The context for stats
AstNodeExpr* m_resultp = nullptr; // The result node of the current traversal
// METHODS
@ -276,7 +276,7 @@ class DfgToAstVisitor final : DfgVisitor {
#include "V3Dfg__gen_dfg_to_ast.h"
// Constructor
explicit DfgToAstVisitor(DfgGraph& dfg, V3DfgOptimizationContext& ctx)
explicit DfgToAstVisitor(DfgGraph& dfg, V3DfgDfgToAstContext& ctx)
: m_modp{dfg.modulep()}
, m_ctx{ctx} {
// Convert the graph back to combinational assignments
@ -297,13 +297,13 @@ class DfgToAstVisitor final : DfgVisitor {
}
public:
static void apply(DfgGraph& dfg, V3DfgOptimizationContext& ctx) { DfgToAstVisitor{dfg, ctx}; }
static void apply(DfgGraph& dfg, V3DfgDfgToAstContext& ctx) { DfgToAstVisitor{dfg, ctx}; }
};
void V3DfgPasses::dfgToAst(DfgGraph& dfg, V3DfgOptimizationContext& ctx) {
void V3DfgPasses::dfgToAst(DfgGraph& dfg, V3DfgContext& ctx) {
if (dfg.modulep()) {
DfgToAstVisitor</* T_Scoped: */ false>::apply(dfg, ctx);
DfgToAstVisitor</* T_Scoped: */ false>::apply(dfg, ctx.m_dfg2AstContext);
} else {
DfgToAstVisitor</* T_Scoped: */ true>::apply(dfg, ctx);
DfgToAstVisitor</* T_Scoped: */ true>::apply(dfg, ctx.m_dfg2AstContext);
}
}

View File

@ -236,7 +236,7 @@ void V3DfgOptimizer::extract(AstNetlist* netlistp) {
V3Global::dumpCheckGlobalTree("dfg-extract", 0, dumpTreeEitherLevel() >= 3);
}
static void process(DfgGraph& dfg, V3DfgOptimizationContext& ctx) {
static void process(DfgGraph& dfg, V3DfgContext& ctx) {
// Extract the cyclic sub-graphs. We do this because a lot of the optimizations assume a
// DAG, and large, mostly acyclic graphs could not be optimized due to the presence of
// small cycles.
@ -307,7 +307,7 @@ void V3DfgOptimizer::optimize(AstNetlist* netlistp, const string& label) {
const VNUser2InUse user2InUse;
const VNUser3InUse user3InUse;
V3DfgOptimizationContext ctx{label};
V3DfgContext ctx{label};
if (!netlistp->topScopep()) {
// Pre V3Scope application. Run on each module separately.

View File

@ -25,92 +25,6 @@
VL_DEFINE_DEBUG_FUNCTIONS;
V3DfgBinToOneHotContext::~V3DfgBinToOneHotContext() {
V3Stats::addStat("Optimizations, DFG " + m_label + " BinToOneHot, decoders created",
m_decodersCreated);
}
V3DfgBreakCyclesContext::~V3DfgBreakCyclesContext() {
V3Stats::addStat("Optimizations, DFG " + m_label + " BreakCycles, made acyclic", m_nFixed);
V3Stats::addStat("Optimizations, DFG " + m_label + " BreakCycles, improved", m_nImproved);
V3Stats::addStat("Optimizations, DFG " + m_label + " BreakCycles, left unchanged",
m_nUnchanged);
V3Stats::addStat("Optimizations, DFG " + m_label + " BreakCycles, trivial", m_nTrivial);
V3Stats::addStat("Optimizations, DFG " + m_label + " BreakCycles, changes applied",
m_nImprovements);
}
V3DfgCseContext::~V3DfgCseContext() {
V3Stats::addStat("Optimizations, DFG " + m_label + " CSE, expressions eliminated",
m_eliminated);
}
V3DfgRegularizeContext::~V3DfgRegularizeContext() {
V3Stats::addStat("Optimizations, DFG " + m_label + " Regularize, temporaries introduced",
m_temporariesIntroduced);
}
V3DfgEliminateVarsContext::~V3DfgEliminateVarsContext() {
V3Stats::addStat("Optimizations, DFG " + m_label + " EliminateVars, variables replaced",
m_varsReplaced);
V3Stats::addStat("Optimizations, DFG " + m_label + " EliminateVars, variables removed",
m_varsRemoved);
}
static std::string getPrefix(const std::string& label) {
if (label.empty()) return "";
std::string str = VString::removeWhitespace(label);
std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { //
return c == ' ' ? '-' : std::tolower(c);
});
str += "-";
return str;
}
V3DfgOptimizationContext::V3DfgOptimizationContext(const std::string& label)
: m_label{label}
, m_prefix{getPrefix(label)} {}
V3DfgOptimizationContext::~V3DfgOptimizationContext() {
const string prefix = "Optimizations, DFG " + m_label + " ";
V3Stats::addStat(prefix + "General, modules", m_modules);
V3Stats::addStat(prefix + "Ast2Dfg, coalesced assignments", m_coalescedAssignments);
V3Stats::addStat(prefix + "Ast2Dfg, input equations", m_inputEquations);
V3Stats::addStat(prefix + "Ast2Dfg, representable", m_representable);
V3Stats::addStat(prefix + "Ast2Dfg, non-representable (dtype)", m_nonRepDType);
V3Stats::addStat(prefix + "Ast2Dfg, non-representable (impure)", m_nonRepImpure);
V3Stats::addStat(prefix + "Ast2Dfg, non-representable (timing)", m_nonRepTiming);
V3Stats::addStat(prefix + "Ast2Dfg, non-representable (lhs)", m_nonRepLhs);
V3Stats::addStat(prefix + "Ast2Dfg, non-representable (node)", m_nonRepNode);
V3Stats::addStat(prefix + "Ast2Dfg, non-representable (unknown)", m_nonRepUnknown);
V3Stats::addStat(prefix + "Ast2Dfg, non-representable (var ref)", m_nonRepVarRef);
V3Stats::addStat(prefix + "Ast2Dfg, non-representable (width)", m_nonRepWidth);
V3Stats::addStat(prefix + "Dfg2Ast, result equations", m_resultEquations);
// Print the collected patterns
if (v3Global.opt.stats()) {
// Label to lowercase, without spaces
std::string ident = m_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
const std::unique_ptr<std::ofstream> ofp{V3File::new_ofstream(filename)};
if (ofp->fail()) v3fatal("Can't write file: " << filename);
m_patternStats.dump(m_label, *ofp);
}
// Check the stats are consistent
UASSERT(m_inputEquations
== m_representable + m_nonRepDType + m_nonRepImpure + m_nonRepTiming + m_nonRepLhs
+ m_nonRepNode + m_nonRepUnknown + m_nonRepVarRef + m_nonRepWidth,
"Inconsistent statistics");
}
// Common sub-expression elimination
void V3DfgPasses::cse(DfgGraph& dfg, V3DfgCseContext& ctx) {
// Remove common sub-expressions
@ -592,7 +506,7 @@ void V3DfgPasses::eliminateVars(DfgGraph& dfg, V3DfgEliminateVarsContext& ctx) {
for (AstNode* const nodep : replacedVariables) nodep->unlinkFrBack()->deleteTree();
}
void V3DfgPasses::optimize(DfgGraph& dfg, V3DfgOptimizationContext& ctx) {
void V3DfgPasses::optimize(DfgGraph& dfg, V3DfgContext& ctx) {
// There is absolutely nothing useful we can do with a graph of size 2 or less
if (dfg.size() <= 2) return;

View File

@ -20,108 +20,11 @@
#include "config_build.h"
#include "verilatedos.h"
#include "V3DfgPatternStats.h"
#include "V3DfgPeephole.h"
#include "V3DfgContext.h"
class AstModule;
class DfgGraph;
//===========================================================================
// Various context objects hold data that need to persist across invocations
// of a DFG pass.
class V3DfgBinToOneHotContext final {
const std::string m_label; // Label to apply to stats
public:
VDouble0 m_decodersCreated; // Number of bianry to one-hot decoders created
explicit V3DfgBinToOneHotContext(const std::string& label)
: m_label{label} {}
~V3DfgBinToOneHotContext() VL_MT_DISABLED;
};
class V3DfgBreakCyclesContext final {
const std::string m_label; // Label to apply to stats
public:
VDouble0 m_nFixed; // Number of graphs that became acyclic
VDouble0 m_nImproved; // Number of graphs that were imporoved but still cyclic
VDouble0 m_nUnchanged; // Number of graphs that were left unchanged
VDouble0 m_nTrivial; // Number of graphs that were not changed
VDouble0 m_nImprovements; // Number of changes made to graphs
explicit V3DfgBreakCyclesContext(const std::string& label)
: m_label{label} {}
~V3DfgBreakCyclesContext() VL_MT_DISABLED;
};
class V3DfgCseContext final {
const std::string m_label; // Label to apply to stats
public:
VDouble0 m_eliminated; // Number of common sub-expressions eliminated
explicit V3DfgCseContext(const std::string& label)
: m_label{label} {}
~V3DfgCseContext() VL_MT_DISABLED;
};
class V3DfgRegularizeContext final {
const std::string m_label; // Label to apply to stats
public:
VDouble0 m_temporariesIntroduced; // Number of temporaries introduced
explicit V3DfgRegularizeContext(const std::string& label)
: m_label{label} {}
~V3DfgRegularizeContext() VL_MT_DISABLED;
};
class V3DfgEliminateVarsContext final {
const std::string m_label; // Label to apply to stats
public:
VDouble0 m_varsReplaced; // Number of variables replaced
VDouble0 m_varsRemoved; // Number of variables removed
explicit V3DfgEliminateVarsContext(const std::string& label)
: m_label{label} {}
~V3DfgEliminateVarsContext() VL_MT_DISABLED;
};
class V3DfgOptimizationContext final {
const std::string m_label; // Label to add to stats, etc.
const std::string m_prefix; // Prefix to add to file dumps (derived from label)
public:
VDouble0 m_modules; // Number of modules optimized
VDouble0 m_coalescedAssignments; // Number of partial assignments coalesced
VDouble0 m_inputEquations; // Number of input combinational equations
VDouble0 m_representable; // Number of combinational equations representable
VDouble0 m_nonRepDType; // Equations non-representable due to data type
VDouble0 m_nonRepImpure; // Equations non-representable due to impure node
VDouble0 m_nonRepTiming; // Equations non-representable due to timing control
VDouble0 m_nonRepLhs; // Equations non-representable due to lhs
VDouble0 m_nonRepNode; // Equations non-representable due to node type
VDouble0 m_nonRepUnknown; // Equations non-representable due to unknown node
VDouble0 m_nonRepVarRef; // Equations non-representable due to variable reference
VDouble0 m_nonRepWidth; // Equations non-representable due to width mismatch
VDouble0 m_resultEquations; // Number of result combinational equations
V3DfgBinToOneHotContext m_binToOneHotContext{m_label};
V3DfgBreakCyclesContext m_breakCyclesContext{m_label};
V3DfgCseContext m_cseContext0{m_label + " 1st"};
V3DfgCseContext m_cseContext1{m_label + " 2nd"};
V3DfgPeepholeContext m_peepholeContext{m_label};
V3DfgRegularizeContext m_regularizeContext{m_label};
V3DfgEliminateVarsContext m_eliminateVarsContext{m_label};
V3DfgPatternStats m_patternStats;
explicit V3DfgOptimizationContext(const std::string& label) VL_MT_DISABLED;
~V3DfgOptimizationContext() VL_MT_DISABLED;
const std::string& prefix() const { return m_prefix; }
};
namespace V3DfgPasses {
//===========================================================================
// Top level entry points
@ -130,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&, V3DfgOptimizationContext&) VL_MT_DISABLED;
DfgGraph* astToDfg(AstModule&, V3DfgContext&) VL_MT_DISABLED;
// Same as above, but for the entire netlist, after V3Scope
DfgGraph* astToDfg(AstNetlist&, V3DfgOptimizationContext&) VL_MT_DISABLED;
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
@ -142,14 +45,14 @@ DfgGraph* astToDfg(AstNetlist&, V3DfgOptimizationContext&) VL_MT_DISABLED;
// graph is always independent of the original. If an imporoved graph is
// returned, then the returned 'bool' flag indicated if the returned graph is
// acyclic (flag 'true'), or still cyclic (flag 'false').
std::pair<std::unique_ptr<DfgGraph>, bool> breakCycles(const DfgGraph&,
V3DfgOptimizationContext&) VL_MT_DISABLED;
std::pair<std::unique_ptr<DfgGraph>, bool> //
breakCycles(const DfgGraph&, V3DfgContext&) VL_MT_DISABLED;
// Optimize the given DfgGraph
void optimize(DfgGraph&, V3DfgOptimizationContext&) VL_MT_DISABLED;
void optimize(DfgGraph&, V3DfgContext&) VL_MT_DISABLED;
// Convert DfgGraph back into Ast, and insert converted graph back into the Ast.
void dfgToAst(DfgGraph&, V3DfgOptimizationContext&) VL_MT_DISABLED;
void dfgToAst(DfgGraph&, V3DfgContext&) VL_MT_DISABLED;
//===========================================================================
// Intermediate/internal operations

View File

@ -23,21 +23,20 @@
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
#include "V3DfgPeephole.h"
#include "V3Dfg.h"
#include "V3DfgCache.h"
#include "V3DfgPasses.h"
#include "V3DfgPeepholePatterns.h"
#include "V3Stats.h"
#include <cctype>
VL_DEFINE_DEBUG_FUNCTIONS;
V3DfgPeepholeContext::V3DfgPeepholeContext(const std::string& label)
: m_label{label} {
V3DfgPeepholeContext::V3DfgPeepholeContext(V3DfgContext& ctx, const std::string& label)
: V3DfgSubContext{ctx, label, "Peephole"} {
const auto checkEnabled = [this](VDfgPeepholePattern id) {
string str{id.ascii()};
std::string str{id.ascii()};
std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { //
return c == '_' ? '-' : std::tolower(c);
});
@ -50,11 +49,11 @@ V3DfgPeepholeContext::V3DfgPeepholeContext(const std::string& label)
V3DfgPeepholeContext::~V3DfgPeepholeContext() {
const auto emitStat = [this](VDfgPeepholePattern id) {
string str{id.ascii()};
std::string str{id.ascii()};
std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { //
return c == '_' ? ' ' : std::tolower(c);
});
V3Stats::addStat("Optimizations, DFG " + m_label + " Peephole, " + str, m_count[id]);
addStat(str, m_count[id]);
};
#define OPTIMIZATION_EMIT_STATS(id, name) emitStat(VDfgPeepholePattern::id);
FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION(OPTIMIZATION_EMIT_STATS)

View File

@ -132,16 +132,4 @@ public:
operator en() const { return m_e; }
};
struct V3DfgPeepholeContext final {
const std::string m_label; // Label to apply to stats
// Enable flags for each optimization
std::array<bool, VDfgPeepholePattern::_ENUM_END> m_enabled;
// Count of applications for each optimization (for statistics)
std::array<VDouble0, VDfgPeepholePattern::_ENUM_END> m_count;
explicit V3DfgPeepholeContext(const std::string& label) VL_MT_DISABLED;
~V3DfgPeepholeContext() VL_MT_DISABLED;
};
#endif

View File

@ -20,7 +20,7 @@ if not os.path.exists(root + "/.git"):
# Read optimizations
optimizations = []
hdrFile = "../src/V3DfgPeephole.h"
hdrFile = "../src/V3DfgPeepholePatterns.h"
with open(hdrFile, 'r', encoding="utf8") as hdrFh:
prevOpt = ""
lineno = 0

View File

@ -14,6 +14,6 @@ test.scenarios('vlt')
test.compile(verilator_flags2=["--stats"])
test.file_grep(test.stats,
r'Optimizations, DFG pre inline Ast2Dfg, non-representable \(impure\)\s+(\d+)', 1)
r'Optimizations, DFG pre inline AstToDfg, non-representable \(impure\)\s+(\d+)', 1)
test.passes()