// -*- 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 std::vector m_deleteps; // AstVar/AstVarScope that can be deleted at the end 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() { for (AstNode* const nodep : m_deleteps) { VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } 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_