diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c224960dd..b0d44b037 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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 diff --git a/src/V3DfgAstToDfg.cpp b/src/V3DfgAstToDfg.cpp index f5f4f03ed..b6c91953f 100644 --- a/src/V3DfgAstToDfg.cpp +++ b/src/V3DfgAstToDfg.cpp @@ -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 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::apply(module, ctx); +DfgGraph* V3DfgPasses::astToDfg(AstModule& module, V3DfgContext& ctx) { + return AstToDfgVisitor::apply(module, ctx.m_ast2DfgContext); } -DfgGraph* V3DfgPasses::astToDfg(AstNetlist& netlist, V3DfgOptimizationContext& ctx) { - return AstToDfgVisitor::apply(netlist, ctx); +DfgGraph* V3DfgPasses::astToDfg(AstNetlist& netlist, V3DfgContext& ctx) { + return AstToDfgVisitor::apply(netlist, ctx.m_ast2DfgContext); } diff --git a/src/V3DfgBreakCycles.cpp b/src/V3DfgBreakCycles.cpp index 46a53c6c2..1a009d586 100644 --- a/src/V3DfgBreakCycles.cpp +++ b/src/V3DfgBreakCycles.cpp @@ -1109,8 +1109,8 @@ public: } }; -std::pair, bool> -V3DfgPasses::breakCycles(const DfgGraph& dfg, V3DfgOptimizationContext& ctx) { +std::pair, 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); diff --git a/src/V3DfgContext.h b/src/V3DfgContext.h new file mode 100644 index 000000000..459aae2fd --- /dev/null +++ b/src/V3DfgContext.h @@ -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 m_enabled; + // Count of applications for each optimization (for statistics) + std::array 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 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_ diff --git a/src/V3DfgDfgToAst.cpp b/src/V3DfgDfgToAst.cpp index 520f42622..7b1cab73a 100644 --- a/src/V3DfgDfgToAst.cpp +++ b/src/V3DfgDfgToAst.cpp @@ -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::apply(dfg, ctx); + DfgToAstVisitor::apply(dfg, ctx.m_dfg2AstContext); } else { - DfgToAstVisitor::apply(dfg, ctx); + DfgToAstVisitor::apply(dfg, ctx.m_dfg2AstContext); } } diff --git a/src/V3DfgOptimizer.cpp b/src/V3DfgOptimizer.cpp index 571b413ac..2db9a8265 100644 --- a/src/V3DfgOptimizer.cpp +++ b/src/V3DfgOptimizer.cpp @@ -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. diff --git a/src/V3DfgPasses.cpp b/src/V3DfgPasses.cpp index 0168ba629..d349551d4 100644 --- a/src/V3DfgPasses.cpp +++ b/src/V3DfgPasses.cpp @@ -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 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; diff --git a/src/V3DfgPasses.h b/src/V3DfgPasses.h index 99cd404dd..b17fa1002 100644 --- a/src/V3DfgPasses.h +++ b/src/V3DfgPasses.h @@ -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, bool> breakCycles(const DfgGraph&, - V3DfgOptimizationContext&) VL_MT_DISABLED; +std::pair, 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 diff --git a/src/V3DfgPeephole.cpp b/src/V3DfgPeephole.cpp index f308a0c7c..a6e990029 100644 --- a/src/V3DfgPeephole.cpp +++ b/src/V3DfgPeephole.cpp @@ -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 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) diff --git a/src/V3DfgPeephole.h b/src/V3DfgPeepholePatterns.h similarity index 94% rename from src/V3DfgPeephole.h rename to src/V3DfgPeepholePatterns.h index f08627660..e3fe5c3d0 100644 --- a/src/V3DfgPeephole.h +++ b/src/V3DfgPeepholePatterns.h @@ -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 m_enabled; - // Count of applications for each optimization (for statistics) - std::array m_count; - - explicit V3DfgPeepholeContext(const std::string& label) VL_MT_DISABLED; - ~V3DfgPeepholeContext() VL_MT_DISABLED; -}; - #endif diff --git a/test_regress/t/t_dfg_peephole.py b/test_regress/t/t_dfg_peephole.py index 034ba591c..ffb1819e9 100755 --- a/test_regress/t/t_dfg_peephole.py +++ b/test_regress/t/t_dfg_peephole.py @@ -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 diff --git a/test_regress/t/t_dfg_unhandled.py b/test_regress/t/t_dfg_unhandled.py index f60c4d682..1bb7d5c4a 100755 --- a/test_regress/t/t_dfg_unhandled.py +++ b/test_regress/t/t_dfg_unhandled.py @@ -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()