From b998721513b4a230d4709042b36c62082394c5bb Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Wed, 1 Apr 2026 14:13:53 +0100 Subject: [PATCH] Optimize Dfg only once, after V3Scope This patch removes the first two applications of Dfg, which is now only run once before V3Gate. The scoped run can optimize much more contents, and running it only once results in slightly better run-time performance, and simplifies maintenance of Dfg a lot. The drawback of this this is that peak verilation memory use can increase as the earlier applications of Dfg used to reduce the working set sizes of the passes in between. Overall verilation time is not significantly different, but generally slightly faster (it was always dominated by the scoped run which is what we keep here). --- docs/guide/exe_verilator.rst | 22 ++- src/V3AstNodeOther.h | 4 - src/V3Dfg.cpp | 83 ++++----- src/V3Dfg.h | 23 +-- src/V3DfgAstToDfg.cpp | 120 ++++--------- src/V3DfgBreakCycles.cpp | 17 +- src/V3DfgContext.h | 132 +++++++------- src/V3DfgDecomposition.cpp | 18 +- src/V3DfgDfgToAst.cpp | 52 ++---- src/V3DfgOptimizer.cpp | 142 ++++----------- src/V3DfgOptimizer.h | 2 +- src/V3DfgPasses.cpp | 100 +++++++---- src/V3DfgPasses.h | 13 +- src/V3DfgPatternStats.h | 8 +- src/V3DfgPeephole.cpp | 52 +----- src/V3DfgRegularize.cpp | 40 +---- src/V3DfgSynthesize.cpp | 165 +++++++----------- src/V3DfgVertices.h | 92 ++++------ src/V3Options.cpp | 23 +-- src/V3Options.h | 8 +- src/Verilator.cpp | 32 +--- test_regress/t/t_cover_line.out | 4 +- test_regress/t/t_cover_line_cc.info.out | 4 +- test_regress/t/t_dfg_bin_to_one_hot.py | 5 +- test_regress/t/t_dfg_break_cycles.py | 2 - test_regress/t/t_dfg_multidriver_dfg_bad.out | 41 ++--- test_regress/t/t_dfg_oob_sel_rvalue.py | 5 +- test_regress/t/t_dfg_peephole.py | 2 +- test_regress/t/t_dfg_push_sel.py | 10 +- test_regress/t/t_dfg_push_sel_off.py | 12 +- ...ns_scoped.out => t_dfg_stats_patterns.out} | 8 +- ...post_inline.py => t_dfg_stats_patterns.py} | 6 +- .../t/t_dfg_stats_patterns_post_inline.out | 99 ----------- .../t/t_dfg_stats_patterns_pre_inline.out | 98 ----------- .../t/t_dfg_stats_patterns_pre_inline.py | 20 --- test_regress/t/t_dfg_stats_patterns_scoped.py | 21 --- test_regress/t/t_dfg_synthesis.py | 9 +- test_regress/t/t_dfg_synthesis_pre_inline.cpp | 60 ------- test_regress/t/t_dfg_synthesis_pre_inline.py | 98 ----------- test_regress/t/t_dfg_synthesis_pre_inline.v | 34 ---- test_regress/t/t_dfg_true_cycle_bad.out | 2 +- test_regress/t/t_flag_deprecated_bad.out | 3 + test_regress/t/t_flag_deprecated_bad.py | 4 +- test_regress/t/t_inst_tree_inl1_pub0.py | 6 +- test_regress/t/t_inst_tree_inl1_pub1.py | 3 +- test_regress/t/t_json_only_first.out | 13 +- test_regress/t/t_json_only_flat.out | 13 +- test_regress/t/t_json_only_flat_vlvbound.out | 9 +- test_regress/t/t_json_only_primary_io.out | 19 +- .../t/t_lint_always_comb_multidriven_bad.out | 4 - ...int_always_comb_multidriven_public_bad.out | 12 +- .../t/t_lint_multidriven_coverage_bad.out | 3 +- test_regress/t/t_opt_const_dfg.py | 2 +- 53 files changed, 497 insertions(+), 1282 deletions(-) rename test_regress/t/{t_dfg_stats_patterns_scoped.out => t_dfg_stats_patterns.out} (97%) rename test_regress/t/{t_dfg_stats_patterns_post_inline.py => t_dfg_stats_patterns.py} (68%) delete mode 100644 test_regress/t/t_dfg_stats_patterns_post_inline.out delete mode 100644 test_regress/t/t_dfg_stats_patterns_pre_inline.out delete mode 100755 test_regress/t/t_dfg_stats_patterns_pre_inline.py delete mode 100755 test_regress/t/t_dfg_stats_patterns_scoped.py delete mode 100644 test_regress/t/t_dfg_synthesis_pre_inline.cpp delete mode 100755 test_regress/t/t_dfg_synthesis_pre_inline.py delete mode 100644 test_regress/t/t_dfg_synthesis_pre_inline.v diff --git a/docs/guide/exe_verilator.rst b/docs/guide/exe_verilator.rst index 50b727e34..ca2232426 100644 --- a/docs/guide/exe_verilator.rst +++ b/docs/guide/exe_verilator.rst @@ -649,9 +649,12 @@ Summary: .. option:: -fno-dfg - Rarely needed. Disable all use of the DFG-based combinational logic - optimizer. Alias for :vlopt:`-fno-dfg-pre-inline`, - :vlopt:`-fno-dfg-post-inline` and :vlopt:`-fno-dfg-scoped`. + Rarely needed. Disable the DFG-based combinational logic optimizer. + + In versions before 5.048: + + Alias for :vlopt:`-fno-dfg-pre-inline`, :vlopt:`-fno-dfg-post-inline` and + :vlopt:`-fno-dfg-scoped`. .. option:: -fno-dfg-break-cycles @@ -667,11 +670,15 @@ Summary: .. option:: -fno-dfg-post-inline - Rarely needed. Do not apply the DFG optimizer after inlining. + Deprecated and has no effect (ignored). + + In versions before 5.048: Do not apply the DFG optimizer after inlining. .. option:: -fno-dfg-pre-inline - Rarely needed. Do not apply the DFG optimizer before inlining. + Deprecated and has no effect (ignored). + + In versions before 5.048: Do not apply the DFG optimizer before inlining. .. option:: -fno-dfg-push-down-sels @@ -679,7 +686,10 @@ Summary: .. option:: -fno-dfg-scoped - Rarely needed. Do not apply the DFG optimizer across module scopes. + Deprecated; use :vlopt:`-fno-dfg` instead. + + In versions before 5.048: Do not apply the DFG optimizer across module + scopes. .. option:: -fno-expand diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index 0c2632604..177be29ba 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -1963,7 +1963,6 @@ class AstVar final : public AstNode { bool m_ignorePostRead : 1; // Ignore reads in 'Post' blocks during ordering bool m_ignorePostWrite : 1; // Ignore writes in 'Post' blocks during ordering bool m_ignoreSchedWrite : 1; // Ignore writes in scheduling (for special optimizations) - bool m_dfgMultidriven : 1; // Singal is multidriven, used by DFG to avoid repeat processing bool m_dfgTriLowered : 1; // Signal/temporary introduced by tristate lowering bool m_dfgAllowMultidriveTri : 1; // Allow DFG MULTIDRIVEN warning for intentional tri nets bool m_globalConstrained : 1; // Global constraint per IEEE 1800-2023 18.5.8 @@ -2021,7 +2020,6 @@ class AstVar final : public AstNode { m_ignorePostRead = false; m_ignorePostWrite = false; m_ignoreSchedWrite = false; - m_dfgMultidriven = false; m_dfgTriLowered = false; m_dfgAllowMultidriveTri = false; m_globalConstrained = false; @@ -2198,8 +2196,6 @@ public: void setIgnorePostWrite() { m_ignorePostWrite = true; } bool ignoreSchedWrite() const { return m_ignoreSchedWrite; } void setIgnoreSchedWrite() { m_ignoreSchedWrite = true; } - bool dfgMultidriven() const { return m_dfgMultidriven; } - void setDfgMultidriven() { m_dfgMultidriven = true; } bool dfgTriLowered() const { return m_dfgTriLowered; } void setDfgTriLowered() { m_dfgTriLowered = true; } bool dfgAllowMultidriveTri() const { return m_dfgAllowMultidriveTri; } diff --git a/src/V3Dfg.cpp b/src/V3Dfg.cpp index 0107b2ace..38e972e39 100644 --- a/src/V3Dfg.cpp +++ b/src/V3Dfg.cpp @@ -18,6 +18,7 @@ #include "V3Dfg.h" +#include "V3Ast.h" #include "V3EmitV.h" #include "V3File.h" @@ -26,18 +27,16 @@ VL_DEFINE_DEBUG_FUNCTIONS; //------------------------------------------------------------------------------ // DfgGraph -DfgGraph::DfgGraph(AstModule* modulep, const string& name) - : m_modulep{modulep} - , m_name{name} {} +DfgGraph::DfgGraph(const string& name) + : m_name{name} {} DfgGraph::~DfgGraph() { forEachVertex([&](DfgVertex& vtx) { vtx.unlinkDelete(*this); }); } std::unique_ptr DfgGraph::clone() const { - const bool scoped = !modulep(); - - DfgGraph* const clonep = new DfgGraph{modulep(), name()}; + // Create the new graph + DfgGraph* const clonep = new DfgGraph{name()}; // Map from original vertex to clone std::unordered_map vtxp2clonep(size() * 2); @@ -54,20 +53,12 @@ std::unique_ptr DfgGraph::clone() const { switch (vtx.type()) { case VDfgType::VarArray: { - if (scoped) { - cp = new DfgVarArray{*clonep, vp->varScopep()}; - } else { - cp = new DfgVarArray{*clonep, vp->varp()}; - } + cp = new DfgVarArray{*clonep, vp->vscp()}; vtxp2clonep.emplace(&vtx, cp); break; } case VDfgType::VarPacked: { - if (scoped) { - cp = new DfgVarPacked{*clonep, vp->varScopep()}; - } else { - cp = new DfgVarPacked{*clonep, vp->varp()}; - } + cp = new DfgVarPacked{*clonep, vp->vscp()}; vtxp2clonep.emplace(&vtx, cp); break; } @@ -78,7 +69,7 @@ std::unique_ptr DfgGraph::clone() const { } } - if (AstNode* const tmpForp = vp->tmpForp()) cp->tmpForp(tmpForp); + if (AstVarScope* const tmpForp = vp->tmpForp()) cp->tmpForp(tmpForp); } // Clone ast reference vertices for (const DfgVertexAst& vtx : m_astVertices) { // LCOV_EXCL_START @@ -203,18 +194,18 @@ void DfgGraph::mergeGraphs(std::vector>&& otherps) { if (otherps.empty()) return; // NODE STATE - // AstVar/AstVarScope::user2p() -> corresponding DfgVertexVar* in 'this' graph + // AstVarScope::user2p() -> corresponding DfgVertexVar* in 'this' graph const VNUser2InUse user2InUse; // Set up Ast Variable -> DfgVertexVar map for 'this' graph - for (DfgVertexVar& vtx : m_varVertices) vtx.nodep()->user2p(&vtx); + for (DfgVertexVar& vtx : m_varVertices) vtx.vscp()->user2p(&vtx); // Merge in each of the other graphs for (const std::unique_ptr& otherp : otherps) { // Process variables for (DfgVertexVar* const vtxp : otherp->m_varVertices.unlinkable()) { // Variabels that are present in 'this', make them use the DfgVertexVar in 'this'. - if (DfgVertexVar* const altp = vtxp->nodep()->user2u().to()) { + if (DfgVertexVar* const altp = vtxp->vscp()->user2u().to()) { DfgVertex* const srcp = vtxp->srcp(); DfgVertex* const defaultp = vtxp->defaultp(); UASSERT_OBJ(!(srcp || defaultp) || (!altp->srcp() && !altp->defaultp()), vtxp, @@ -226,7 +217,7 @@ void DfgGraph::mergeGraphs(std::vector>&& otherps) { continue; } // Otherwise they will be moved - vtxp->nodep()->user2p(vtxp); + vtxp->vscp()->user2p(vtxp); vtxp->m_userGeneration = 0; #ifdef VL_DEBUG vtxp->m_dfgp = this; @@ -279,29 +270,17 @@ std::string DfgGraph::makeUniqueName(const std::string& prefix, size_t n) { DfgVertexVar* DfgGraph::makeNewVar(FileLine* flp, const std::string& name, const DfgDataType& dtype, AstScope* scopep) { - UASSERT_OBJ(!!scopep != !!modulep(), flp, - "makeNewVar scopep should only be provided for a scoped DfgGraph"); - // Create AstVar AstVar* const varp = new AstVar{flp, VVarType::MODULETEMP, name, dtype.astDtypep()}; - - if (scopep) { - // Add AstVar to the scope's module - scopep->modp()->addStmtsp(varp); - // Create AstVarScope - AstVarScope* const vscp = new AstVarScope{flp, scopep, varp}; - // Add to scope - scopep->addVarsp(vscp); - // Create and return the corresponding variable vertex - if (dtype.isArray()) return new DfgVarArray{*this, vscp}; - return new DfgVarPacked{*this, vscp}; - } else { - // Add AstVar to containing module - modulep()->addStmtsp(varp); - // Create and return the corresponding variable vertex - if (dtype.isArray()) return new DfgVarArray{*this, varp}; - return new DfgVarPacked{*this, varp}; - } + // Add AstVar to the scope's module + scopep->modp()->addStmtsp(varp); + // Create AstVarScope + AstVarScope* const vscp = new AstVarScope{flp, scopep, varp}; + // Add to scope + scopep->addVarsp(vscp); + // Create and return the corresponding variable vertex + if (dtype.isArray()) return new DfgVarArray{*this, vscp}; + return new DfgVarPacked{*this, vscp}; } static const std::string toDotId(const DfgVertex& vtx) { return '"' + cvtToHex(&vtx) + '"'; } @@ -309,19 +288,19 @@ static const std::string toDotId(const DfgVertex& vtx) { return '"' + cvtToHex(& // Dump one DfgVertex in Graphviz format static void dumpDotVertex(std::ostream& os, const DfgVertex& vtx) { if (const DfgVertexVar* const varVtxp = vtx.cast()) { - const AstNode* const nodep = varVtxp->nodep(); + const AstVarScope* const vscp = varVtxp->vscp(); os << toDotId(vtx); // Begin attributes os << " ["; // Begin 'label' os << "label=\""; // Name - os << nodep->prettyName(); + os << vscp->prettyName(); // Address os << '\n' << cvtToHex(varVtxp); // Original variable, if any - if (const AstNode* const tmpForp = varVtxp->tmpForp()) { - if (tmpForp != nodep) os << "\ntemporary for: " << tmpForp->prettyName(); + if (const AstVarScope* const tmpForp = varVtxp->tmpForp()) { + if (tmpForp != vscp) os << "\ntemporary for: " << tmpForp->prettyName(); } // Type and fanout os << '\n'; @@ -872,10 +851,8 @@ DfgVertexVar* DfgVertex::getResultVar() { } // Prefer real variables over temporaries - const bool resIsTemp - = resp->varp() ? resp->varp()->isTemp() : resp->varScopep()->varp()->isTemp(); - const bool varIsTemp - = varp->varp() ? varp->varp()->isTemp() : varp->varScopep()->varp()->isTemp(); + const bool resIsTemp = resp->vscp()->varp()->isTemp(); + const bool varIsTemp = varp->vscp()->varp()->isTemp(); if (resIsTemp != varIsTemp) { if (resIsTemp) resp = varp; return false; @@ -893,7 +870,7 @@ DfgVertexVar* DfgVertex::getResultVar() { return false; } // Prefer the one with the lexically smaller name - if (const int cmp = resp->nodep()->name().compare(varp->nodep()->name())) { + if (const int cmp = resp->vscp()->name().compare(varp->vscp()->name())) { if (cmp > 0) resp = varp; return false; } @@ -906,13 +883,13 @@ DfgVertexVar* DfgVertex::getResultVar() { AstScope* DfgVertex::scopep(ScopeCache& cache, bool tryResultVar) VL_MT_DISABLED { // If this is a variable, we are done if (const DfgVertexVar* const varp = this->cast()) { - return varp->varScopep()->scopep(); + return varp->vscp()->scopep(); } // Try the result var first if instructed (usully only in the recursive case) if (tryResultVar) { if (const DfgVertexVar* const varp = this->getResultVar()) { - return varp->varScopep()->scopep(); + return varp->vscp()->scopep(); } } diff --git a/src/V3Dfg.h b/src/V3Dfg.h index aff13d8fc..fce033f9c 100644 --- a/src/V3Dfg.h +++ b/src/V3Dfg.h @@ -386,9 +386,6 @@ class DfgGraph final { DfgVertex::List m_constVertices; // The constant vertices in the graph DfgVertex::List m_opVertices; // The operation vertices in the graph size_t m_size = 0; // Number of vertices in the graph - // Parent of the graph (i.e.: the module containing the logic represented by this graph), - // or nullptr when run after V3Scope - AstModule* const m_modulep; const std::string m_name; // Name of graph - need not be unique std::string m_tmpNameStub{""}; // Name stub for temporary variables - computed lazy @@ -399,15 +396,13 @@ class DfgGraph final { public: // CONSTRUCTOR - explicit DfgGraph(AstModule* modulep, const string& name = "") VL_MT_DISABLED; + explicit DfgGraph(const string& name = "") VL_MT_DISABLED; ~DfgGraph() VL_MT_DISABLED; VL_UNCOPYABLE(DfgGraph); // METHODS // Number of vertices in this graph size_t size() const { return m_size; } - // Parent module - or nullptr when run after V3Scope - AstModule* modulep() const { return m_modulep; } // Name of this graph const string& name() const { return m_name; } @@ -558,16 +553,6 @@ namespace V3Dfg { //----------------------------------------------------------------------- // Functions for compatibility tests -// Returns true if variable can be represented in the graph -inline bool isSupported(const AstVar* varp) { - if (varp->isIfaceRef()) return false; // Cannot handle interface references - if (varp->delayp()) return false; // Cannot handle delayed variables - if (varp->isSc()) return false; // SystemC variables are special and rare, we can ignore - if (varp->dfgMultidriven()) return false; // Discovered as multidriven on earlier DFG run - if (DfgVertexVar::hasRWRefs(varp)) return false; // Referenced via READWRITE references - return DfgDataType::fromAst(varp->dtypep()); -} - // Returns true if variable can be represented in the graph inline bool isSupported(const AstVarScope* vscp) { const AstNodeModule* const modp = vscp->scopep()->modp(); @@ -582,7 +567,11 @@ inline bool isSupported(const AstVarScope* vscp) { } if (DfgVertexVar::hasRWRefs(vscp)) return false; // Referenced via READWRITE references // Check the AstVar - return isSupported(vscp->varp()); + AstVar* const varp = vscp->varp(); + if (varp->isIfaceRef()) return false; // Cannot handle interface references + if (varp->delayp()) return false; // Cannot handle delayed variables + if (varp->isSc()) return false; // SystemC variables are special and rare, we can ignore + return DfgDataType::fromAst(varp->dtypep()); } } //namespace V3Dfg diff --git a/src/V3DfgAstToDfg.cpp b/src/V3DfgAstToDfg.cpp index 02bc6f7f6..14a6444ca 100644 --- a/src/V3DfgAstToDfg.cpp +++ b/src/V3DfgAstToDfg.cpp @@ -30,28 +30,14 @@ VL_DEFINE_DEBUG_FUNCTIONS; -template class AstToDfgAddAstRefs final : public VNVisitorConst { - // TYPES - using Variable = std::conditional_t; - // STATE DfgGraph& m_dfg; // The graph being processed - // Function to get the DfgVertexVar for a Variable - const std::function m_getVarVertex; + // Function to get the DfgVertexVar for a AstVarScope + const std::function m_getVarVertex; bool m_inSenItem = false; // Inside an AstSenItem bool m_inLoop = false; // Inside an AstLoop - // METHODS - static Variable* getTarget(const AstVarRef* refp) { - // TODO: remove the useless reinterpret_casts when C++17 'if constexpr' actually works - if VL_CONSTEXPR_CXX17 (T_Scoped) { - return reinterpret_cast(refp->varScopep()); - } else { - return reinterpret_cast(refp->varp()); - } - } - // VISITORS void visit(AstNode* nodep) override { iterateChildrenConst(nodep); } @@ -71,12 +57,12 @@ class AstToDfgAddAstRefs final : public VNVisitorConst { // Disguised hierarchical reference handled as external reference, ignore if (nodep->classOrPackagep()) return; // If target is not supported, ignore - Variable* const tgtp = getTarget(nodep); - if (!V3Dfg::isSupported(tgtp)) return; + AstVarScope* const vscp = nodep->varScopep(); + if (!V3Dfg::isSupported(vscp)) return; // V3Dfg::isSupported should reject vars with READWRITE references - UASSERT_OBJ(!nodep->access().isRW(), nodep, "Variable with READWRITE ref not rejected"); + UASSERT_OBJ(!nodep->access().isRW(), nodep, "AstVarScope with READWRITE ref not rejected"); // Get target variable vergtex, ignore if not given one - DfgVertexVar* const varp = m_getVarVertex(tgtp); + DfgVertexVar* const varp = m_getVarVertex(vscp); if (!varp) return; // Create Ast reference vertices if (nodep->access().isReadOnly()) { @@ -85,11 +71,11 @@ class AstToDfgAddAstRefs final : public VNVisitorConst { return; } // Mark as written from non-DFG logic - DfgVertexVar::setHasModWrRefs(tgtp); + DfgVertexVar::setHasModWrRefs(vscp); } AstToDfgAddAstRefs(DfgGraph& dfg, AstNode* nodep, - std::function getVarVertex) + std::function getVarVertex) : m_dfg{dfg} , m_getVarVertex{getVarVertex} { iterateConst(nodep); @@ -97,67 +83,37 @@ class AstToDfgAddAstRefs final : public VNVisitorConst { public: static void apply(DfgGraph& dfg, AstNode* nodep, - std::function getVarVertex) { + std::function getVarVertex) { AstToDfgAddAstRefs{dfg, nodep, getVarVertex}; } }; void V3DfgPasses::addAstRefs(DfgGraph& dfg, AstNode* nodep, - std::function getVarVertex) { - if (dfg.modulep()) { - AstToDfgAddAstRefs::apply(dfg, nodep, getVarVertex); - } else { - AstToDfgAddAstRefs::apply(dfg, nodep, getVarVertex); - } + std::function getVarVertex) { + AstToDfgAddAstRefs::apply(dfg, nodep, getVarVertex); } -template class AstToDfgVisitor final : public VNVisitor { // NODE STATE - // AstVar/AstVarScope::user2() -> DfgVertexVar* : the corresponding variable vertex - // AstVar/AstVarScope::user3() -> bool : Already gathered - used fine grained below + // AstVarScope::user2() -> DfgVertexVar* : the corresponding variable vertex + // AstVarScope::user3() -> bool : Already gathered - used fine grained below const VNUser2InUse m_user2InUse; - // TYPES - using RootType = std::conditional_t; - using Variable = std::conditional_t; - // STATE DfgGraph& m_dfg; // The graph being built V3DfgAstToDfgContext& m_ctx; // The context for stats AstScope* m_scopep = nullptr; // The current scope, iff T_Scoped // METHODS - static Variable* getTarget(const AstVarRef* refp) { - // TODO: remove the useless reinterpret_casts when C++17 'if constexpr' actually works - if VL_CONSTEXPR_CXX17 (T_Scoped) { - return reinterpret_cast(refp->varScopep()); - } else { - return reinterpret_cast(refp->varp()); - } - } - - std::unique_ptr> getLiveVariables(const CfgGraph& cfg) { - // TODO: remove the useless reinterpret_casts when C++17 'if constexpr' actually works - if VL_CONSTEXPR_CXX17 (T_Scoped) { - std::unique_ptr> result = V3Cfg::liveVarScopes(cfg); - const auto resultp = reinterpret_cast*>(result.release()); - return std::unique_ptr>{resultp}; - } else { - std::unique_ptr> result = V3Cfg::liveVars(cfg); - const auto resultp = reinterpret_cast*>(result.release()); - return std::unique_ptr>{resultp}; - } - } // Mark variables referenced under node void markReferenced(AstNode* nodep) { - V3DfgPasses::addAstRefs(m_dfg, nodep, [this](AstNode* varp) { // - return getVarVertex(static_cast(varp)); + V3DfgPasses::addAstRefs(m_dfg, nodep, [this](AstVarScope* vscp) { // + return getVarVertex(vscp); }); } - DfgVertexVar* getVarVertex(Variable* varp) { + DfgVertexVar* getVarVertex(AstVarScope* varp) { if (!varp->user2p()) { // TODO: fix this up when removing the different flavours of DfgVar const AstNodeDType* const dtypep = varp->dtypep()->skipRefp(); @@ -175,14 +131,11 @@ class AstToDfgVisitor final : public VNVisitor { std::unique_ptr> gatherWritten(const AstNode* nodep) { const VNUser3InUse user3InUse; std::unique_ptr> resp{new std::vector{}}; - // We can ignore AstVarXRef here. The only thing we can do with DfgLogic is - // synthesize it into regular vertices, which will fail on a VarXRef at that point. - const bool abort = nodep->exists([&](const AstNodeVarRef* vrefp) -> bool { - if (VN_IS(vrefp, VarXRef)) return true; - if (vrefp->access().isReadOnly()) return false; - Variable* const varp = getTarget(VN_AS(vrefp, VarRef)); - if (!V3Dfg::isSupported(varp)) return true; - if (!varp->user3SetOnce()) resp->emplace_back(getVarVertex(varp)); + const bool abort = nodep->exists([&](const AstVarRef* refp) -> bool { + if (refp->access().isReadOnly()) return false; + AstVarScope* const vscp = refp->varScopep(); + if (!V3Dfg::isSupported(vscp)) return true; + if (!vscp->user3SetOnce()) resp->emplace_back(getVarVertex(vscp)); return false; }); if (abort) { @@ -197,14 +150,11 @@ class AstToDfgVisitor final : public VNVisitor { std::unique_ptr> gatherRead(const AstNode* nodep) { const VNUser3InUse user3InUse; std::unique_ptr> resp{new std::vector{}}; - // We can ignore AstVarXRef here. The only thing we can do with DfgLogic is - // synthesize it into regular vertices, which will fail on a VarXRef at that point. - const bool abort = nodep->exists([&](const AstNodeVarRef* vrefp) -> bool { - if (VN_IS(vrefp, VarXRef)) return true; - if (vrefp->access().isWriteOnly()) return false; - Variable* const varp = getTarget(VN_AS(vrefp, VarRef)); - if (!V3Dfg::isSupported(varp)) return true; - if (!varp->user3SetOnce()) resp->emplace_back(getVarVertex(varp)); + const bool abort = nodep->exists([&](const AstVarRef* refp) -> bool { + if (refp->access().isWriteOnly()) return false; + AstVarScope* const vscp = refp->varScopep(); + if (!V3Dfg::isSupported(vscp)) return true; + if (!vscp->user3SetOnce()) resp->emplace_back(getVarVertex(vscp)); return false; }); if (abort) { @@ -218,7 +168,7 @@ class AstToDfgVisitor final : public VNVisitor { // Return nullptr if any are not supported. std::unique_ptr> gatherLive(const CfgGraph& cfg) { // Run analysis - std::unique_ptr> varps = getLiveVariables(cfg); + std::unique_ptr> varps = V3Cfg::liveVarScopes(cfg); if (!varps) { ++m_ctx.m_nonRepLive; return nullptr; @@ -228,7 +178,7 @@ class AstToDfgVisitor final : public VNVisitor { const VNUser3InUse user3InUse; std::unique_ptr> resp{new std::vector{}}; resp->reserve(varps->size()); - for (Variable* const varp : *varps) { + for (AstVarScope* const varp : *varps) { if (!V3Dfg::isSupported(varp)) { ++m_ctx.m_nonRepVar; return nullptr; @@ -347,7 +297,7 @@ class AstToDfgVisitor final : public VNVisitor { } // CONSTRUCTOR - AstToDfgVisitor(DfgGraph& dfg, RootType& root, V3DfgAstToDfgContext& ctx) + AstToDfgVisitor(DfgGraph& dfg, AstNetlist& root, V3DfgAstToDfgContext& ctx) : m_dfg{dfg} , m_ctx{ctx} { iterate(&root); @@ -356,7 +306,7 @@ class AstToDfgVisitor final : public VNVisitor { VL_UNMOVABLE(AstToDfgVisitor); public: - static void apply(DfgGraph& dfg, RootType& root, V3DfgAstToDfgContext& ctx) { + static void apply(DfgGraph& dfg, AstNetlist& root, V3DfgAstToDfgContext& ctx) { // Convert all logic under 'root' AstToDfgVisitor{dfg, root, ctx}; // Remove unread and undriven variables (created when something failed to convert) @@ -371,14 +321,8 @@ public: } }; -std::unique_ptr V3DfgPasses::astToDfg(AstModule& module, V3DfgContext& ctx) { - DfgGraph* const dfgp = new DfgGraph{&module, module.name()}; - AstToDfgVisitor::apply(*dfgp, module, ctx.m_ast2DfgContext); - return std::unique_ptr{dfgp}; -} - std::unique_ptr V3DfgPasses::astToDfg(AstNetlist& netlist, V3DfgContext& ctx) { - DfgGraph* const dfgp = new DfgGraph{nullptr, "netlist"}; - AstToDfgVisitor::apply(*dfgp, netlist, ctx.m_ast2DfgContext); + DfgGraph* const dfgp = new DfgGraph{"netlist"}; + AstToDfgVisitor::apply(*dfgp, netlist, ctx.m_ast2DfgContext); return std::unique_ptr{dfgp}; } diff --git a/src/V3DfgBreakCycles.cpp b/src/V3DfgBreakCycles.cpp index eb8d719a2..4c25bbdc0 100644 --- a/src/V3DfgBreakCycles.cpp +++ b/src/V3DfgBreakCycles.cpp @@ -115,15 +115,14 @@ class TraceDriver final : public DfgVisitor { // Create temporary capable of holding the result of 'vtxp' DfgVertexVar* createTmp(const char* prefix, DfgVertex* vtxp) { - AstNode* nodep = m_dfg.modulep(); - if (!nodep) nodep = v3Global.rootp(); + AstNode* nodep = v3Global.rootp(); const std::string name = m_dfg.makeUniqueName(prefix, nodep->user2Inc()); FileLine* const flp = vtxp->fileline(); DfgVertex::ScopeCache scopeCache; - AstScope* const scopep = m_dfg.modulep() ? nullptr : vtxp->scopep(scopeCache); + AstScope* const scopep = vtxp->scopep(scopeCache); DfgVertexVar* const varp = m_dfg.makeNewVar(flp, name, vtxp->dtype(), scopep); - varp->varp()->isInternal(true); - varp->tmpForp(varp->nodep()); + varp->vscp()->varp()->isInternal(true); + varp->tmpForp(varp->vscp()); m_vtx2Scc[varp] = 0; return varp; } @@ -1015,7 +1014,7 @@ class FixUp final { return debugStr(*aselp->fromp()) + "[" + std::to_string(i) + "]"; } if (const DfgVertexVar* const varp = vtx.cast()) { - return varp->nodep()->name(); + return varp->vscp()->name(); } vtx.v3fatalSrc("Unhandled node type"); } // LCOV_EXCL_STOP @@ -1128,7 +1127,7 @@ class FixUp final { } void main(DfgVertexVar& var) { - UINFO(9, "FixUp of " << var.nodep()->name()); + UINFO(9, "FixUp of " << var.vscp()->name()); if (var.is()) { // For Packed variables, fix up as whole @@ -1179,7 +1178,7 @@ std::pair, bool> // 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); + if (dumpDfgLevel() >= level) dfg.dumpDotFilePrefixed("breakCycles-" + name); }; // Can't do much with trivial things ('a = a' or 'a[1] = a[0]'), so bail @@ -1237,7 +1236,7 @@ breakCycles(const DfgGraph& dfg, V3DfgContext& ctx) { if (dumpDfgLevel() >= 9) { Vtx2Scc vtx2Scc = res.makeUserMap(); V3DfgPasses::colorStronglyConnectedComponents(res, vtx2Scc); - res.dumpDotFilePrefixed(ctx.prefix() + "breakCycles-remaining", [&](const DfgVertex& vtx) { + res.dumpDotFilePrefixed("breakCycles-remaining", [&](const DfgVertex& vtx) { return vtx2Scc[vtx]; // }); } diff --git a/src/V3DfgContext.h b/src/V3DfgContext.h index dd1a05f2f..be223f494 100644 --- a/src/V3DfgContext.h +++ b/src/V3DfgContext.h @@ -37,25 +37,17 @@ 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} {} + V3DfgSubContext(const std::string& name) + : m_name{name} {} void addStat(const std::string& what, double value) { - V3Stats::addStat("Optimizations, DFG " + m_label + " " + m_name + ", " + what, value); + V3Stats::addStat("Optimizations, DFG, " + m_name + ", " + what, value); } - -public: - inline const std::string& prefix() const; - const std::string& label() const { return m_label; } }; //###################################################################### @@ -74,8 +66,8 @@ public: VDouble0 m_nonRepVar; // Non-representable due to unsupported variable properties private: - V3DfgAstToDfgContext(V3DfgContext& ctx, const std::string& label) - : V3DfgSubContext{ctx, label, "AstToDfg"} {} + V3DfgAstToDfgContext() + : V3DfgSubContext{"AstToDfg"} {} ~V3DfgAstToDfgContext() { addStat("input processes", m_inputs); addStat("representable", m_representable); @@ -96,8 +88,8 @@ public: VDouble0 m_decodersCreated; // Number of bianry to one-hot decoders created private: - V3DfgBinToOneHotContext(V3DfgContext& ctx, const std::string& label) - : V3DfgSubContext{ctx, label, "BinToOneHot"} {} + V3DfgBinToOneHotContext() + : V3DfgSubContext{"BinToOneHot"} {} ~V3DfgBinToOneHotContext() { addStat("decoders created", m_decodersCreated); } }; class V3DfgBreakCyclesContext final : public V3DfgSubContext { @@ -113,8 +105,8 @@ public: VDouble0 m_nImprovements; // Number of changes made to graphs private: - V3DfgBreakCyclesContext(V3DfgContext& ctx, const std::string& label) - : V3DfgSubContext{ctx, label, "BreakCycles"} {} + V3DfgBreakCyclesContext() + : V3DfgSubContext{"BreakCycles"} {} ~V3DfgBreakCyclesContext() { addStat("made acyclic", m_nFixed); addStat("improved", m_nImproved); @@ -132,8 +124,8 @@ public: VDouble0 m_eliminated; // Number of common sub-expressions eliminated private: - V3DfgCseContext(V3DfgContext& ctx, const std::string& label) - : V3DfgSubContext{ctx, label, "CSE"} {} + explicit V3DfgCseContext(const std::string& label) + : V3DfgSubContext{"CSE " + label} {} ~V3DfgCseContext() { addStat("expressions eliminated", m_eliminated); } }; @@ -150,8 +142,8 @@ public: VDouble0 m_varRefsSubstituted; // Number of variable references substituted in the Ast private: - V3DfgDfgToAstContext(V3DfgContext& ctx, const std::string& label) - : V3DfgSubContext{ctx, label, "DfgToAst"} {} + V3DfgDfgToAstContext() + : V3DfgSubContext{"DfgToAst"} {} ~V3DfgDfgToAstContext() { addStat("output variables", m_outputVariables); addStat("output variables with default driver", m_outputVariablesWithDefault); @@ -173,8 +165,34 @@ public: std::vector m_deleteps; // AstVar/AstVarScope that can be deleted at the end private: - V3DfgPeepholeContext(V3DfgContext& ctx, const std::string& label) VL_MT_DISABLED; - ~V3DfgPeepholeContext() VL_MT_DISABLED; + V3DfgPeepholeContext() + : V3DfgSubContext{"Peephole"} { + const auto checkEnabled = [this](VDfgPeepholePattern id) { + std::string str{id.ascii()}; + std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { // + return c == '_' ? '-' : std::tolower(c); + }); + m_enabled[id] = v3Global.opt.fDfgPeepholeEnabled(str); + }; +#define OPTIMIZATION_CHECK_ENABLED(id, name) checkEnabled(VDfgPeepholePattern::id); + FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION(OPTIMIZATION_CHECK_ENABLED) +#undef OPTIMIZATION_CHECK_ENABLED + } + ~V3DfgPeepholeContext() { + for (AstNode* const nodep : m_deleteps) { + VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); + } + const auto emitStat = [this](VDfgPeepholePattern id) { + std::string str{id.ascii()}; + std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { // + return c == '_' ? ' ' : std::tolower(c); + }); + addStat(str, m_count[id]); + }; +#define OPTIMIZATION_EMIT_STATS(id, name) emitStat(VDfgPeepholePattern::id); + FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION(OPTIMIZATION_EMIT_STATS) +#undef OPTIMIZATION_EMIT_STATS + } }; class V3DfgPushDownSelsContext final : public V3DfgSubContext { // Only V3DfgContext can create an instance @@ -185,8 +203,8 @@ public: size_t m_pushedDown = 0; // Number of selects pushed down through concatenations size_t m_wouldBeCyclic = 0; // Number of selects not pushed due to cycle private: - V3DfgPushDownSelsContext(V3DfgContext& ctx, const std::string& label) - : V3DfgSubContext{ctx, label, "PushDownSels"} {} + V3DfgPushDownSelsContext() + : V3DfgSubContext{"PushDownSels"} {} ~V3DfgPushDownSelsContext() { addStat("sels pushed down", m_pushedDown); addStat("would be cyclic", m_wouldBeCyclic); @@ -204,8 +222,8 @@ public: VDouble0 m_temporariesIntroduced; // Number of temporaries introduced for reuse private: - V3DfgRegularizeContext(V3DfgContext& ctx, const std::string& label) - : V3DfgSubContext{ctx, label, "Regularize"} {} + V3DfgRegularizeContext() + : V3DfgSubContext{"Regularize"} {} ~V3DfgRegularizeContext() { for (AstNode* const nodep : m_deleteps) { VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); @@ -227,8 +245,8 @@ public: VDouble0 m_logicDeleted; // Number of logic blocks removed from the Dfg and the Ast private: - V3DfgRemoveUnobservableContext(V3DfgContext& ctx, const std::string& label) - : V3DfgSubContext{ctx, label, "RemoveUnobservable"} {} + V3DfgRemoveUnobservableContext() + : V3DfgSubContext{"RemoveUnobservable"} {} ~V3DfgRemoveUnobservableContext() { addStat("variables removed", m_varsRemoved); addStat("variables deleted", m_varsDeleted); @@ -291,8 +309,8 @@ public: } m_synt; private: - V3DfgSynthesisContext(V3DfgContext& ctx, const std::string& label) - : V3DfgSubContext{ctx, label, "Synthesis"} {} + V3DfgSynthesisContext() + : V3DfgSubContext{"Synthesis"} {} ~V3DfgSynthesisContext() { // Conversion statistics addStat("conv / input assignments", m_conv.inputAssignments); @@ -367,64 +385,40 @@ private: // 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}; - V3DfgPeepholeContext m_peepholeContext{*this, m_label}; - V3DfgPushDownSelsContext m_pushDownSelsContext{*this, m_label}; - V3DfgRegularizeContext m_regularizeContext{*this, m_label}; - V3DfgRemoveUnobservableContext m_removeUnobservableContext{*this, m_label}; - V3DfgSynthesisContext m_synthContext{*this, m_label}; + V3DfgAstToDfgContext m_ast2DfgContext; + V3DfgBinToOneHotContext m_binToOneHotContext; + V3DfgBreakCyclesContext m_breakCyclesContext; + V3DfgCseContext m_cseContext0{"1st"}; + V3DfgCseContext m_cseContext1{"2nd"}; + V3DfgDfgToAstContext m_dfg2AstContext; + V3DfgPeepholeContext m_peepholeContext; + V3DfgPushDownSelsContext m_pushDownSelsContext; + V3DfgRegularizeContext m_regularizeContext; + V3DfgRemoveUnobservableContext m_removeUnobservableContext; + V3DfgSynthesisContext m_synthContext; // Node pattern collector V3DfgPatternStats m_patternStats; // CONSTRUCTOR - explicit V3DfgContext(const std::string& label) - : m_label{label} - , m_prefix{VString::removeWhitespace(label) + "-"} {} + V3DfgContext() = default; ~V3DfgContext() { - const string front = "Optimizations, DFG " + label() + " General, "; - V3Stats::addStat(front + "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"; + + v3Global.opt.prefix() + "__stats_dfg_patterns.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); + m_patternStats.dump(*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/V3DfgDecomposition.cpp b/src/V3DfgDecomposition.cpp index ccf4f52f7..6d695970d 100644 --- a/src/V3DfgDecomposition.cpp +++ b/src/V3DfgDecomposition.cpp @@ -22,9 +22,7 @@ #include "V3Dfg.h" #include "V3DfgPasses.h" -#include "V3File.h" -#include #include #include @@ -103,7 +101,7 @@ class SplitIntoComponents final { // Allocate the component graphs m_components.resize(m_componentCounter - 1); for (size_t i = 1; i < m_componentCounter; ++i) { - m_components[i - 1].reset(new DfgGraph{m_dfg.modulep(), m_prefix + cvtToStr(i - 1)}); + m_components[i - 1].reset(new DfgGraph{m_prefix + cvtToStr(i - 1)}); } // Move the vertices to the component graphs moveVertices(m_dfg.varVertices()); @@ -222,17 +220,9 @@ class ExtractCyclicComponents final { DfgVertexVar*& clonep = m_clones[&vtx][component]; if (!clonep) { if (DfgVarPacked* const pVtxp = vtx.cast()) { - if (AstVarScope* const vscp = pVtxp->varScopep()) { - clonep = new DfgVarPacked{m_dfg, vscp}; - } else { - clonep = new DfgVarPacked{m_dfg, pVtxp->varp()}; - } + clonep = new DfgVarPacked{m_dfg, pVtxp->vscp()}; } else if (DfgVarArray* const aVtxp = vtx.cast()) { - if (AstVarScope* const vscp = aVtxp->varScopep()) { - clonep = new DfgVarArray{m_dfg, vscp}; - } else { - clonep = new DfgVarArray{m_dfg, aVtxp->varp()}; - } + clonep = new DfgVarArray{m_dfg, aVtxp->vscp()}; } UASSERT_OBJ(clonep, &vtx, "Unhandled 'DfgVertexVar' sub-type"); m_component[clonep] = component; @@ -326,7 +316,7 @@ class ExtractCyclicComponents final { // Allocate result graphs m_components.resize(nComponents); for (uint32_t i = 0; i < nComponents; ++i) { - m_components[i].reset(new DfgGraph{m_dfg.modulep(), m_prefix + cvtToStr(i)}); + m_components[i].reset(new DfgGraph{m_prefix + cvtToStr(i)}); } // Fix up edges crossing components (we can only do this at variable boundaries, and the diff --git a/src/V3DfgDfgToAst.cpp b/src/V3DfgDfgToAst.cpp index 9c354f037..e88966201 100644 --- a/src/V3DfgDfgToAst.cpp +++ b/src/V3DfgDfgToAst.cpp @@ -32,8 +32,6 @@ #include "V3DfgPasses.h" #include "V3UniqueNames.h" -#include - VL_DEFINE_DEBUG_FUNCTIONS; namespace { @@ -92,34 +90,19 @@ AstShiftRS* makeNode( // } // namespace -template class DfgToAstVisitor final : DfgVisitor { // NODE STATE // AstScope::user2p // The combinational AstActive under this scope const VNUser2InUse m_user2InUse; - // TYPES - using Variable = std::conditional_t; - using Container = std::conditional_t; - // STATE - AstModule* const m_modp; // The parent/result module - This is nullptr when T_Scoped V3DfgDfgToAstContext& m_ctx; // The context for stats AstNodeExpr* m_resultp = nullptr; // The result node of the current traversal AstAlways* m_alwaysp = nullptr; // Process to add assignments to, if have a default driver - Container* m_containerp = nullptr; // The AstNodeModule or AstActive to insert assigns into + AstActive* m_activep = nullptr; // The AstNodeModule or AstActive to insert assigns into // METHODS - - static Variable* getNode(const DfgVertexVar* vtxp) { - if VL_CONSTEXPR_CXX17 (T_Scoped) { - return reinterpret_cast(vtxp->varScopep()); - } else { - return reinterpret_cast(vtxp->varp()); - } - } - static AstActive* getCombActive(AstScope* scopep) { if (!scopep->user2p()) { // Try to find the existing combinational AstActive @@ -173,7 +156,7 @@ class DfgToAstVisitor final : DfgVisitor { // Otherwise create an AssignW AstAssignW* const ap = new AstAssignW{flp, lhsp, rhsp}; - m_containerp->addStmtsp(new AstAlways{ap}); + m_activep->addStmtsp(new AstAlways{ap}); } void convertDriver(FileLine* flp, AstNodeExpr* lhsp, DfgVertex* driverp) { @@ -234,11 +217,11 @@ class DfgToAstVisitor final : DfgVisitor { } // LCOV_EXCL_STOP void visit(DfgVarPacked* vtxp) override { - m_resultp = new AstVarRef{vtxp->fileline(), getNode(vtxp), VAccess::READ}; + m_resultp = new AstVarRef{vtxp->fileline(), vtxp->vscp(), VAccess::READ}; } void visit(DfgVarArray* vtxp) override { - m_resultp = new AstVarRef{vtxp->fileline(), getNode(vtxp), VAccess::READ}; + m_resultp = new AstVarRef{vtxp->fileline(), vtxp->vscp(), VAccess::READ}; } void visit(DfgConst* vtxp) override { // @@ -264,8 +247,7 @@ class DfgToAstVisitor final : DfgVisitor { // Constructor DfgToAstVisitor(DfgGraph& dfg, V3DfgDfgToAstContext& ctx) - : m_modp{dfg.modulep()} - , m_ctx{ctx} { + : m_ctx{ctx} { if (v3Global.opt.debugCheck()) V3DfgPasses::typeCheck(dfg); // Convert the graph back to combinational assignments. The graph must have been @@ -283,24 +265,18 @@ class DfgToAstVisitor final : DfgVisitor { // Render variable assignments FileLine* const flp = vtx.driverFileLine() ? vtx.driverFileLine() : vtx.fileline(); - AstVarRef* const lhsp = new AstVarRef{flp, getNode(&vtx), VAccess::WRITE}; + AstVarRef* const lhsp = new AstVarRef{flp, vtx.vscp(), VAccess::WRITE}; - VL_RESTORER(m_containerp); - if VL_CONSTEXPR_CXX17 (T_Scoped) { - // Add it to the scope holding the target variable - AstActive* const activep = getCombActive(vtx.varScopep()->scopep()); - m_containerp = reinterpret_cast(activep); - } else { - // Add it to the parent module of the DfgGraph - m_containerp = reinterpret_cast(m_modp); - } + // Add it to the scope holding the target variable + VL_RESTORER(m_activep); + m_activep = getCombActive(vtx.vscp()->scopep()); // If there is a default value, render all drivers under an AstAlways VL_RESTORER(m_alwaysp); if (DfgVertex* const defaultp = vtx.defaultp()) { ++m_ctx.m_outputVariablesWithDefault; m_alwaysp = new AstAlways{vtx.fileline(), VAlwaysKwd::ALWAYS_COMB, nullptr}; - m_containerp->addStmtsp(m_alwaysp); + m_activep->addStmtsp(m_alwaysp); // The default assignment needs to go first createAssignment(vtx.fileline(), lhsp->cloneTreePure(false), defaultp); } @@ -326,8 +302,6 @@ class DfgToAstVisitor final : DfgVisitor { if (VN_IS(exprp, VarRef)) { ++m_ctx.m_varRefsSubstituted; } else { - UASSERT_OBJ(!dfg.modulep(), &vtx, - "Expressions should only be inlined on final scoped run"); ++m_ctx.m_expressionsInlined; } rVtxp->exprp()->replaceWith(exprp); @@ -342,9 +316,5 @@ public: }; void V3DfgPasses::dfgToAst(DfgGraph& dfg, V3DfgContext& ctx) { - if (dfg.modulep()) { - DfgToAstVisitor::apply(dfg, ctx.m_dfg2AstContext); - } else { - DfgToAstVisitor::apply(dfg, ctx.m_dfg2AstContext); - } + DfgToAstVisitor::apply(dfg, ctx.m_dfg2AstContext); } diff --git a/src/V3DfgOptimizer.cpp b/src/V3DfgOptimizer.cpp index 0558c35e8..638386f56 100644 --- a/src/V3DfgOptimizer.cpp +++ b/src/V3DfgOptimizer.cpp @@ -26,6 +26,7 @@ #include "V3Const.h" #include "V3Dfg.h" #include "V3DfgPasses.h" +#include "V3Error.h" #include "V3Graph.h" #include "V3UniqueNames.h" @@ -255,84 +256,39 @@ class DataflowOptimize final { // STATE V3DfgContext m_ctx; // The context holding values that need to persist across multiple graphs - const bool m_scoped; // Running after V3Scope void endOfStage(const std::string& name, const DfgGraph* dfgp = nullptr) { // Dump the graph for debugging if given one - if (VL_UNLIKELY(dumpDfgLevel() >= 8 && dfgp)) { - dfgp->dumpDotFilePrefixed(m_ctx.prefix() + name); - } + if (VL_UNLIKELY(dumpDfgLevel() >= 8 && dfgp)) dfgp->dumpDotFilePrefixed(name); // Dump stage stats only in scoped mode when running on the whole netlist - if (VL_UNLIKELY(v3Global.opt.stats() && m_scoped)) { - V3Stats::statsStage("dfg-optimize-" + name); - } + if (VL_UNLIKELY(v3Global.opt.stats())) V3Stats::statsStage("dfg-optimize-" + name); } // Mark variables with external references void markExternallyReferencedVariables(AstNetlist* netlistp) { - netlistp->foreach([this](AstNode* nodep) { + netlistp->foreach([](AstNode* nodep) { // Check variable flags - if (m_scoped) { - if (AstVarScope* const vscp = VN_CAST(nodep, VarScope)) { - const AstVar* const varp = vscp->varp(); - // Force and trace have already been processed - const bool hasExtRd = varp->isPrimaryIO() || varp->isSigUserRdPublic(); - const bool hasExtWr = varp->isPrimaryIO() || varp->isSigUserRWPublic(); - if (hasExtRd) DfgVertexVar::setHasExtRdRefs(vscp); - if (hasExtWr) DfgVertexVar::setHasExtWrRefs(vscp); - return; - } - // Check direct references - if (const AstVarRef* const refp = VN_CAST(nodep, VarRef)) { - if (refp->access().isRW()) DfgVertexVar::setHasRWRefs(refp->varScopep()); - UASSERT_OBJ(!refp->classOrPackagep(), refp, "V3Scope should have removed"); - return; - } - } else { - if (AstVar* const varp = VN_CAST(nodep, Var)) { - const bool hasExtRd = varp->isPrimaryIO() || varp->isSigUserRdPublic() // - || varp->isForced() || varp->isTrace(); - const bool hasExtWr = varp->isPrimaryIO() || varp->isSigUserRWPublic() // - || varp->isForced(); - if (hasExtRd) DfgVertexVar::setHasExtRdRefs(varp); - if (hasExtWr) DfgVertexVar::setHasExtWrRefs(varp); - return; - } - // Check direct references - if (const AstVarRef* const refp = VN_CAST(nodep, VarRef)) { - AstVar* const varp = refp->varp(); - if (refp->access().isRW()) DfgVertexVar::setHasRWRefs(varp); - // With classOrPackagep set this is a disguised hierarchical reference, mark - if (refp->classOrPackagep()) { - if (refp->access().isReadOrRW()) DfgVertexVar::setHasExtRdRefs(varp); - if (refp->access().isWriteOrRW()) DfgVertexVar::setHasExtWrRefs(varp); - } - return; - } - } - - // Check hierarchical references - if (const AstVarXRef* const xrefp = VN_CAST(nodep, VarXRef)) { - AstVar* const tgtp = xrefp->varp(); - if (!tgtp) return; - if (xrefp->access().isReadOrRW()) DfgVertexVar::setHasExtRdRefs(tgtp); - if (xrefp->access().isWriteOrRW()) DfgVertexVar::setHasExtWrRefs(tgtp); - if (xrefp->access().isRW()) DfgVertexVar::setHasRWRefs(tgtp); + if (AstVarScope* const vscp = VN_CAST(nodep, VarScope)) { + const AstVar* const varp = vscp->varp(); + // Force and trace have already been processed + const bool hasExtRd = varp->isPrimaryIO() || varp->isSigUserRdPublic(); + const bool hasExtWr + = (varp->isPrimaryIO() && varp->isNonOutput()) || varp->isSigUserRWPublic(); + if (hasExtRd) DfgVertexVar::setHasExtRdRefs(vscp); + if (hasExtWr) DfgVertexVar::setHasExtWrRefs(vscp); return; } + // Check references + if (const AstVarRef* const refp = VN_CAST(nodep, VarRef)) { + if (refp->access().isRW()) DfgVertexVar::setHasRWRefs(refp->varScopep()); + UASSERT_OBJ(!refp->classOrPackagep(), refp, "V3Scope should have removed"); + return; + } + UASSERT_OBJ(!VN_IS(nodep, VarXRef), nodep, "V3Scope should have removed"); // Check cell ports if (const AstCell* const cellp = VN_CAST(nodep, Cell)) { - for (const AstPin *pinp = cellp->pinsp(), *nextp; pinp; pinp = nextp) { - nextp = VN_AS(pinp->nextp(), Pin); - AstVar* const tgtp = pinp->modVarp(); - if (!tgtp) return; - const VDirection dir = tgtp->direction(); - // hasExtRd/hasExtWr from perspective of Pin - const bool hasExtRd = dir == VDirection::OUTPUT || dir.isInoutOrRef(); - const bool hasExtWr = dir == VDirection::INPUT || dir.isInoutOrRef(); - if (hasExtRd) DfgVertexVar::setHasExtRdRefs(tgtp); - if (hasExtWr) DfgVertexVar::setHasExtWrRefs(tgtp); - } + // Why does this not hold? + UASSERT_OBJ(true || !cellp->pinsp(), cellp, "Pins should have been lowered"); return; } }); @@ -415,9 +371,7 @@ class DataflowOptimize final { } } - DataflowOptimize(AstNetlist* netlistp, const string& label) - : m_ctx{label} - , m_scoped{!!netlistp->topScopep()} { + DataflowOptimize(AstNetlist* netlistp) { // Mark interfaces that might be referenced by a virtual interface if (v3Global.hasVirtIfaces()) { @@ -430,51 +384,29 @@ class DataflowOptimize final { // Mark variables with external references markExternallyReferencedVariables(netlistp); - if (!m_scoped) { - // Pre V3Scope application. Run on each module separately. - for (AstNode* nodep = netlistp->modulesp(); nodep; nodep = nodep->nextp()) { - // Only optimize proper modules - AstModule* const modp = VN_CAST(nodep, Module); - if (!modp) continue; - // Pre V3Scope application. Run on module. - 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 dfgp = V3DfgPasses::astToDfg(*modp, m_ctx); - endOfStage("ast-to-dfg", dfgp.get()); - // Actually process the graph - optimize(*dfgp); - // Convert back to Ast - V3DfgPasses::dfgToAst(*dfgp, m_ctx); - endOfStage("dfg-to-ast", dfgp.get()); - } - } else { - // 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 dfgp = V3DfgPasses::astToDfg(*netlistp, m_ctx); - endOfStage("ast-to-dfg", dfgp.get()); - // Actually process the graph - optimize(*dfgp); - // Convert back to Ast - V3DfgPasses::dfgToAst(*dfgp, m_ctx); - endOfStage("dfg-to-ast", dfgp.get()); - // Some sentrees might have become constant, remove them - removeNeverActives(netlistp); - } + // 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 dfgp = V3DfgPasses::astToDfg(*netlistp, m_ctx); + endOfStage("ast-to-dfg", dfgp.get()); + // Actually process the graph + optimize(*dfgp); + // Convert back to Ast + V3DfgPasses::dfgToAst(*dfgp, m_ctx); + endOfStage("dfg-to-ast", dfgp.get()); + // Some sentrees might have become constant, remove them + removeNeverActives(netlistp); // Reset interned types so the corresponding Ast types can be garbage collected DfgDataType::reset(); } public: - static void apply(AstNetlist* netlistp, const string& label) { - DataflowOptimize{netlistp, label}; - } + static void apply(AstNetlist* netlistp) { DataflowOptimize{netlistp}; } }; -void V3DfgOptimizer::optimize(AstNetlist* netlistp, const string& label) { +void V3DfgOptimizer::optimize(AstNetlist* netlistp) { UINFO(2, __FUNCTION__ << ":"); - DataflowOptimize::apply(netlistp, label); + DataflowOptimize::apply(netlistp); V3Global::dumpCheckGlobalTree("dfg-optimize", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3DfgOptimizer.h b/src/V3DfgOptimizer.h index a5256b213..bea3bb89e 100644 --- a/src/V3DfgOptimizer.h +++ b/src/V3DfgOptimizer.h @@ -29,7 +29,7 @@ namespace V3DfgOptimizer { void extract(AstNetlist*) VL_MT_DISABLED; // Optimize the design -void optimize(AstNetlist*, const string& label) VL_MT_DISABLED; +void optimize(AstNetlist*) VL_MT_DISABLED; } // namespace V3DfgOptimizer #endif // Guard diff --git a/src/V3DfgPasses.cpp b/src/V3DfgPasses.cpp index 3e9d1fd17..d2c005e88 100644 --- a/src/V3DfgPasses.cpp +++ b/src/V3DfgPasses.cpp @@ -18,6 +18,7 @@ #include "V3DfgPasses.h" +#include "V3Ast.h" #include "V3Dfg.h" #include "V3File.h" #include "V3Global.h" @@ -71,7 +72,7 @@ void V3DfgPasses::removeUnobservable(DfgGraph& dfg, V3DfgContext& dfgCtx) { if (vVtxp->hasSinks()) continue; if (vVtxp->isObserved()) continue; DfgVertex* const srcp = vVtxp->srcp(); // Must be a DfgUnresolved or nullptr - AstNode* const varp = vVtxp->nodep(); + AstVarScope* const vscp = vVtxp->vscp(); // Can delete the Ast variable too if it has no other references const bool delAst = (!srcp || !srcp->nInputs()) // && !vVtxp->hasExtWrRefs() // @@ -79,7 +80,7 @@ void V3DfgPasses::removeUnobservable(DfgGraph& dfg, V3DfgContext& dfgCtx) { VL_DO_DANGLING(vVtxp->unlinkDelete(dfg), vVtxp); if (srcp) VL_DO_DANGLING(srcp->unlinkDelete(dfg), srcp); if (delAst) { - VL_DO_DANGLING(varp->unlinkFrBack()->deleteTree(), varp); + VL_DO_DANGLING(vscp->unlinkFrBack()->deleteTree(), vscp); ++ctx.m_varsDeleted; } else { ++ctx.m_varsRemoved; @@ -96,7 +97,7 @@ void V3DfgPasses::removeUnobservable(DfgGraph& dfg, V3DfgContext& dfgCtx) { // AstVar/AstVarScope::user2p() -> corresponding DfgVertexVar* in the graph const VNUser2InUse m_user2InUse; logicp->foreachSource([](DfgVertex& src) { - src.as()->nodep()->user2p(&src); + src.as()->vscp()->user2p(&src); return false; }); V3DfgPasses::addAstRefs(dfg, logicp->nodep(), [](AstNode* varp) { // @@ -181,8 +182,6 @@ void V3DfgPasses::removeUnused(DfgGraph& dfg) { } void V3DfgPasses::binToOneHot(DfgGraph& dfg, V3DfgBinToOneHotContext& ctx) { - if (!dfg.modulep()) return; // binToOneHot only works with unscoped DfgGraphs for now - // Structure to keep track of comparison details struct Term final { DfgVertex* m_vtxp = nullptr; // Vertex to replace @@ -291,6 +290,8 @@ void V3DfgPasses::binToOneHot(DfgGraph& dfg, V3DfgBinToOneHotContext& ctx) { // Sequence numbers for name generation size_t nTables = 0; + DfgVertex::ScopeCache scopeCache; + // Create decoders for each srcp for (DfgVertex* const srcp : srcps) { const Val2Terms& val2Terms = vtx2Val2Terms[srcp]; @@ -318,6 +319,38 @@ void V3DfgPasses::binToOneHot(DfgGraph& dfg, V3DfgBinToOneHotContext& ctx) { // - and replace the comparisons with 'tab[const]' FileLine* const flp = srcp->fileline(); + AstScope* const scopep = srcp->scopep(scopeCache, true); + + AstActive* const staticActivep = [scopep]() { + // Try to find the existing combinational AstActive + for (AstNode* nodep = scopep->blocksp(); nodep; nodep = nodep->nextp()) { + AstActive* const activep = VN_CAST(nodep, Active); + if (!activep) continue; + if (activep->sentreep()->hasStatic()) return activep; + } + // If there isn't one, create a new one + FileLine* const flp = scopep->fileline(); + AstSenTree* const stp = new AstSenTree{flp, new AstSenItem{flp, AstSenItem::Static{}}}; + AstActive* const activep = new AstActive{flp, "", stp}; + activep->senTreeStorep(stp); + scopep->addBlocksp(activep); + return activep; + }(); + AstActive* const combActivep = [scopep]() { + // Try to find the existing combinational AstActive + for (AstNode* nodep = scopep->blocksp(); nodep; nodep = nodep->nextp()) { + AstActive* const activep = VN_CAST(nodep, Active); + if (!activep) continue; + if (activep->sentreep()->hasCombo()) return activep; + } + // If there isn't one, create a new one + FileLine* const flp = scopep->fileline(); + AstSenTree* const stp = new AstSenTree{flp, new AstSenItem{flp, AstSenItem::Combo{}}}; + AstActive* const activep = new AstActive{flp, "", stp}; + activep->senTreeStorep(stp); + scopep->addBlocksp(activep); + return activep; + }(); // Required data types const DfgDataType& idxDType = srcp->dtype(); @@ -330,31 +363,31 @@ void V3DfgPasses::binToOneHot(DfgGraph& dfg, V3DfgBinToOneHotContext& ctx) { if (DfgVertexVar* const vp = srcp->getResultVar()) return vp->as(); // Otherwise create a new variable const std::string name = dfg.makeUniqueName("BinToOneHot_Idx", nTables); - DfgVertexVar* const vtxp = dfg.makeNewVar(flp, name, idxDType, nullptr); - vtxp->varp()->isInternal(true); + DfgVertexVar* const vtxp = dfg.makeNewVar(flp, name, idxDType, scopep); + vtxp->vscp()->varp()->isInternal(true); vtxp->srcp(srcp); return vtxp->as(); }(); - AstVar* const idxVarp = idxVtxp->varp(); + AstVarScope* const idxVscp = idxVtxp->vscp(); // The previous index variable - we don't need a vertex for this - AstVar* const preVarp = [&]() { + AstVarScope* const preVscp = [&]() { const std::string name = dfg.makeUniqueName("BinToOneHot_Pre", nTables); - AstVar* const varp = new AstVar{flp, VVarType::MODULETEMP, name, idxDType.astDtypep()}; - dfg.modulep()->addStmtsp(varp); - varp->isInternal(true); - varp->noReset(true); - varp->setIgnoreSchedWrite(); - return varp; + DfgVertexVar* const vtxp = dfg.makeNewVar(flp, name, idxDType, scopep); + AstVarScope* const vscp = vtxp->vscp(); + VL_DO_DANGLING(vtxp->unlinkDelete(dfg), vtxp); + vscp->varp()->isInternal(true); + vscp->varp()->noReset(true); + vscp->varp()->setIgnoreSchedWrite(); + return vscp; }(); // The table variable DfgVarArray* const tabVtxp = [&]() { const std::string name = dfg.makeUniqueName("BinToOneHot_Tab", nTables); - DfgVarArray* const varp - = dfg.makeNewVar(flp, name, tabDType, nullptr)->as(); - varp->varp()->isInternal(true); - varp->varp()->noReset(true); + DfgVertexVar* const varp = dfg.makeNewVar(flp, name, tabDType, scopep); + varp->vscp()->varp()->isInternal(true); + varp->vscp()->varp()->noReset(true); varp->setHasModWrRefs(); - return varp; + return varp->as(); }(); ++nTables; @@ -362,16 +395,16 @@ void V3DfgPasses::binToOneHot(DfgGraph& dfg, V3DfgBinToOneHotContext& ctx) { // Initialize 'tab' and 'pre' variables statically AstInitialStatic* const initp = new AstInitialStatic{flp, nullptr}; - dfg.modulep()->addStmtsp(initp); + staticActivep->addStmtsp(initp); { // pre = 0 initp->addStmtsp(new AstAssign{ flp, // - new AstVarRef{flp, preVarp, VAccess::WRITE}, // + new AstVarRef{flp, preVscp, VAccess::WRITE}, // new AstConst{flp, AstConst::WidthedValue{}, static_cast(width), 0}}); } { // tab.fill(0) AstCMethodHard* const callp = new AstCMethodHard{ - flp, new AstVarRef{flp, tabVtxp->varp(), VAccess::WRITE}, VCMethod::UNPACKED_FILL}; + flp, new AstVarRef{flp, tabVtxp->vscp(), VAccess::WRITE}, VCMethod::UNPACKED_FILL}; callp->addPinsp(new AstConst{flp, AstConst::BitFalse{}}); callp->dtypeSetVoid(); initp->addStmtsp(callp->makeStmt()); @@ -379,28 +412,28 @@ void V3DfgPasses::binToOneHot(DfgGraph& dfg, V3DfgBinToOneHotContext& ctx) { // Build the decoder logic AstAlways* const logicp = new AstAlways{flp, VAlwaysKwd::ALWAYS_COMB, nullptr, nullptr}; - dfg.modulep()->addStmtsp(logicp); + combActivep->addStmtsp(logicp); { // tab[pre] = 0; logicp->addStmtsp(new AstAssign{ flp, // - new AstArraySel{flp, new AstVarRef{flp, tabVtxp->varp(), VAccess::WRITE}, - new AstVarRef{flp, preVarp, VAccess::READ}}, // + new AstArraySel{flp, new AstVarRef{flp, tabVtxp->vscp(), VAccess::WRITE}, + new AstVarRef{flp, preVscp, VAccess::READ}}, // new AstConst{flp, AstConst::BitFalse{}}}); } { // tab[idx] = 1 - AstVarRef* const idxRefp = new AstVarRef{flp, idxVarp, VAccess::READ}; + AstVarRef* const idxRefp = new AstVarRef{flp, idxVscp, VAccess::READ}; logicp->addStmtsp(new AstAssign{ flp, // - new AstArraySel{flp, new AstVarRef{flp, tabVtxp->varp(), VAccess::WRITE}, + new AstArraySel{flp, new AstVarRef{flp, tabVtxp->vscp(), VAccess::WRITE}, idxRefp}, // new AstConst{flp, AstConst::BitTrue{}}}); DfgAstRd* const astRdp = new DfgAstRd{dfg, idxRefp, false, false}; astRdp->srcp(idxVtxp); } { // pre = idx - AstVarRef* const idxRefp = new AstVarRef{flp, idxVarp, VAccess::READ}; + AstVarRef* const idxRefp = new AstVarRef{flp, idxVscp, VAccess::READ}; logicp->addStmtsp(new AstAssign{flp, // - new AstVarRef{flp, preVarp, VAccess::WRITE}, // + new AstVarRef{flp, preVscp, VAccess::WRITE}, // idxRefp}); DfgAstRd* const astRdp = new DfgAstRd{dfg, idxRefp, false, false}; astRdp->srcp(idxVtxp); @@ -442,7 +475,7 @@ void V3DfgPasses::optimize(DfgGraph& dfg, V3DfgContext& ctx) { // Apply the pass pass(); // Debug dump - if (dump) dfg.dumpDotFilePrefixed(ctx.prefix() + "opt-" + VString::removeWhitespace(name)); + if (dump) dfg.dumpDotFilePrefixed("opt-" + VString::removeWhitespace(name)); // Internal type check if (v3Global.opt.debugCheck()) V3DfgPasses::typeCheck(dfg); }; @@ -456,10 +489,7 @@ void V3DfgPasses::optimize(DfgGraph& dfg, V3DfgContext& ctx) { run("cse0 ", dumpLvl >= 4, [&]() { cse(dfg, ctx.m_cseContext0); }); run("binToOneHot ", dumpLvl >= 4, [&]() { binToOneHot(dfg, ctx.m_binToOneHotContext); }); run("peephole ", dumpLvl >= 4, [&]() { peephole(dfg, ctx.m_peepholeContext); }); - // Run only on final scoped DfgGraphs, as otherwise later DfgPeephole wold just undo this work - if (!dfg.modulep()) { - run("pushDownSels", dumpLvl >= 4, [&]() { pushDownSels(dfg, ctx.m_pushDownSelsContext); }); - } + run("pushDownSels", dumpLvl >= 4, [&]() { pushDownSels(dfg, ctx.m_pushDownSelsContext); }); run("cse1 ", dumpLvl >= 4, [&]() { cse(dfg, ctx.m_cseContext1); }); run("output ", dumpLvl >= 3, [&]() { /* debug dump only */ }); diff --git a/src/V3DfgPasses.h b/src/V3DfgPasses.h index da0aa1461..1ef17ea47 100644 --- a/src/V3DfgPasses.h +++ b/src/V3DfgPasses.h @@ -30,19 +30,16 @@ namespace V3DfgPasses { // Top level entry points //=========================================================================== -// 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. -std::unique_ptr astToDfg(AstModule&, V3DfgContext&) VL_MT_DISABLED; - -// Same as above, but for the entire netlist, after V3Scope +// Construct a DfGGraph representing the combinational logic in the netlist. +// The logic that is represented by the graph is removed from the netlist. +// Returns the constructed DfgGraph. std::unique_ptr astToDfg(AstNetlist&, V3DfgContext&) VL_MT_DISABLED; // Add DfgVertexAst to the given DfgGraph for all references in the given AstNode. -// The function 'getVarVertex' is used to get the DfgVertexVar for an AstVar/AstVarScope. +// The function 'getVarVertex' is used to get the DfgVertexVar for an AstVarScope. // If it returns nullptr, the reference will be ignored. void addAstRefs(DfgGraph& dfg, AstNode* nodep, - std::function getVarVertex) VL_MT_DISABLED; + std::function getVarVertex) VL_MT_DISABLED; // Remove unobservable variabels and logic that drives only such variables void removeUnobservable(DfgGraph&, V3DfgContext&) VL_MT_DISABLED; diff --git a/src/V3DfgPatternStats.h b/src/V3DfgPatternStats.h index 538d24536..4e38ec633 100644 --- a/src/V3DfgPatternStats.h +++ b/src/V3DfgPatternStats.h @@ -28,7 +28,7 @@ class V3DfgPatternStats final { static constexpr uint32_t MAX_PATTERN_DEPTH = 4; std::map m_internedConsts; // Interned constants - std::map m_internedVars; // Interned variables + std::map m_internedVars; // Interned variables std::map m_internedSelLsbs; // Interned lsb value for selects std::map m_internedWordWidths; // Interned widths std::map m_internedWideWidths; // Interned widths @@ -51,7 +51,7 @@ class V3DfgPatternStats final { } const std::string& internVar(const DfgVertexVar& vtx) { - const auto pair = m_internedVars.emplace(vtx.nodep(), "v"); + const auto pair = m_internedVars.emplace(vtx.vscp(), "v"); if (pair.second) pair.first->second += toLetters(m_internedVars.size() - 1); return pair.first->second; } @@ -167,10 +167,10 @@ public: }); } - void dump(const std::string& stage, std::ostream& os) { + void dump(std::ostream& os) { using Line = std::pair; for (uint32_t i = MIN_PATTERN_DEPTH; i <= MAX_PATTERN_DEPTH; ++i) { - os << "DFG '" << stage << "' patterns with depth " << i << '\n'; + os << "DFG patterns with depth " << i << '\n'; // Pick up pattern accumulators with given depth const auto& patternCounts = m_patterCounts[i]; diff --git a/src/V3DfgPeephole.cpp b/src/V3DfgPeephole.cpp index 2a95525ca..6acff64b7 100644 --- a/src/V3DfgPeephole.cpp +++ b/src/V3DfgPeephole.cpp @@ -38,11 +38,11 @@ #include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT +#include "V3Ast.h" #include "V3Dfg.h" #include "V3DfgCache.h" #include "V3DfgPasses.h" #include "V3DfgPeepholePatterns.h" -#include "V3Stats.h" #include #include @@ -50,36 +50,6 @@ VL_DEFINE_DEBUG_FUNCTIONS; -V3DfgPeepholeContext::V3DfgPeepholeContext(V3DfgContext& ctx, const std::string& label) - : V3DfgSubContext{ctx, label, "Peephole"} { - const auto checkEnabled = [this](VDfgPeepholePattern id) { - std::string str{id.ascii()}; - std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { // - return c == '_' ? '-' : std::tolower(c); - }); - m_enabled[id] = v3Global.opt.fDfgPeepholeEnabled(str); - }; -#define OPTIMIZATION_CHECK_ENABLED(id, name) checkEnabled(VDfgPeepholePattern::id); - FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION(OPTIMIZATION_CHECK_ENABLED) -#undef OPTIMIZATION_CHECK_ENABLED -} - -V3DfgPeepholeContext::~V3DfgPeepholeContext() { - for (AstNode* const nodep : m_deleteps) { - VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); - } - const auto emitStat = [this](VDfgPeepholePattern id) { - std::string str{id.ascii()}; - std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { // - return c == '_' ? ' ' : std::tolower(c); - }); - addStat(str, m_count[id]); - }; -#define OPTIMIZATION_EMIT_STATS(id, name) emitStat(VDfgPeepholePattern::id); - FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION(OPTIMIZATION_EMIT_STATS) -#undef OPTIMIZATION_EMIT_STATS -} - // clang-format off template struct ReductionToBitwiseImpl {}; @@ -250,9 +220,8 @@ class V3DfgPeephole final : public DfgVisitor { // to the variable and no references in other graph then delete the Ast var too. const DfgVertexVar* const varp = vtxp->cast(); if (varp && !varp->isVolatile() && !varp->hasDfgRefs()) { - AstNode* const nodep = varp->nodep(); + m_ctx.m_deleteps.push_back(varp->vscp()); VL_DO_DANGLING(vtxp->unlinkDelete(m_dfg), vtxp); - m_ctx.m_deleteps.push_back(nodep); } else { VL_DO_DANGLING(vtxp->unlinkDelete(m_dfg), vtxp); } @@ -1617,8 +1586,8 @@ class V3DfgPeephole final : public DfgVisitor { if (!idxp) return; DfgVarArray* const varp = vtxp->fromp()->cast(); if (!varp) return; - if (varp->varp()->isForced()) return; - if (varp->varp()->isSigUserRWPublic()) return; + if (varp->vscp()->varp()->isForced()) return; + if (varp->vscp()->varp()->isSigUserRWPublic()) return; DfgVertex* const srcp = varp->srcp(); if (!srcp) return; @@ -1862,16 +1831,13 @@ class V3DfgPeephole final : public DfgVisitor { DfgSplicePacked* const sp = new DfgSplicePacked{m_dfg, flp, vtxp->dtype()}; m_vInfo[sp].m_id = ++m_lastId; sp->addDriver(catp, lsb, flp); - AstScope* const scopep = [&]() -> AstScope* { - if (m_dfg.modulep()) return nullptr; - DfgVertex::ScopeCache scopeCache; - return vtxp->scopep(scopeCache, true); - }(); + DfgVertex::ScopeCache scopeCache; + AstScope* const scopep = vtxp->scopep(scopeCache, true); const std::string name = m_dfg.makeUniqueName("PeepholeNarrow", m_nTemps++); DfgVertexVar* const varp = m_dfg.makeNewVar(flp, name, vtxp->dtype(), scopep); - varp->tmpForp(varp->nodep()); + varp->tmpForp(varp->vscp()); m_vInfo[varp].m_id = ++m_lastId; - varp->varp()->isInternal(true); + varp->vscp()->varp()->isInternal(true); varp->srcp(sp); replace(varp); return; @@ -2591,8 +2557,6 @@ class V3DfgPeephole final : public DfgVisitor { if (const DfgVertexVar* const varp = sink.cast()) { if (!varp->hasSinks() && !varp->isObserved()) return false; } - // Keep before final scoped run if feeds an Ast reference - if (sink.is() && m_dfg.modulep()) return true; // Keep if found more than one sink if (foundOne) return true; // Mark first sink found diff --git a/src/V3DfgRegularize.cpp b/src/V3DfgRegularize.cpp index 3f9a29af5..622bb4648 100644 --- a/src/V3DfgRegularize.cpp +++ b/src/V3DfgRegularize.cpp @@ -54,26 +54,6 @@ class DfgRegularize final { vtx.replaceWith(varp); varp->srcp(&vtx); } - - // Const vertices driving an Ast reference can only be inlined in scoped - // mode as some algorithms assume VarRefs in certain places. - if (m_dfg.modulep()) { - for (DfgConst& vtx : m_dfg.constVertices()) { - const bool drivesAstRef = vtx.foreachSink([](const DfgVertex& dst) { // - return dst.is(); - }); - if (!drivesAstRef) continue; - - // The prefered result variable is the canonical one if exists - DfgVertexVar* const varp = vtx.getResultVar(); - if (!varp) continue; - - // Relink all other sinks reading this vertex to read 'varp' - varp->srcp(nullptr); - vtx.replaceWith(varp); - varp->srcp(&vtx); - } - } } std::unordered_set gatherCyclicVariables() { @@ -108,9 +88,6 @@ class DfgRegularize final { UASSERT_OBJ(!aVtx.is(), &aVtx, "Should be an operation vertex"); if (bVtx.hasMultipleSinks()) { - // We are not inlining expressions prior to the final scoped run - if (m_dfg.modulep()) return true; - // Add a temporary if it's cheaper to store and load from memory than recompute if (!aVtx.isCheaperThanLoad()) return true; @@ -123,10 +100,8 @@ class DfgRegularize final { // No need to add a temporary if the single sink is a variable already if (sink.is()) return false; - // Do not inline expressions prior to the final scoped run, or if they are in a loop - if (const DfgAstRd* const astRdp = sink.cast()) { - return m_dfg.modulep() || astRdp->inLoop(); - } + // Do not inline expressions into a loop body + if (const DfgAstRd* const astRdp = sink.cast()) { return astRdp->inLoop(); } // Make sure roots of wide concatenation trees are written to variables, // this enables V3FuncOpt to split them which can be a big speed gain @@ -163,7 +138,7 @@ class DfgRegularize final { }); // Delete corresponsing Ast variable at the end if (const DfgVertexVar* const varp = vtx.cast()) { - m_ctx.m_deleteps.push_back(varp->nodep()); + m_ctx.m_deleteps.push_back(varp->vscp()); } // Remove the unused vertex vtx.unlinkDelete(m_dfg); @@ -218,7 +193,6 @@ class DfgRegularize final { // Insert a temporary variable for all vertices that have multiple non-variable sinks // Scope cache for below - const bool scoped = !m_dfg.modulep(); DfgVertex::ScopeCache scopeCache; // Ensure intermediate values used multiple times are written to variables @@ -233,7 +207,7 @@ class DfgRegularize final { ++m_ctx.m_temporariesIntroduced; const std::string name = m_dfg.makeUniqueName("Regularize", m_nTmps); FileLine* const flp = vtx.fileline(); - AstScope* const scopep = scoped ? vtx.scopep(scopeCache) : nullptr; + AstScope* const scopep = vtx.scopep(scopeCache); DfgVertexVar* const newp = m_dfg.makeNewVar(flp, name, vtx.dtype(), scopep); ++m_nTmps; // Replace vertex with the variable, make it drive the variable @@ -248,13 +222,13 @@ class DfgRegularize final { , m_ctx{ctx} { uninlineVariables(); - if (dumpDfgLevel() >= 9) dfg.dumpDotFilePrefixed(ctx.prefix() + "regularize-uninlined"); + if (dumpDfgLevel() >= 9) dfg.dumpDotFilePrefixed("regularize-uninlined"); eliminateVars(); - if (dumpDfgLevel() >= 9) dfg.dumpDotFilePrefixed(ctx.prefix() + "regularize-eliminate"); + if (dumpDfgLevel() >= 9) dfg.dumpDotFilePrefixed("regularize-eliminate"); insertTemporaries(); - if (dumpDfgLevel() >= 9) dfg.dumpDotFilePrefixed(ctx.prefix() + "regularize-inserttmp"); + if (dumpDfgLevel() >= 9) dfg.dumpDotFilePrefixed("regularize-inserttmp"); } public: diff --git a/src/V3DfgSynthesize.cpp b/src/V3DfgSynthesize.cpp index 36333a950..745b41461 100644 --- a/src/V3DfgSynthesize.cpp +++ b/src/V3DfgSynthesize.cpp @@ -21,12 +21,12 @@ #include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT +#include "V3Ast.h" #include "V3Cfg.h" #include "V3Const.h" #include "V3Dfg.h" #include "V3DfgPasses.h" #include "V3EmitV.h" -#include "V3Os.h" #include #include @@ -55,16 +55,12 @@ DfgArraySel* makeVertex(const AstArraySel* nodep, DfgG } // namespace // Visitor that can convert Ast statements and expressions in Dfg vertices -template class AstToDfgConverter final : public VNVisitor { // NODE STATE // AstNodeExpr/AstVar/AstVarScope::user2p -> DfgVertex* for this Node // AstVar::user3() -> int temporary counter for variable const VNUser3InUse m_user3InUse; - // TYPES - using Variable = std::conditional_t; - // STATE DfgGraph& m_dfg; // The graph being built V3DfgSynthesisContext& m_ctx; // The context for stats @@ -73,7 +69,7 @@ class AstToDfgConverter final : public VNVisitor { DfgLogic* m_logicp = nullptr; // Variable updates produced by currently converted statement. This almost // always have a single element, so a vector is ok - std::vector>* m_updatesp = nullptr; + std::vector>* m_updatesp = nullptr; bool m_foundUnhandled = false; // Found node not implemented as DFG or not implemented 'visit' bool m_converting = false; // We are trying to convert some logic at the moment @@ -81,14 +77,6 @@ class AstToDfgConverter final : public VNVisitor { size_t m_nUnpack = 0; // Sequence numbers for temporaries // METHODS - static Variable* getTarget(const AstVarRef* refp) { - // TODO: remove the useless reinterpret_casts when C++17 'if constexpr' actually works - if VL_CONSTEXPR_CXX17 (T_Scoped) { - return reinterpret_cast(refp->varScopep()); - } else { - return reinterpret_cast(refp->varp()); - } - } // Allocate a new non-variable vertex, add it to the currently synthesized logic template @@ -117,7 +105,7 @@ class AstToDfgConverter final : public VNVisitor { // Cannot represent cross module references if (nodep->classOrPackagep()) return false; // Check target - return V3Dfg::isSupported(getTarget(nodep)); + return V3Dfg::isSupported(nodep->varScopep()); } // Given an RValue expression, return the equivalent Vertex, or nullptr if not representable. @@ -154,16 +142,16 @@ class AstToDfgConverter final : public VNVisitor { // Get (or create a new) temporary for this variable const DfgVertexVar* const vtxp = [&]() -> DfgVertexVar* { // The variable being assigned - Variable* const tgtp = getTarget(vrefp); + AstVarScope* const vscp = vrefp->varScopep(); // Find existing one, if any for (const auto& pair : *m_updatesp) { - if (pair.first == tgtp) return pair.second; + if (pair.first == vscp) return pair.second; } // Create new one - DfgVertexVar* const newp = createTmp(*m_logicp, tgtp, "SynthAssign"); - m_updatesp->emplace_back(tgtp, newp); + DfgVertexVar* const newp = createTmp(*m_logicp, vscp, "SynthAssign"); + m_updatesp->emplace_back(vscp, newp); // Create the Splice driver for the new temporary if (newp->is()) { @@ -375,7 +363,7 @@ class AstToDfgConverter final : public VNVisitor { } // Variable should have been bound before starting conversion - DfgVertex* const vtxp = getTarget(nodep)->user2u().template to(); + DfgVertex* const vtxp = nodep->varScopep()->user2u().template to(); UASSERT_OBJ(vtxp, nodep, "Referenced variable has no associated DfgVertexVar"); nodep->user2p(vtxp); } @@ -450,27 +438,26 @@ public: const std::string name = m_dfg.makeUniqueName(prefix, tmpCount); DfgVertexVar* const vtxp = m_dfg.makeNewVar(flp, name, dtype, logic.scopep()); logic.synth().emplace_back(vtxp); - vtxp->varp()->isInternal(true); - vtxp->tmpForp(vtxp->nodep()); + vtxp->vscp()->varp()->isInternal(true); + vtxp->tmpForp(vtxp->vscp()); return vtxp; } // Create a new temporary variable capable of holding 'varp' - DfgVertexVar* createTmp(DfgLogic& logic, Variable* varp, const std::string& prefix) { - AstVar* const astVarp = T_Scoped ? reinterpret_cast(varp)->varp() - : reinterpret_cast(varp); + DfgVertexVar* createTmp(DfgLogic& logic, AstVarScope* vscp, const std::string& prefix) { + AstVar* const astVarp = vscp->varp(); FileLine* const flp = astVarp->fileline(); const DfgDataType& dtype = *DfgDataType::fromAst(astVarp->dtypep()); const std::string prfx = prefix + "_" + astVarp->name(); const size_t tmpCount = astVarp->user3Inc(); DfgVertexVar* const vtxp = createTmp(logic, flp, dtype, prfx, tmpCount); - vtxp->tmpForp(varp); + vtxp->tmpForp(vscp); return vtxp; } // Convert AstAssign to Dfg, return true if successful. // Fills 'updates' with bindings for assigned variables. - bool convert(std::vector>& updates, DfgLogic& vtx, + bool convert(std::vector>& updates, DfgLogic& vtx, AstNodeAssign* nodep) { UASSERT_OBJ(VN_IS(nodep, Assign) || VN_IS(nodep, AssignW), nodep, "Bad NodeAssign"); UASSERT_OBJ(updates.empty(), nodep, "'updates' should be empty"); @@ -530,21 +517,19 @@ public: // Debug aid - outisde 'AstToDfgSynthesize' as it is a template, but want one instance V3DebugBisect s_dfgSynthDebugBisect{"DfgSynthesize"}; -template class AstToDfgSynthesize final { // NODE STATE // AstNodeExpr/AstVar/AstVarScope::user2p -> DfgVertex* for this Node // TYPES - using Variable = std::conditional_t; // SymTab must be ordered in order to yield stable results - struct VariableComparator final { - bool operator()(const Variable* lhs, const Variable* rhs) const { + struct AstVarScopeComparator final { + bool operator()(const AstVarScope* lhs, const AstVarScope* rhs) const { return lhs->name() < rhs->name(); } }; - using SymTab = std::map; + using SymTab = std::map; // Represents a [potentially partial] driver of a variable struct Driver final { @@ -573,7 +558,7 @@ class AstToDfgSynthesize final { // STATE - Persistent DfgGraph& m_dfg; // The graph being built V3DfgSynthesisContext& m_ctx; // The context for stats - AstToDfgConverter m_converter; // The convert instance to use for each construct + AstToDfgConverter m_converter; // The convert instance to use for each construct size_t m_nBranchCond = 0; // Sequence numbers for temporaries size_t m_nPathPred = 0; // Sequence numbers for temporaries DfgWorklist m_toRevert{m_dfg}; // We need a worklist for reverting synthesis @@ -609,26 +594,16 @@ class AstToDfgSynthesize final { } if (VL_UNLIKELY(dumpDfgLevel() >= 9 || m_debugOSrcConep)) { - const auto label = m_ctx.prefix() + name; - m_dfg.dumpDotFilePrefixed(label); + m_dfg.dumpDotFilePrefixed(name); if (m_debugOSrcConep) { // Dump only the subgraph involving the inputs and outputs of the bad vertex - m_dfg.dumpDotFilePrefixed(label + "-min", [&](const DfgVertex& v) -> bool { + m_dfg.dumpDotFilePrefixed(name + "-min"s, [&](const DfgVertex& v) -> bool { return m_debugOSrcConep->count(&v); }); } } } - static AstVar* getAstVar(Variable* vp) { - // TODO: remove the useless reinterpret_casts when C++17 'if constexpr' actually works - if VL_CONSTEXPR_CXX17 (T_Scoped) { - return reinterpret_cast(vp)->varp(); - } else { - return reinterpret_cast(vp); - } - } - // Allocate a new non-variable vertex, add it to the currently synthesized logic template Vertex* make(Args&&... args) { @@ -674,14 +649,7 @@ class AstToDfgSynthesize final { if (std::find(visited.begin(), visited.end(), vtxp) != visited.end()) continue; visited.emplace_back(vtxp); if (const DfgVertexVar* const varp = vtxp->cast()) { - AstVar* const astVarp = [&]() -> AstVar* { - if VL_CONSTEXPR_CXX17 (T_Scoped) { - return reinterpret_cast(varp->nodep())->varp(); - } else { - return reinterpret_cast(varp->nodep()); - } - }(); - if (astVarp->dfgTriLowered()) return true; + if (varp->vscp()->varp()->dfgTriLowered()) return true; } vtxp->foreachSource([&](const DfgVertex& src) { stack.emplace_back(&src); @@ -849,15 +817,14 @@ class AstToDfgSynthesize final { if (warned) continue; // The variable to warn on - AstNode* const nodep = var.tmpForp() ? var.tmpForp() : var.nodep(); - Variable* const varp = reinterpret_cast(nodep); + AstVarScope* const vscp = var.tmpForp() ? var.tmpForp() : var.vscp(); // Loop index often abused, so suppress - if (getAstVar(varp)->isUsedLoopIdx()) continue; + if (vscp->varp()->isUsedLoopIdx()) continue; // Tristate lowering can intentionally create overlapping contributors. // Keep the signal marked multidriven for DFG fallback, but suppress // warning only when both overlapping driver cones look tri-lowered. - if (getAstVar(varp)->dfgAllowMultidriveTri()) { + if (vscp->varp()->dfgAllowMultidriveTri()) { const bool iTri = containsTriLoweredVar(iD.m_vtxp); const bool jTri = containsTriLoweredVar(jD.m_vtxp); const bool triPair = iTri && jTri; @@ -872,9 +839,9 @@ class AstToDfgSynthesize final { const std::string kind = isPacked ? "Bit" : "Element"; const std::string part = hi == lo ? (" [" + lo + "]") : ("s [" + hi + ":" + lo + "]"); - varp->v3warn( // + vscp->v3warn( // MULTIDRIVEN, // - kind << part << " of signal '" << varp->prettyName() << sub << "'" + kind << part << " of signal '" << vscp->prettyName() << sub << "'" << " have multiple combinational drivers." << " This can cause performance degradation.\n" << iD.m_flp->warnOther() << "... Location of offending driver\n" @@ -961,29 +928,28 @@ class AstToDfgSynthesize final { void initializeEntrySymbolTable(SymTab& iSymTab) { m_logicp->foreachSource([&](DfgVertex& src) { DfgVertexVar* const vvp = src.as(); - Variable* const varp = reinterpret_cast(vvp->nodep()); - iSymTab[varp] = vvp; + iSymTab[vvp->vscp()] = vvp; return false; }); } // Join variable drivers across a control flow confluence (insert muxes ...) - DfgVertexVar* joinDrivers(Variable* varp, DfgVertexVar* predicatep, // + DfgVertexVar* joinDrivers(AstVarScope* vscp, DfgVertexVar* predicatep, // DfgVertexVar* thenp, DfgVertexVar* elsep) { - AstNode* const thenVarp = thenp->tmpForp() ? thenp->tmpForp() : thenp->nodep(); - AstNode* const elseVarp = elsep->tmpForp() ? elsep->tmpForp() : elsep->nodep(); - UASSERT_OBJ(thenVarp == elseVarp, varp, "Attempting to join unrelated variables"); + AstVarScope* const thenVscp = thenp->tmpForp() ? thenp->tmpForp() : thenp->vscp(); + AstVarScope* const elseVscp = elsep->tmpForp() ? elsep->tmpForp() : elsep->vscp(); + UASSERT_OBJ(thenVscp == elseVscp, vscp, "Attempting to join unrelated variables"); // If both bindings are the the same (variable not updated through either path), // then there is nothing to do, can use the same binding if (thenp == elsep) return thenp; // We can't join the input variable just yet, so bail - if (thenp->nodep() == varp) { + if (thenp->vscp() == vscp) { ++m_ctx.m_synt.nonSynJoinInput; return nullptr; } - if (elsep->nodep() == varp) { + if (elsep->vscp() == vscp) { ++m_ctx.m_synt.nonSynJoinInput; return nullptr; } @@ -1003,13 +969,13 @@ class AstToDfgSynthesize final { std::vector eDrivers = gatherDrivers(elsep->srcp()->as()); // Default drivers should be the same or not present on either - UASSERT_OBJ(tDefaultp == eDefaultp, varp, "Different default drivers"); + UASSERT_OBJ(tDefaultp == eDefaultp, vscp, "Different default drivers"); // Location to use for the join vertices FileLine* const flp = predicatep->fileline(); // Create a fresh temporary for the joined value - DfgVertexVar* const joinp = m_converter.createTmp(*m_logicp, varp, "SynthJoin"); + DfgVertexVar* const joinp = m_converter.createTmp(*m_logicp, vscp, "SynthJoin"); DfgVertexSplice* const joinSplicep = make(flp, joinp->dtype()); joinp->srcp(joinSplicep); @@ -1020,7 +986,7 @@ class AstToDfgSynthesize final { && eDrivers.size() == 1 // && eDrivers[0].m_lo == 0 // && eDrivers[0].m_hi == elsep->width() - 1) { - UASSERT_OBJ(!tDefaultp, varp, "Fully driven variable have default driver"); + UASSERT_OBJ(!tDefaultp, vscp, "Fully driven variable have default driver"); DfgCond* const condp = make(flp, joinp->dtype()); condp->condp(predicatep); @@ -1081,11 +1047,11 @@ class AstToDfgSynthesize final { // Any variable that does not have a binding on both paths will be removed. These might be // temporaries, loop vars, etc used only in one branch. Conversion will fail if the // variable is actually referenced later. - std::vector toRemove; + std::vector toRemove; // Join each symbol - for (std::pair& pair : elseSymTab) { - Variable* const varp = pair.first; + for (std::pair& pair : elseSymTab) { + AstVarScope* const varp = pair.first; // Find same variable on the else path const auto it = thenSymTab.find(varp); // Record for removal if not assigned on both paths @@ -1102,7 +1068,7 @@ class AstToDfgSynthesize final { } // Remove variables not assigned on both paths - for (Variable* const varp : toRemove) elseSymTab.erase(varp); + for (AstVarScope* const varp : toRemove) elseSymTab.erase(varp); // Done return true; @@ -1285,8 +1251,8 @@ class AstToDfgSynthesize final { // Given the drivers of a variable after converting a single statement // 'newp', add drivers from 'oldp' that were not reassigned be drivers // in newp. This computes the total result of all previous assignments. - bool incorporatePreviousValue(Variable* varp, DfgVertexVar* newp, DfgVertexVar* oldp) { - UASSERT_OBJ(newp->srcp(), varp, "Assigned variable has no driver"); + bool incorporatePreviousValue(AstVarScope* vscp, DfgVertexVar* newp, DfgVertexVar* oldp) { + UASSERT_OBJ(newp->srcp(), vscp, "Assigned variable has no driver"); // Easy if there is no old value... if (!oldp) return true; @@ -1296,12 +1262,12 @@ class AstToDfgSynthesize final { // If the old value is the real variable we just computed the new value for, // then it is the circular feedback into the synthesized block, add it as default driver. - if (oldp->nodep() == varp) { + if (oldp->vscp() == vscp) { if (!nSplicep->wholep()) newp->defaultp(oldp); return true; } - UASSERT_OBJ(oldp->srcp(), varp, "Previously assigned variable has no driver"); + UASSERT_OBJ(oldp->srcp(), vscp, "Previously assigned variable has no driver"); // Can't do arrays yet if (!newp->isPacked()) { @@ -1347,16 +1313,16 @@ class AstToDfgSynthesize final { // Use fresh set of vertices in m_converter const VNUser2InUse user2InUse; - // Initialize Variable -> Vertex bindings available in this block + // Initialize AstVarScope -> Vertex bindings available in this block for (const auto& pair : iSymTab) { - Variable* const varp = pair.first; + AstVarScope* const varp = pair.first; DfgVertexVar* const vtxp = pair.second; varp->user2p(vtxp); oSymTab[varp] = vtxp; } // Synthesize each statement one after the other - std::vector> updates; + std::vector> updates; for (AstNodeStmt* const stmtp : stmtps) { // Regular statements AstNodeAssign* const ap = VN_CAST(stmtp, NodeAssign); @@ -1369,7 +1335,7 @@ class AstToDfgSynthesize final { // Apply variable updates from this statement for (const auto& pair : updates) { // The target variable that was assigned to - Variable* const varp = pair.first; + AstVarScope* const vscp = pair.first; // The new, potentially partially assigned value DfgVertexVar* const newp = pair.second; // Normalize drivers within this statement, bail if multidriven @@ -1377,7 +1343,6 @@ class AstToDfgSynthesize final { std::vector drivers = gatherDrivers(srcp); const bool single = drivers.size() == 1; if (!normalizeDrivers(*newp, drivers)) { - getAstVar(varp)->setDfgMultidriven(); ++m_ctx.m_synt.nonSynMultidrive; return false; } @@ -1387,13 +1352,13 @@ class AstToDfgSynthesize final { for (const Driver& d : drivers) srcp->addDriver(d.m_vtxp, d.m_lo, d.m_flp); } // The old value, if any - DfgVertexVar* const oldp = varp->user2u().template to(); + DfgVertexVar* const oldp = vscp->user2u().template to(); // Inncorporate old value into the new value - if (!incorporatePreviousValue(varp, newp, oldp)) return false; + if (!incorporatePreviousValue(vscp, newp, oldp)) return false; // Update binding of target variable - varp->user2p(newp); + vscp->user2p(newp); // Update output symbol table of this block - oSymTab[varp] = newp; + oSymTab[vscp] = newp; } updates.clear(); continue; @@ -1518,10 +1483,8 @@ class AstToDfgSynthesize final { // braces and check here too. We can't touch any output variables if so. const bool missing = m_logicp->foreachSink([&](const DfgVertex& sink) { const DfgUnresolved* const unresolvedp = sink.as(); - AstNode* const tgtp = unresolvedp->singleSink()->as()->nodep(); - // cppcheck-suppress constVariablePointer - Variable* const varp = reinterpret_cast(tgtp); - return !oSymTab.count(varp); + AstVarScope* const vscp = unresolvedp->singleSink()->as()->vscp(); + return !oSymTab.count(vscp); }); if (missing) { ++m_ctx.m_synt.nonSynFalseWrite; @@ -1532,7 +1495,7 @@ class AstToDfgSynthesize final { return !m_logicp->foreachSink([&](DfgVertex& sink) { DfgUnresolved* const unresolvedp = sink.as(); const DfgVertexVar* const varp = unresolvedp->singleSink()->as(); - DfgVertexVar* const resp = oSymTab.at(reinterpret_cast(varp->nodep())); + DfgVertexVar* const resp = oSymTab.at(varp->vscp()); UASSERT_OBJ(resp->srcp(), resp, "Undriven result"); // If the output is not used further in the synthesized logic itself, @@ -1750,10 +1713,10 @@ class AstToDfgSynthesize final { // There should be no sinks left for unselected DfgLogic, delete them here UASSERT_OBJ(!logicp->hasSinks(), vtxp, "Unselected 'DfgLogic' with sinks remaining"); // Input variables will be read in Ast code, add Ast reference vertices - // AstVar/AstVarScope::user4p() -> corresponding DfgVertexVar* in the graph + // AstVarScope::user4p() -> corresponding DfgVertexVar* in the graph const VNUser4InUse m_user4InUse; logicp->foreachSource([](DfgVertex& src) { - src.as()->nodep()->user4p(&src); + src.as()->vscp()->user4p(&src); return false; }); V3DfgPasses::addAstRefs(m_dfg, logicp->nodep(), [](AstNode* varp) { // @@ -1831,8 +1794,6 @@ class AstToDfgSynthesize final { const bool newEntry = resolvedDrivers.emplace(&var, resolvedp).second; UASSERT_OBJ(newEntry, &var, "Dupliacte driver"); } - // Mark as multidriven for future DFG runs - here, so we get all warnings above - for (const DfgVertexVar* const vtxp : multidrivenps) vtxp->varp()->setDfgMultidriven(); // Revert and remove drivers of multi-driven variables revert(m_ctx.m_synt.revertMultidrive); // Replace all DfgUnresolved with the resolved drivers @@ -1866,10 +1827,10 @@ class AstToDfgSynthesize final { } else { // Not synthesized. Logic stays in Ast. Add Ast reference vertices. // Outputs already marked by revertTransivelyAndRemove. - // AstVar/AstVarScope::user4p() -> corresponding DfgVertexVar* in the graph + // AstVarScope::user4p() -> corresponding DfgVertexVar* in the graph const VNUser4InUse m_user4InUse; logicp->foreachSource([](DfgVertex& src) { - src.as()->nodep()->user4p(&src); + src.as()->vscp()->user4p(&src); return false; }); V3DfgPasses::addAstRefs(m_dfg, logicp->nodep(), [](AstNode* varp) { // @@ -1926,7 +1887,7 @@ public: // Final step outside, as both AstToDfgSynthesize and removeUnused used DfgUserMap UINFO(5, "Step 6: Remove all unused vertices"); V3DfgPasses::removeUnused(dfg); - if (dumpDfgLevel() >= 9) dfg.dumpDotFilePrefixed(ctx.prefix() + "synth-rmunused"); + if (dumpDfgLevel() >= 9) dfg.dumpDotFilePrefixed("synth-rmunused"); // No operation vertex should have multiple sinks. Cyclic decomoposition // depends on this and it can easily be ensured by using temporaries. @@ -2021,9 +1982,5 @@ void V3DfgPasses::synthesize(DfgGraph& dfg, V3DfgContext& ctx) { // Select which DfgLogic to attempt to synthesize dfgSelectLogicForSynthesis(dfg); // Synthesize them - also removes un-synthesized DfgLogic, so must run even if nothing selected - if (dfg.modulep()) { - AstToDfgSynthesize::apply(dfg, ctx.m_synthContext); - } else { - AstToDfgSynthesize::apply(dfg, ctx.m_synthContext); - } + AstToDfgSynthesize::apply(dfg, ctx.m_synthContext); } diff --git a/src/V3DfgVertices.h b/src/V3DfgVertices.h index 82719e7d8..7a8fe1040 100644 --- a/src/V3DfgVertices.h +++ b/src/V3DfgVertices.h @@ -48,47 +48,32 @@ class DfgVertexVar VL_NOT_FINAL : public DfgVertex { // Represents a variable. It has 2 optional inputs, 'srcp' and 'defaultp'. - AstVar* const m_varp; // The AstVar associated with this vertex (not owned by this vertex) - AstVarScope* const m_varScopep; // The AstVarScope associated with this vertex (not owned) + AstVarScope* const m_vscp; // The AstVarScope associated with this vertex (not owned) // Location of driver of this variable. Only used for converting back to Ast. Might be nullptr. FileLine* m_driverFileLine = nullptr; - // If this DfgVertexVar is a synthesized temporary, this is the original Var/VarScope it stands - // for. It might point to m_varp/m_varScopep itself to indicate it's a temporary without an - // associated input Var/VarScope. - AstNode* m_tmpForp = nullptr; + // If this DfgVertexVar is a synthesized temporary, this is the original AstVarScope it stands + // for. It might point to m_vscp itself to indicate it's a temporary without an associated + // input AstVarScope. + AstVarScope* m_tmpForp = nullptr; - DfgVertexVar(DfgGraph& dfg, VDfgType type, AstVar* varp, AstVarScope* vscp) - : DfgVertex{dfg, type, varp->fileline(), *DfgDataType::fromAst(varp->dtypep())} - , m_varp{varp} - , m_varScopep{vscp} { -#ifdef VL_DEBUG - if (v3Global.rootp()->topScopep()) { - UASSERT_OBJ(vscp, varp, "Un-scoped DfgVertexVar created in scoped DfgGraph"); - } else { - UASSERT_OBJ(!vscp, varp, "Scoped DfgVertexVar created in un-scoped DfgGraph"); - } -#endif +protected: + DfgVertexVar(DfgGraph& dfg, VDfgType type, AstVarScope* vscp) + : DfgVertex{dfg, type, vscp->varp()->fileline(), + *DfgDataType::fromAst(vscp->varp()->dtypep())} + , m_vscp{vscp} { // Increment reference count - AstNode* const variablep = nodep(); - variablep->user1(variablep->user1() + 0x20); - UASSERT_OBJ((variablep->user1() >> 5) > 0, variablep, "Reference count overflow"); + m_vscp->user1(m_vscp->user1() + 0x20); + UASSERT_OBJ((m_vscp->user1() >> 5) > 0, m_vscp, "Reference count overflow"); // Allocate sources newInput(); newInput(); } -protected: - DfgVertexVar(DfgGraph& dfg, VDfgType type, AstVar* varp) - : DfgVertexVar{dfg, type, varp, nullptr} {} - DfgVertexVar(DfgGraph& dfg, VDfgType type, AstVarScope* vscp) - : DfgVertexVar{dfg, type, vscp->varp(), vscp} {} - public: ~DfgVertexVar() { // Decrement reference count - AstNode* const variablep = nodep(); - variablep->user1(variablep->user1() - 0x20); - UASSERT_OBJ((variablep->user1() >> 5) >= 0, variablep, "Reference count underflow"); + m_vscp->user1(m_vscp->user1() - 0x20); + UASSERT_OBJ((m_vscp->user1() >> 5) >= 0, m_vscp, "Reference count underflow"); } ASTGEN_MEMBERS_DfgVertexVar; @@ -102,42 +87,39 @@ public: std::string srcName(size_t idx) const override final { return idx ? "defaultp" : "srcp"; } // The Ast variable this vertex representess - AstVar* varp() const { return m_varp; } - AstVarScope* varScopep() const { return m_varScopep; } - AstNode* nodep() const { - return m_varScopep ? static_cast(m_varScopep) : static_cast(m_varp); - } + // AstVar* varp() const { return m_varp; } + AstVarScope* vscp() const { return m_vscp; } // If this is a temporary, the Ast variable it stands for, or same as // 'nodep()' if it's a temporary with no associated original Ast variable. - AstNode* tmpForp() const { return m_tmpForp; } - void tmpForp(AstNode* nodep) { m_tmpForp = nodep; } + AstVarScope* tmpForp() const { return m_tmpForp; } + void tmpForp(AstVarScope* nodep) { m_tmpForp = nodep; } // Location of driver of variable (only used if 'srcp' is not a splice) FileLine* driverFileLine() const { return m_driverFileLine; } void driverFileLine(FileLine* flp) { m_driverFileLine = flp; } // Variable referenced from other DFG in the same module/netlist - bool hasDfgRefs() const { return nodep()->user1() >> 6; } // I.e.: (nodep()->user1() >> 5) > 1 + bool hasDfgRefs() const { return m_vscp->user1() >> 6; } // I.e.: (nodep()->user1() >> 5) > 1 // Variable referenced from Ast code in the same module/netlist - static bool hasModWrRefs(const AstNode* nodep) { return nodep->user1() & 0x08; } - static void setHasModWrRefs(AstNode* nodep) { nodep->user1(nodep->user1() | 0x08); } - bool hasModWrRefs() const { return hasModWrRefs(nodep()); } - void setHasModWrRefs() const { setHasModWrRefs(nodep()); } + static bool hasModWrRefs(const AstVarScope* nodep) { return nodep->user1() & 0x08; } + static void setHasModWrRefs(AstVarScope* nodep) { nodep->user1(nodep->user1() | 0x08); } + bool hasModWrRefs() const { return hasModWrRefs(m_vscp); } + void setHasModWrRefs() const { setHasModWrRefs(m_vscp); } // Variable referenced outside the containing module/netlist. - static bool hasExtRdRefs(const AstNode* nodep) { return nodep->user1() & 0x01; } - static bool hasExtWrRefs(const AstNode* nodep) { return nodep->user1() & 0x02; } - static void setHasExtRdRefs(AstNode* nodep) { nodep->user1(nodep->user1() | 0x01); } - static void setHasExtWrRefs(AstNode* nodep) { nodep->user1(nodep->user1() | 0x02); } - bool hasExtRdRefs() const { return hasExtRdRefs(nodep()); } - bool hasExtWrRefs() const { return hasExtWrRefs(nodep()); } + static bool hasExtRdRefs(const AstVarScope* nodep) { return nodep->user1() & 0x01; } + static bool hasExtWrRefs(const AstVarScope* nodep) { return nodep->user1() & 0x02; } + static void setHasExtRdRefs(AstVarScope* nodep) { nodep->user1(nodep->user1() | 0x01); } + static void setHasExtWrRefs(AstVarScope* nodep) { nodep->user1(nodep->user1() | 0x02); } + bool hasExtRdRefs() const { return hasExtRdRefs(m_vscp); } + bool hasExtWrRefs() const { return hasExtWrRefs(m_vscp); } bool hasExtRefs() const { return hasExtRdRefs() || hasExtWrRefs(); } // Variable referenced via READWRITE references - static bool hasRWRefs(const AstNode* nodep) { return nodep->user1() & 0x10; } - static void setHasRWRefs(AstNode* nodep) { nodep->user1(nodep->user1() | 0x10); } + static bool hasRWRefs(const AstVarScope* nodep) { return nodep->user1() & 0x10; } + static void setHasRWRefs(AstVarScope* nodep) { nodep->user1(nodep->user1() | 0x10); } // True iff the value of this variable is read outside this DfgGraph bool isObserved() const { @@ -150,10 +132,10 @@ public: // The value of this vertex might differ from what is defined by its drivers // 'srcp' and 'defaultp'. That is, it might be assigned, possibly partially, // or abruptly outside the graph, hence it is not equivalent to its 'srcp'. - static bool isVolatile(const AstNode* nodep) { + static bool isVolatile(const AstVarScope* nodep) { return hasModWrRefs(nodep) || hasExtWrRefs(nodep); } - bool isVolatile() const { return isVolatile(nodep()); } + bool isVolatile() const { return isVolatile(m_vscp); } }; class DfgVarArray final : public DfgVertexVar { @@ -161,10 +143,6 @@ class DfgVarArray final : public DfgVertexVar { friend class DfgVisitor; public: - DfgVarArray(DfgGraph& dfg, AstVar* varp) - : DfgVertexVar{dfg, dfgType(), varp} { - UASSERT_OBJ(isArray(), varp, "Non-array DfgVarArray"); - } DfgVarArray(DfgGraph& dfg, AstVarScope* vscp) : DfgVertexVar{dfg, dfgType(), vscp} { UASSERT_OBJ(isArray(), vscp, "Non-array DfgVarArray"); @@ -177,10 +155,6 @@ class DfgVarPacked final : public DfgVertexVar { friend class DfgVisitor; public: - DfgVarPacked(DfgGraph& dfg, AstVar* varp) - : DfgVertexVar{dfg, dfgType(), varp} { - UASSERT_OBJ(isPacked(), varp, "Non-packed DfgVarPacked"); - } DfgVarPacked(DfgGraph& dfg, AstVarScope* vscp) : DfgVertexVar{dfg, dfgType(), vscp} { UASSERT_OBJ(isPacked(), vscp, "Non-packed DfgVarPacked"); diff --git a/src/V3Options.cpp b/src/V3Options.cpp index f0b9a77f6..d7ef86388 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -1455,11 +1455,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, DECL_OPTION("-fdead-assigns", FOnOff, &m_fDeadAssigns); DECL_OPTION("-fdead-cells", FOnOff, &m_fDeadCells); DECL_OPTION("-fdedup", FOnOff, &m_fDedupe); - DECL_OPTION("-fdfg", CbFOnOff, [this](bool flag) { - m_fDfgPreInline = flag; - m_fDfgPostInline = flag; - m_fDfgScoped = flag; - }); + DECL_OPTION("-fdfg", CbFOnOff, [this](bool flag) { m_fDfg = flag; }); DECL_OPTION("-fdfg-break-cycles", FOnOff, &m_fDfgBreakCycles); DECL_OPTION("-fdfg-peephole", FOnOff, &m_fDfgPeephole); DECL_OPTION("-fdfg-peephole-", CbPartialMatch, [this](const char* optp) { // @@ -1468,11 +1464,18 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, DECL_OPTION("-fno-dfg-peephole-", CbPartialMatch, [this](const char* optp) { // m_fDfgPeepholeDisabled.emplace(optp); }); - DECL_OPTION("-fdfg-pre-inline", FOnOff, &m_fDfgPreInline); - DECL_OPTION("-fdfg-post-inline", FOnOff, &m_fDfgPostInline); + DECL_OPTION("-fdfg-pre-inline", CbFOnOff, [fl](bool) { + fl->v3warn(DEPRECATED, "Option '-fno-dfg-pre-inline' is deprecated and has no effect"); + }); + DECL_OPTION("-fdfg-post-inline", CbFOnOff, [fl](bool) { + fl->v3warn(DEPRECATED, "Option '-fno-dfg-post-inline' is deprecated and has no effect"); + }); DECL_OPTION("-fdfg-push-down-sels", FOnOff, &m_fDfgPushDownSels); - DECL_OPTION("-fdfg-scoped", FOnOff, &m_fDfgScoped); DECL_OPTION("-fdfg-synthesize-all", FOnOff, &m_fDfgSynthesizeAll); + DECL_OPTION("-fdfg-scoped", CbFOnOff, [this, fl](bool flag) { + fl->v3warn(DEPRECATED, "Option '-fno-dfg-scoped' is deprecated, use '-fno-dfg' instead."); + m_fDfg = flag; + }); DECL_OPTION("-fexpand", FOnOff, &m_fExpand); DECL_OPTION("-ffunc-opt", CbFOnOff, [this](bool flag) { // m_fFuncSplitCat = flag; @@ -2351,9 +2354,7 @@ void V3Options::optimize(int level) { m_fConst = flag; m_fConstBitOpTree = flag; m_fDedupe = flag; - m_fDfgPreInline = flag; - m_fDfgPostInline = flag; - m_fDfgScoped = flag; + m_fDfg = flag; m_fDeadAssigns = flag; m_fDeadCells = flag; m_fExpand = flag; diff --git a/src/V3Options.h b/src/V3Options.h index bfe27f491..7e2e50f10 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -399,10 +399,8 @@ private: bool m_fDedupe; // main switch: -fno-dedupe: logic deduplication bool m_fDfgBreakCycles = true; // main switch: -fno-dfg-break-cycles bool m_fDfgPeephole = true; // main switch: -fno-dfg-peephole - bool m_fDfgPreInline; // main switch: -fno-dfg-pre-inline and -fno-dfg - bool m_fDfgPostInline; // main switch: -fno-dfg-post-inline and -fno-dfg bool m_fDfgPushDownSels = true; // main switch: -fno-dfg-push-down-sels - bool m_fDfgScoped; // main switch: -fno-dfg-scoped and -fno-dfg + bool m_fDfg; // main switch: -fno-dfg bool m_fDfgSynthesizeAll = false; // main switch: -fdfg-synthesize-all bool m_fDeadAssigns; // main switch: -fno-dead-assigns: remove dead assigns bool m_fDeadCells; // main switch: -fno-dead-cells: remove dead cells @@ -718,12 +716,10 @@ public: bool fConstBitOpTree() const { return m_fConstBitOpTree; } bool fConstEager() const { return m_fConstEager; } bool fDedupe() const { return m_fDedupe; } + bool fDfg() const { return m_fDfg; } bool fDfgBreakCycles() const { return m_fDfgBreakCycles; } bool fDfgPeephole() const { return m_fDfgPeephole; } - bool fDfgPreInline() const { return m_fDfgPreInline; } - bool fDfgPostInline() const { return m_fDfgPostInline; } bool fDfgPushDownSels() const { return m_fDfgPushDownSels; } - bool fDfgScoped() const { return m_fDfgScoped; } bool fDfgSynthesizeAll() const { return m_fDfgSynthesizeAll; } bool fDfgPeepholeEnabled(const std::string& name) const { return !m_fDfgPeepholeDisabled.count(name); diff --git a/src/Verilator.cpp b/src/Verilator.cpp index f0f21eaab..1e3e6fbb2 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -301,15 +301,8 @@ static void process() { v3Global.constRemoveXs(true); } - if (v3Global.opt.fDfgPreInline() || v3Global.opt.fDfgPostInline()) { - // If doing DFG optimization, extract some additional candidates - V3DfgOptimizer::extract(v3Global.rootp()); - } - - if (v3Global.opt.fDfgPreInline()) { - // Pre inline DFG optimization - V3DfgOptimizer::optimize(v3Global.rootp(), "pre inline"); - } + // If doing DFG optimization, extract some additional candidates + if (v3Global.opt.fDfg()) V3DfgOptimizer::extract(v3Global.rootp()); if (!(v3Global.opt.serializeOnly() && !v3Global.opt.flatten())) { // Module inlining @@ -323,15 +316,10 @@ static void process() { if (v3Global.opt.trace()) V3Interface::interfaceAll(v3Global.rootp()); - if (v3Global.opt.fDfgPostInline()) { - // Post inline DFG optimization - V3DfgOptimizer::optimize(v3Global.rootp(), "post inline"); - } - // --PRE-FLAT OPTIMIZATIONS------------------ // Initial const/dead to reduce work for ordering code - V3Const::constifyAll(v3Global.rootp()); + if (v3Global.opt.fConstBeforeDfg()) V3Const::constifyAll(v3Global.rootp()); v3Global.checkTree(); V3Dead::deadifyDTypes(v3Global.rootp()); @@ -349,7 +337,7 @@ static void process() { V3Inst::instAll(v3Global.rootp()); // Inst may have made lots of concats; fix them - V3Const::constifyAll(v3Global.rootp()); + if (v3Global.opt.fConstBeforeDfg()) V3Const::constifyAll(v3Global.rootp()); // Flatten hierarchy, creating a SCOPE for each module's usage as a cell // No more AstAlias after linkDotScope @@ -364,7 +352,7 @@ static void process() { if (!(v3Global.opt.serializeOnly() && !v3Global.opt.flatten())) { // Cleanup - V3Const::constifyAll(v3Global.rootp()); + if (v3Global.opt.fConstBeforeDfg()) V3Const::constifyAll(v3Global.rootp()); V3Dead::deadifyDTypesScoped(v3Global.rootp()); v3Global.checkTree(); } @@ -392,7 +380,7 @@ static void process() { V3Slice::sliceAll(v3Global.rootp()); // Push constants across variables and remove redundant assignments - V3Const::constifyAll(v3Global.rootp()); + if (v3Global.opt.fConstBeforeDfg()) V3Const::constifyAll(v3Global.rootp()); if (v3Global.opt.fLife()) V3Life::lifeAll(v3Global.rootp()); @@ -403,7 +391,7 @@ static void process() { } // Cleanup - V3Const::constifyAll(v3Global.rootp()); + if (v3Global.opt.fConstBeforeDfg()) V3Const::constifyAll(v3Global.rootp()); V3Dead::deadifyDTypesScoped(v3Global.rootp()); v3Global.checkTree(); @@ -423,10 +411,8 @@ static void process() { // forcing. V3Force::forceAll(v3Global.rootp()); - if (v3Global.opt.fDfgScoped()) { - // Scoped DFG optimization - V3DfgOptimizer::optimize(v3Global.rootp(), "scoped"); - } + // DFG optimization + if (v3Global.opt.fDfg()) V3DfgOptimizer::optimize(v3Global.rootp()); // Gate-based logic elimination; eliminate signals and push constant across cell // boundaries Instant propagation makes lots-o-constant reduction possibilities. diff --git a/test_regress/t/t_cover_line.out b/test_regress/t/t_cover_line.out index a826d835a..49338a4b6 100644 --- a/test_regress/t/t_cover_line.out +++ b/test_regress/t/t_cover_line.out @@ -465,9 +465,9 @@ +000010 point: type=line comment=block hier=top.t.cond1 endfunction -~000011 assign a = (cyc == 0) ? clk : 1'bz; +~000031 assign a = (cyc == 0) ? clk : 1'bz; -000000 point: type=branch comment=cond_then hier=top.t.cond1 -+000011 point: type=branch comment=cond_else hier=top.t.cond1 ++000031 point: type=branch comment=cond_else hier=top.t.cond1 ~000028 assign b = (cyc == 1) ? clk : 0; -000003 point: type=branch comment=cond_then hier=top.t.cond1 +000028 point: type=branch comment=cond_else hier=top.t.cond1 diff --git a/test_regress/t/t_cover_line_cc.info.out b/test_regress/t/t_cover_line_cc.info.out index 9c6059f0f..6a04c28bf 100644 --- a/test_regress/t/t_cover_line_cc.info.out +++ b/test_regress/t/t_cover_line_cc.info.out @@ -156,9 +156,9 @@ DA:325,1 DA:328,10 DA:329,10 DA:330,10 -DA:333,11 +DA:333,31 BRDA:333,0,0,0 -BRDA:333,0,1,11 +BRDA:333,0,1,31 DA:334,28 BRDA:334,0,0,3 BRDA:334,0,1,28 diff --git a/test_regress/t/t_dfg_bin_to_one_hot.py b/test_regress/t/t_dfg_bin_to_one_hot.py index 9eba4ddc2..463e646aa 100755 --- a/test_regress/t/t_dfg_bin_to_one_hot.py +++ b/test_regress/t/t_dfg_bin_to_one_hot.py @@ -11,11 +11,10 @@ import vltest_bootstrap test.scenarios('vlt') -test.compile(verilator_flags2=["--stats"]) +test.compile(verilator_flags2=["--stats", "-fno-table"]) test.execute() -test.file_grep(test.stats, r'Optimizations, DFG pre inline BinToOneHot, decoders created\s+(\d+)', - 4) +test.file_grep(test.stats, r'Optimizations, DFG, BinToOneHot, decoders created\s+(\d+)', 4) test.passes() diff --git a/test_regress/t/t_dfg_break_cycles.py b/test_regress/t/t_dfg_break_cycles.py index 583627873..4244fb3a6 100755 --- a/test_regress/t/t_dfg_break_cycles.py +++ b/test_regress/t/t_dfg_break_cycles.py @@ -80,8 +80,6 @@ test.file_grep(test.obj_dir + "/obj_ref/Vref__stats.txt", test.compile(verilator_flags2=[ "--stats", "--build", - "-fno-dfg-post-inline", - "-fno-dfg-scoped", "--exe", "+incdir+" + test.obj_dir, "-Mdir", test.obj_dir + "/obj_opt", diff --git a/test_regress/t/t_dfg_multidriver_dfg_bad.out b/test_regress/t/t_dfg_multidriver_dfg_bad.out index b7ccc6082..feec4ce32 100644 --- a/test_regress/t/t_dfg_multidriver_dfg_bad.out +++ b/test_regress/t/t_dfg_multidriver_dfg_bad.out @@ -1,5 +1,4 @@ -%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:45:16: Bit [1] of signal 'y' have multiple combinational drivers. This can cause performance degradation. - : ... note: In instance 't' +%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:45:16: Bit [1] of signal 't.y' have multiple combinational drivers. This can cause performance degradation. t/t_dfg_multidriver_dfg_bad.v:48:22: ... Location of offending driver 48 | {y[1:0], y[2:1]} = i[3:0] + 4'd5; | ^ @@ -8,88 +7,77 @@ | ^ ... For warning description see https://verilator.org/warn/MULTIDRIVEN?v=latest ... Use "/* verilator lint_off MULTIDRIVEN */" and lint_on around source to disable this message. -%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:16:16: Bits [3:1] of signal 'a' have multiple combinational drivers. This can cause performance degradation. - : ... note: In instance 't' +%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:16:16: Bits [3:1] of signal 't.a' have multiple combinational drivers. This can cause performance degradation. t/t_dfg_multidriver_dfg_bad.v:17:17: ... Location of offending driver 17 | assign a[3:0] = i[3:0]; | ^ t/t_dfg_multidriver_dfg_bad.v:18:17: ... Location of offending driver 18 | assign a[4:1] = ~i[4:1]; | ^ -%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:16:16: Bit [3] of signal 'a' have multiple combinational drivers. This can cause performance degradation. - : ... note: In instance 't' +%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:16:16: Bit [3] of signal 't.a' have multiple combinational drivers. This can cause performance degradation. t/t_dfg_multidriver_dfg_bad.v:17:17: ... Location of offending driver 17 | assign a[3:0] = i[3:0]; | ^ t/t_dfg_multidriver_dfg_bad.v:19:15: ... Location of offending driver 19 | assign a[3] = ~i[3]; | ^ -%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:16:16: Bits [7:6] of signal 'a' have multiple combinational drivers. This can cause performance degradation. - : ... note: In instance 't' +%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:16:16: Bits [7:6] of signal 't.a' have multiple combinational drivers. This can cause performance degradation. t/t_dfg_multidriver_dfg_bad.v:20:17: ... Location of offending driver 20 | assign a[8:5] = i[8:5]; | ^ t/t_dfg_multidriver_dfg_bad.v:21:17: ... Location of offending driver 21 | assign a[7:6] = ~i[7:6]; | ^ -%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:16:16: Bit [9] of signal 'a' have multiple combinational drivers. This can cause performance degradation. - : ... note: In instance 't' +%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:16:16: Bit [9] of signal 't.a' have multiple combinational drivers. This can cause performance degradation. t/t_dfg_multidriver_dfg_bad.v:22:15: ... Location of offending driver 22 | assign a[9] = i[9]; | ^ t/t_dfg_multidriver_dfg_bad.v:23:15: ... Location of offending driver 23 | assign a[9] = ~i[9]; | ^ -%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:26:16: Elements [3:0] of signal 'u' have multiple combinational drivers. This can cause performance degradation. - : ... note: In instance 't' +%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:26:16: Elements [3:0] of signal 't.u' have multiple combinational drivers. This can cause performance degradation. t/t_dfg_multidriver_dfg_bad.v:27:12: ... Location of offending driver 27 | assign u = j; | ^ t/t_dfg_multidriver_dfg_bad.v:28:12: ... Location of offending driver 28 | assign u = k; | ^ -%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:30:16: Element [1] of signal 'v' have multiple combinational drivers. This can cause performance degradation. - : ... note: In instance 't' +%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:30:16: Element [1] of signal 't.v' have multiple combinational drivers. This can cause performance degradation. t/t_dfg_multidriver_dfg_bad.v:31:12: ... Location of offending driver 31 | assign v = j; | ^ t/t_dfg_multidriver_dfg_bad.v:32:11: ... Location of offending driver 32 | assign v[1] = i; | ^ -%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:34:16: Element [0] of signal 'w' have multiple combinational drivers. This can cause performance degradation. - : ... note: In instance 't' +%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:34:16: Element [0] of signal 't.w' have multiple combinational drivers. This can cause performance degradation. t/t_dfg_multidriver_dfg_bad.v:35:11: ... Location of offending driver 35 | assign w[0] = i; | ^ t/t_dfg_multidriver_dfg_bad.v:36:12: ... Location of offending driver 36 | assign w = j; | ^ -%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:38:16: Bits [3:2] of signal 'x[3]' have multiple combinational drivers. This can cause performance degradation. - : ... note: In instance 't' +%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:38:16: Bits [3:2] of signal 't.x[3]' have multiple combinational drivers. This can cause performance degradation. t/t_dfg_multidriver_dfg_bad.v:39:15: ... Location of offending driver 39 | assign x[3] = i; | ^ t/t_dfg_multidriver_dfg_bad.v:40:20: ... Location of offending driver 40 | assign x[3][3:2] = ~i[1:0]; | ^ -%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:51:16: Bits [2:1] of signal 'z' have multiple combinational drivers. This can cause performance degradation. - : ... note: In instance 't' +%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:51:16: Bits [2:1] of signal 't.z' have multiple combinational drivers. This can cause performance degradation. t/t_dfg_multidriver_dfg_bad.v:53:12: ... Location of offending driver 53 | z[2:0] = i[2:0]; | ^ t/t_dfg_multidriver_dfg_bad.v:58:15: ... Location of offending driver 58 | z[3:1] = i[3:1]; | ^ -%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:51:16: Bits [6:5] of signal 'z' have multiple combinational drivers. This can cause performance degradation. - : ... note: In instance 't' +%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:51:16: Bits [6:5] of signal 't.z' have multiple combinational drivers. This can cause performance degradation. t/t_dfg_multidriver_dfg_bad.v:57:12: ... Location of offending driver 57 | z[6:4] = i[6:4]; | ^ t/t_dfg_multidriver_dfg_bad.v:54:12: ... Location of offending driver 54 | z[7:5] = i[7:5]; | ^ -%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:51:16: Bit [7] of signal 'z' have multiple combinational drivers. This can cause performance degradation. - : ... note: In instance 't' +%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:51:16: Bit [7] of signal 't.z' have multiple combinational drivers. This can cause performance degradation. t/t_dfg_multidriver_dfg_bad.v:54:12: ... Location of offending driver 54 | z[7:5] = i[7:5]; | ^ @@ -117,4 +105,7 @@ t/t_dfg_multidriver_dfg_bad.v:66:24: ... Location of offending driver 66 | assign sub_2.a[10:5] = i[10:5]; | ^ -%Error: Exiting due to +%Error: Internal Error: t/t_dfg_multidriver_dfg_bad.v:48:12: ../V3Gate.cpp:#: Concat on LHS of assignment; V3Const should have deleted it + 48 | {y[1:0], y[2:1]} = i[3:0] + 4'd5; + | ^ + ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. diff --git a/test_regress/t/t_dfg_oob_sel_rvalue.py b/test_regress/t/t_dfg_oob_sel_rvalue.py index 7c1ccefb2..76205c3f9 100755 --- a/test_regress/t/t_dfg_oob_sel_rvalue.py +++ b/test_regress/t/t_dfg_oob_sel_rvalue.py @@ -13,8 +13,7 @@ test.scenarios('vlt') test.compile(verilator_flags2=["--stats"]) -test.file_grep( - test.stats, - r'Optimizations, DFG scoped Synthesis, conv / non-representable \(oobsel\)\s+(\d+)', 1) +test.file_grep(test.stats, + r'Optimizations, DFG, Synthesis, conv / non-representable \(oobsel\)\s+(\d+)', 1) test.passes() diff --git a/test_regress/t/t_dfg_peephole.py b/test_regress/t/t_dfg_peephole.py index ba878f333..7b2461c00 100755 --- a/test_regress/t/t_dfg_peephole.py +++ b/test_regress/t/t_dfg_peephole.py @@ -106,7 +106,7 @@ test.compile(verilator_flags2=[ def check(name, enabled): name = name.lower() name = re.sub(r'_', ' ', name) - pattern = r'DFG\s+(pre inline|post inline|scoped) Peephole, ' + name + r'\s+([1-9]\d*)\s*$' + pattern = r'DFG, Peephole, ' + name + r'\s+([1-9]\d*)\s*$' if enabled: test.file_grep(test.obj_dir + "/obj_opt/Vopt__stats.txt", pattern) else: diff --git a/test_regress/t/t_dfg_push_sel.py b/test_regress/t/t_dfg_push_sel.py index 5e23ff9b3..f7e694cfd 100755 --- a/test_regress/t/t_dfg_push_sel.py +++ b/test_regress/t/t_dfg_push_sel.py @@ -11,16 +11,12 @@ import vltest_bootstrap test.scenarios('simulator_st') -test.compile(verilator_flags2=[ - "--binary", "--stats", "-fno-dfg-pre-inline", "-fno-dfg-post-inline", "-fno-dfg-peephole" -]) +test.compile(verilator_flags2=["--binary", "--stats", "-fno-dfg-peephole"]) test.execute() if test.vlt: - test.file_grep(test.stats, r'Optimizations, DFG scoped PushDownSels, sels pushed down\s+(\d+)', - 49) - test.file_grep(test.stats, r'Optimizations, DFG scoped PushDownSels, would be cyclic\s+(\d+)', - 1) + test.file_grep(test.stats, r'Optimizations, DFG, PushDownSels, sels pushed down\s+(\d+)', 49) + test.file_grep(test.stats, r'Optimizations, DFG, PushDownSels, would be cyclic\s+(\d+)', 1) test.passes() diff --git a/test_regress/t/t_dfg_push_sel_off.py b/test_regress/t/t_dfg_push_sel_off.py index 14b54340f..87a50d91c 100755 --- a/test_regress/t/t_dfg_push_sel_off.py +++ b/test_regress/t/t_dfg_push_sel_off.py @@ -13,17 +13,13 @@ test.scenarios('simulator_st') test.top_filename = "t/t_dfg_push_sel.v" -test.compile(verilator_flags2=[ - "--binary", "--stats", "-fno-dfg-pre-inline", "-fno-dfg-post-inline", "-fno-dfg-peephole", - "-fno-dfg-push-down-sels" -]) +test.compile( + verilator_flags2=["--binary", "--stats", "-fno-dfg-peephole", "-fno-dfg-push-down-sels"]) test.execute() if test.vlt: - test.file_grep(test.stats, r'Optimizations, DFG scoped PushDownSels, sels pushed down\s+(\d+)', - 0) - test.file_grep(test.stats, r'Optimizations, DFG scoped PushDownSels, would be cyclic\s+(\d+)', - 0) + test.file_grep(test.stats, r'Optimizations, DFG, PushDownSels, sels pushed down\s+(\d+)', 0) + test.file_grep(test.stats, r'Optimizations, DFG, PushDownSels, would be cyclic\s+(\d+)', 0) test.passes() diff --git a/test_regress/t/t_dfg_stats_patterns_scoped.out b/test_regress/t/t_dfg_stats_patterns.out similarity index 97% rename from test_regress/t/t_dfg_stats_patterns_scoped.out rename to test_regress/t/t_dfg_stats_patterns.out index dc86b18e2..dc228e88a 100644 --- a/test_regress/t/t_dfg_stats_patterns_scoped.out +++ b/test_regress/t/t_dfg_stats_patterns.out @@ -1,4 +1,4 @@ -DFG 'scoped' patterns with depth 1 +DFG patterns with depth 1 9 (CONCAT _A:1 _B:a):b 8 (REDXOR _A:a):1 3 (NOT vA:a)*:a @@ -16,7 +16,7 @@ DFG 'scoped' patterns with depth 1 1 (SEL@0 _A:a):b 1 (SEL@A _A:a):1 -DFG 'scoped' patterns with depth 2 +DFG patterns with depth 2 6 (CONCAT (REDXOR _A:a):1 (CONCAT _B:1 _C:b):c):d 2 (AND (NOT vA:a)*:a (NOT vB:a)*:a):a 2 (REDXOR (AND _A:a _B:a):a):1 @@ -42,7 +42,7 @@ DFG 'scoped' patterns with depth 2 1 (SEL@0 (REPLICATE _A:a cA:a)*:b):c 1 (SEL@A (AND _A:a _B:a)*:a):1 -DFG 'scoped' patterns with depth 3 +DFG patterns with depth 3 2 (REDXOR (AND (NOT vA:a)*:a (NOT vB:a)*:a):a):1 1 (CONCAT (REDXOR (AND _A:a _B:a)*:a):1 (CONCAT (REDXOR _C:a):1 (CONCAT _D:1 _E:b):c):d):e 1 (CONCAT (REDXOR (AND _A:a _B:a):a):1 (CONCAT (REDXOR _C:a):1 (CONCAT _D:1 _E:b):c):d):e @@ -71,7 +71,7 @@ DFG 'scoped' patterns with depth 3 1 (SEL@0 (REPLICATE (NOT _A:a):a cA:a)*:b):c 1 (SEL@A (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a):1 -DFG 'scoped' patterns with depth 4 +DFG patterns with depth 4 1 (CONCAT (REDXOR (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a):1 (CONCAT (REDXOR (AND _A:a _B:a):a):1 (CONCAT (REDXOR _C:a):1 (CONCAT _D:1 _E:b):c):d):e):f 1 (CONCAT (REDXOR (AND (NOT vA:a)*:a (NOT vB:a)*:a):a):1 (CONCAT (REDXOR (AND _A:a _B:a):a):1 (CONCAT (SEL@0 _C:a):1 (CONCAT _D:1 _E:b):c):d):e):f 1 (CONCAT (REDXOR (AND (NOT vA:a)*:a (NOT vB:a)*:a):a):1 (CONCAT (SEL@0 (AND _A:a _B:a)*:a):1 (CONCAT (REDXOR _C:b):1 (CONCAT _D:1 _E:c):d):e):b):f diff --git a/test_regress/t/t_dfg_stats_patterns_post_inline.py b/test_regress/t/t_dfg_stats_patterns.py similarity index 68% rename from test_regress/t/t_dfg_stats_patterns_post_inline.py rename to test_regress/t/t_dfg_stats_patterns.py index afe7bc2ca..858c7942e 100755 --- a/test_regress/t/t_dfg_stats_patterns_post_inline.py +++ b/test_regress/t/t_dfg_stats_patterns.py @@ -12,9 +12,9 @@ import vltest_bootstrap test.scenarios('vlt') test.top_filename = "t/t_dfg_stats_patterns.v" -test.compile(verilator_flags2=["--stats --no-skip-identical -fno-dfg-pre-inline -fno-dfg-scoped"]) +test.compile(verilator_flags2=["--stats --no-skip-identical"]) -fn = test.glob_one(test.obj_dir + "/" + test.vm_prefix + "__stats_dfg_patterns*") -test.files_identical(fn, test.golden_filename) +test.files_identical(test.obj_dir + "/" + test.vm_prefix + "__stats_dfg_patterns.txt", + test.golden_filename) test.passes() diff --git a/test_regress/t/t_dfg_stats_patterns_post_inline.out b/test_regress/t/t_dfg_stats_patterns_post_inline.out deleted file mode 100644 index 37d092dca..000000000 --- a/test_regress/t/t_dfg_stats_patterns_post_inline.out +++ /dev/null @@ -1,99 +0,0 @@ -DFG 'post inline' patterns with depth 1 - 9 (CONCAT _A:1 _B:a):b - 8 (REDXOR _A:a):1 - 4 (ASTRD vA:a):a - 3 (NOT vA:a)*:a - 2 (AND _A:a _B:a):a - 1 (AND _A:a _B:a)*:a - 1 (CONCAT _A:1 _B:1):a - 1 (NOT _A:a):a - 1 (REDXOR _A:a)*:1 - 1 (REPLICATE _A:1 cA:a)*:b - 1 (REPLICATE _A:a cA:a)*:b - 1 (REPLICATE _A:a cA:a):b - 1 (REPLICATE _A:a cA:b)*:b - 1 (REPLICATE _A:a cA:b)*:c - 1 (SEL@0 _A:a):1 - 1 (SEL@0 _A:a):b - 1 (SEL@A _A:a):1 - -DFG 'post inline' patterns with depth 2 - 6 (CONCAT (REDXOR _A:a):1 (CONCAT _B:1 _C:b):c):d - 2 (AND (NOT vA:a)*:a (NOT vB:a)*:a):a - 2 (REDXOR (AND _A:a _B:a):a):1 - 1 (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a - 1 (CONCAT (REDXOR _A:a)*:1 (CONCAT _B:1 _C:b):c):d - 1 (CONCAT (REDXOR _A:a):1 (CONCAT _B:1 _C:1):b):c - 1 (CONCAT (REDXOR _A:a):1 (REDXOR _B:b)*:1):c - 1 (CONCAT (SEL@0 _A:a):1 (CONCAT _B:1 _C:b):c):d - 1 (NOT (REPLICATE _A:a cA:b)*:b):b - 1 (REDXOR (AND _A:a _B:a)*:a):1 - 1 (REDXOR (REPLICATE _A:1 cA:a)*:b):1 - 1 (REDXOR (REPLICATE _A:a cA:a)*:b):1 - 1 (REDXOR (REPLICATE _A:a cA:a):b)*:1 - 1 (REDXOR (REPLICATE _A:a cA:b)*:b):1 - 1 (REDXOR (REPLICATE _A:a cA:b)*:c):1 - 1 (REDXOR (SEL@0 _A:a):b):1 - 1 (REPLICATE (NOT _A:a):a cA:a)*:b - 1 (REPLICATE (REPLICATE _A:1 cA:a)*:b cB:a)*:c - 1 (REPLICATE (REPLICATE _A:a cA:b)*:b cA:b):c - 1 (REPLICATE (REPLICATE _A:a cA:b)*:c cA:b)*:b - 1 (REPLICATE (SEL@A _A:a):1 cA:b)*:c - 1 (SEL@0 (AND _A:a _B:a)*:a):1 - 1 (SEL@0 (REPLICATE _A:a cA:a)*:b):c - 1 (SEL@A (AND _A:a _B:a)*:a):1 - -DFG 'post inline' patterns with depth 3 - 2 (REDXOR (AND (NOT vA:a)*:a (NOT vB:a)*:a):a):1 - 1 (CONCAT (REDXOR (AND _A:a _B:a)*:a):1 (CONCAT (REDXOR _C:a):1 (CONCAT _D:1 _E:b):c):d):e - 1 (CONCAT (REDXOR (AND _A:a _B:a):a):1 (CONCAT (REDXOR _C:a):1 (CONCAT _D:1 _E:b):c):d):e - 1 (CONCAT (REDXOR (AND _A:a _B:a):a):1 (CONCAT (SEL@0 _C:a):1 (CONCAT _D:1 _E:b):c):d):e - 1 (CONCAT (REDXOR (REPLICATE _A:1 cA:a)*:b):1 (CONCAT (REDXOR _B:c):1 (CONCAT _C:1 _D:d):e):f):g - 1 (CONCAT (REDXOR (REPLICATE _A:a cA:a)*:b):1 (CONCAT (REDXOR _B:c):1 (REDXOR _C:b)*:1):d):e - 1 (CONCAT (REDXOR (REPLICATE _A:a cA:a):b)*:1 (CONCAT (REDXOR _B:b):1 (CONCAT _C:1 _D:1):c):d):e - 1 (CONCAT (REDXOR (REPLICATE _A:a cA:b)*:b):1 (CONCAT (REDXOR _B:c)*:1 (CONCAT _C:1 _D:d):e):f):g - 1 (CONCAT (REDXOR (REPLICATE _A:a cA:b)*:c):1 (CONCAT (REDXOR _B:b):1 (CONCAT _C:1 _D:d):e):f):g - 1 (CONCAT (REDXOR (SEL@0 _A:a):b):1 (REDXOR (REPLICATE _B:c cA:c):a)*:1):d - 1 (CONCAT (SEL@0 (AND _A:a _B:a)*:a):1 (CONCAT (REDXOR _C:b):1 (CONCAT _D:1 _E:c):d):e):b - 1 (NOT (REPLICATE (REPLICATE _A:a cA:b)*:c cA:b)*:b):b - 1 (REDXOR (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a):1 - 1 (REDXOR (REPLICATE (NOT _A:a):a cA:a)*:b):1 - 1 (REDXOR (REPLICATE (REPLICATE _A:1 cA:a)*:b cB:a)*:c):1 - 1 (REDXOR (REPLICATE (REPLICATE _A:a cA:b)*:b cA:b):c)*:1 - 1 (REDXOR (REPLICATE (REPLICATE _A:a cA:b)*:c cA:b)*:b):1 - 1 (REDXOR (REPLICATE (SEL@A _A:a):1 cA:b)*:c):1 - 1 (REDXOR (SEL@0 (REPLICATE _A:a cA:a)*:b):c):1 - 1 (REPLICATE (NOT (REPLICATE _A:a cA:b)*:b):b cA:b)*:c - 1 (REPLICATE (REPLICATE (REPLICATE _A:1 cA:a)*:b cB:a)*:c cB:a)*:a - 1 (REPLICATE (REPLICATE (REPLICATE _A:a cA:b)*:c cA:b)*:b cA:b):d - 1 (REPLICATE (REPLICATE (SEL@A _A:a):1 cA:b)*:c cB:b)*:d - 1 (REPLICATE (SEL@A (AND _A:a _B:a)*:a):1 cA:b)*:c - 1 (SEL@0 (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a):1 - 1 (SEL@0 (REPLICATE (NOT _A:a):a cA:a)*:b):c - 1 (SEL@A (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a):1 - -DFG 'post inline' patterns with depth 4 - 1 (CONCAT (REDXOR (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a):1 (CONCAT (REDXOR (AND _A:a _B:a):a):1 (CONCAT (REDXOR _C:a):1 (CONCAT _D:1 _E:b):c):d):e):f - 1 (CONCAT (REDXOR (AND (NOT vA:a)*:a (NOT vB:a)*:a):a):1 (CONCAT (REDXOR (AND _A:a _B:a):a):1 (CONCAT (SEL@0 _C:a):1 (CONCAT _D:1 _E:b):c):d):e):f - 1 (CONCAT (REDXOR (AND (NOT vA:a)*:a (NOT vB:a)*:a):a):1 (CONCAT (SEL@0 (AND _A:a _B:a)*:a):1 (CONCAT (REDXOR _C:b):1 (CONCAT _D:1 _E:c):d):e):b):f - 1 (CONCAT (REDXOR (REPLICATE (NOT _A:a):a cA:a)*:b):1 (CONCAT (REDXOR (SEL@0 _B:b):c):1 (REDXOR (REPLICATE _A:a cA:a):b)*:1):d):e - 1 (CONCAT (REDXOR (REPLICATE (REPLICATE _A:1 cA:a)*:b cB:a)*:c):1 (CONCAT (REDXOR (REPLICATE _B:c cB:a)*:a):1 (CONCAT (REDXOR _C:d)*:1 (CONCAT _D:1 _E:e):f):g):h):i - 1 (CONCAT (REDXOR (REPLICATE (REPLICATE _A:a cA:b)*:b cA:b):c)*:1 (CONCAT (REDXOR (REPLICATE _B:b cA:b)*:c):1 (CONCAT (REDXOR _C:d):1 (REDXOR _D:c)*:1):e):f):g - 1 (CONCAT (REDXOR (REPLICATE (REPLICATE _A:a cA:b)*:c cA:b)*:b):1 (CONCAT (REDXOR (REPLICATE _B:b cA:b):d)*:1 (CONCAT (REDXOR _C:d):1 (CONCAT _D:1 _E:1):e):f):g):h - 1 (CONCAT (REDXOR (REPLICATE (SEL@A _A:a):1 cA:b)*:c):1 (CONCAT (REDXOR (REPLICATE _B:c cB:b)*:d):1 (CONCAT (REDXOR _C:b):1 (CONCAT _D:1 _E:e):a):f):g):h - 1 (CONCAT (REDXOR (SEL@0 (REPLICATE _A:a cA:a)*:b):c):1 (REDXOR (REPLICATE (REPLICATE _B:d cA:a)*:a cA:a):b)*:1):e - 1 (CONCAT (SEL@0 (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a):1 (CONCAT (REDXOR (REPLICATE _A:1 cA:b)*:c):1 (CONCAT (REDXOR _B:d):1 (CONCAT _C:1 _D:a):e):f):g):c - 1 (NOT (REPLICATE (REPLICATE (REPLICATE _A:1 cA:a)*:b cB:a)*:c cB:a)*:a):a - 1 (REDXOR (REPLICATE (NOT (REPLICATE _A:a cA:b)*:b):b cA:b)*:c):1 - 1 (REDXOR (REPLICATE (REPLICATE (REPLICATE _A:1 cA:a)*:b cB:a)*:c cB:a)*:a):1 - 1 (REDXOR (REPLICATE (REPLICATE (REPLICATE _A:a cA:b)*:c cA:b)*:b cA:b):d)*:1 - 1 (REDXOR (REPLICATE (REPLICATE (SEL@A _A:a):1 cA:b)*:c cB:b)*:d):1 - 1 (REDXOR (REPLICATE (SEL@A (AND _A:a _B:a)*:a):1 cA:b)*:c):1 - 1 (REDXOR (SEL@0 (REPLICATE (NOT _A:a):a cA:a)*:b):c):1 - 1 (REPLICATE (NOT (REPLICATE (REPLICATE _A:a cA:b)*:c cA:b)*:b):b cA:b)*:d - 1 (REPLICATE (REPLICATE (REPLICATE (REPLICATE _A:1 cA:a)*:b cB:a)*:c cB:a)*:a cB:a):d - 1 (REPLICATE (REPLICATE (REPLICATE (SEL@A _A:a):1 cA:b)*:c cB:b)*:d cB:b)*:b - 1 (REPLICATE (REPLICATE (SEL@A (AND _A:a _B:a)*:a):1 cA:b)*:c cB:b)*:d - 1 (REPLICATE (SEL@A (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a):1 cA:b)*:c - 1 (SEL@0 (REPLICATE (NOT (REPLICATE _A:a cA:b)*:b):b cA:b)*:c):d - diff --git a/test_regress/t/t_dfg_stats_patterns_pre_inline.out b/test_regress/t/t_dfg_stats_patterns_pre_inline.out deleted file mode 100644 index f7b216e9b..000000000 --- a/test_regress/t/t_dfg_stats_patterns_pre_inline.out +++ /dev/null @@ -1,98 +0,0 @@ -DFG 'pre inline' patterns with depth 1 - 9 (CONCAT _A:1 _B:a):b - 8 (REDXOR _A:a):1 - 3 (NOT vA:a)*:a - 2 (AND _A:a _B:a):a - 1 (AND _A:a _B:a)*:a - 1 (CONCAT _A:1 _B:1):a - 1 (NOT _A:a):a - 1 (REDXOR _A:a)*:1 - 1 (REPLICATE _A:1 cA:a)*:b - 1 (REPLICATE _A:a cA:a)*:b - 1 (REPLICATE _A:a cA:a):b - 1 (REPLICATE _A:a cA:b)*:b - 1 (REPLICATE _A:a cA:b)*:c - 1 (SEL@0 _A:a):1 - 1 (SEL@0 _A:a):b - 1 (SEL@A _A:a):1 - -DFG 'pre inline' patterns with depth 2 - 6 (CONCAT (REDXOR _A:a):1 (CONCAT _B:1 _C:b):c):d - 2 (AND (NOT vA:a)*:a (NOT vB:a)*:a):a - 2 (REDXOR (AND _A:a _B:a):a):1 - 1 (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a - 1 (CONCAT (REDXOR _A:a)*:1 (CONCAT _B:1 _C:b):c):d - 1 (CONCAT (REDXOR _A:a):1 (CONCAT _B:1 _C:1):b):c - 1 (CONCAT (REDXOR _A:a):1 (REDXOR _B:b)*:1):c - 1 (CONCAT (SEL@0 _A:a):1 (CONCAT _B:1 _C:b):c):d - 1 (NOT (REPLICATE _A:a cA:b)*:b):b - 1 (REDXOR (AND _A:a _B:a)*:a):1 - 1 (REDXOR (REPLICATE _A:1 cA:a)*:b):1 - 1 (REDXOR (REPLICATE _A:a cA:a)*:b):1 - 1 (REDXOR (REPLICATE _A:a cA:a):b)*:1 - 1 (REDXOR (REPLICATE _A:a cA:b)*:b):1 - 1 (REDXOR (REPLICATE _A:a cA:b)*:c):1 - 1 (REDXOR (SEL@0 _A:a):b):1 - 1 (REPLICATE (NOT _A:a):a cA:a)*:b - 1 (REPLICATE (REPLICATE _A:1 cA:a)*:b cB:a)*:c - 1 (REPLICATE (REPLICATE _A:a cA:b)*:b cA:b):c - 1 (REPLICATE (REPLICATE _A:a cA:b)*:c cA:b)*:b - 1 (REPLICATE (SEL@A _A:a):1 cA:b)*:c - 1 (SEL@0 (AND _A:a _B:a)*:a):1 - 1 (SEL@0 (REPLICATE _A:a cA:a)*:b):c - 1 (SEL@A (AND _A:a _B:a)*:a):1 - -DFG 'pre inline' patterns with depth 3 - 2 (REDXOR (AND (NOT vA:a)*:a (NOT vB:a)*:a):a):1 - 1 (CONCAT (REDXOR (AND _A:a _B:a)*:a):1 (CONCAT (REDXOR _C:a):1 (CONCAT _D:1 _E:b):c):d):e - 1 (CONCAT (REDXOR (AND _A:a _B:a):a):1 (CONCAT (REDXOR _C:a):1 (CONCAT _D:1 _E:b):c):d):e - 1 (CONCAT (REDXOR (AND _A:a _B:a):a):1 (CONCAT (SEL@0 _C:a):1 (CONCAT _D:1 _E:b):c):d):e - 1 (CONCAT (REDXOR (REPLICATE _A:1 cA:a)*:b):1 (CONCAT (REDXOR _B:c):1 (CONCAT _C:1 _D:d):e):f):g - 1 (CONCAT (REDXOR (REPLICATE _A:a cA:a)*:b):1 (CONCAT (REDXOR _B:c):1 (REDXOR _C:b)*:1):d):e - 1 (CONCAT (REDXOR (REPLICATE _A:a cA:a):b)*:1 (CONCAT (REDXOR _B:b):1 (CONCAT _C:1 _D:1):c):d):e - 1 (CONCAT (REDXOR (REPLICATE _A:a cA:b)*:b):1 (CONCAT (REDXOR _B:c)*:1 (CONCAT _C:1 _D:d):e):f):g - 1 (CONCAT (REDXOR (REPLICATE _A:a cA:b)*:c):1 (CONCAT (REDXOR _B:b):1 (CONCAT _C:1 _D:d):e):f):g - 1 (CONCAT (REDXOR (SEL@0 _A:a):b):1 (REDXOR (REPLICATE _B:c cA:c):a)*:1):d - 1 (CONCAT (SEL@0 (AND _A:a _B:a)*:a):1 (CONCAT (REDXOR _C:b):1 (CONCAT _D:1 _E:c):d):e):b - 1 (NOT (REPLICATE (REPLICATE _A:a cA:b)*:c cA:b)*:b):b - 1 (REDXOR (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a):1 - 1 (REDXOR (REPLICATE (NOT _A:a):a cA:a)*:b):1 - 1 (REDXOR (REPLICATE (REPLICATE _A:1 cA:a)*:b cB:a)*:c):1 - 1 (REDXOR (REPLICATE (REPLICATE _A:a cA:b)*:b cA:b):c)*:1 - 1 (REDXOR (REPLICATE (REPLICATE _A:a cA:b)*:c cA:b)*:b):1 - 1 (REDXOR (REPLICATE (SEL@A _A:a):1 cA:b)*:c):1 - 1 (REDXOR (SEL@0 (REPLICATE _A:a cA:a)*:b):c):1 - 1 (REPLICATE (NOT (REPLICATE _A:a cA:b)*:b):b cA:b)*:c - 1 (REPLICATE (REPLICATE (REPLICATE _A:1 cA:a)*:b cB:a)*:c cB:a)*:a - 1 (REPLICATE (REPLICATE (REPLICATE _A:a cA:b)*:c cA:b)*:b cA:b):d - 1 (REPLICATE (REPLICATE (SEL@A _A:a):1 cA:b)*:c cB:b)*:d - 1 (REPLICATE (SEL@A (AND _A:a _B:a)*:a):1 cA:b)*:c - 1 (SEL@0 (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a):1 - 1 (SEL@0 (REPLICATE (NOT _A:a):a cA:a)*:b):c - 1 (SEL@A (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a):1 - -DFG 'pre inline' patterns with depth 4 - 1 (CONCAT (REDXOR (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a):1 (CONCAT (REDXOR (AND _A:a _B:a):a):1 (CONCAT (REDXOR _C:a):1 (CONCAT _D:1 _E:b):c):d):e):f - 1 (CONCAT (REDXOR (AND (NOT vA:a)*:a (NOT vB:a)*:a):a):1 (CONCAT (REDXOR (AND _A:a _B:a):a):1 (CONCAT (SEL@0 _C:a):1 (CONCAT _D:1 _E:b):c):d):e):f - 1 (CONCAT (REDXOR (AND (NOT vA:a)*:a (NOT vB:a)*:a):a):1 (CONCAT (SEL@0 (AND _A:a _B:a)*:a):1 (CONCAT (REDXOR _C:b):1 (CONCAT _D:1 _E:c):d):e):b):f - 1 (CONCAT (REDXOR (REPLICATE (NOT _A:a):a cA:a)*:b):1 (CONCAT (REDXOR (SEL@0 _B:b):c):1 (REDXOR (REPLICATE _A:a cA:a):b)*:1):d):e - 1 (CONCAT (REDXOR (REPLICATE (REPLICATE _A:1 cA:a)*:b cB:a)*:c):1 (CONCAT (REDXOR (REPLICATE _B:c cB:a)*:a):1 (CONCAT (REDXOR _C:d)*:1 (CONCAT _D:1 _E:e):f):g):h):i - 1 (CONCAT (REDXOR (REPLICATE (REPLICATE _A:a cA:b)*:b cA:b):c)*:1 (CONCAT (REDXOR (REPLICATE _B:b cA:b)*:c):1 (CONCAT (REDXOR _C:d):1 (REDXOR _D:c)*:1):e):f):g - 1 (CONCAT (REDXOR (REPLICATE (REPLICATE _A:a cA:b)*:c cA:b)*:b):1 (CONCAT (REDXOR (REPLICATE _B:b cA:b):d)*:1 (CONCAT (REDXOR _C:d):1 (CONCAT _D:1 _E:1):e):f):g):h - 1 (CONCAT (REDXOR (REPLICATE (SEL@A _A:a):1 cA:b)*:c):1 (CONCAT (REDXOR (REPLICATE _B:c cB:b)*:d):1 (CONCAT (REDXOR _C:b):1 (CONCAT _D:1 _E:e):a):f):g):h - 1 (CONCAT (REDXOR (SEL@0 (REPLICATE _A:a cA:a)*:b):c):1 (REDXOR (REPLICATE (REPLICATE _B:d cA:a)*:a cA:a):b)*:1):e - 1 (CONCAT (SEL@0 (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a):1 (CONCAT (REDXOR (REPLICATE _A:1 cA:b)*:c):1 (CONCAT (REDXOR _B:d):1 (CONCAT _C:1 _D:a):e):f):g):c - 1 (NOT (REPLICATE (REPLICATE (REPLICATE _A:1 cA:a)*:b cB:a)*:c cB:a)*:a):a - 1 (REDXOR (REPLICATE (NOT (REPLICATE _A:a cA:b)*:b):b cA:b)*:c):1 - 1 (REDXOR (REPLICATE (REPLICATE (REPLICATE _A:1 cA:a)*:b cB:a)*:c cB:a)*:a):1 - 1 (REDXOR (REPLICATE (REPLICATE (REPLICATE _A:a cA:b)*:c cA:b)*:b cA:b):d)*:1 - 1 (REDXOR (REPLICATE (REPLICATE (SEL@A _A:a):1 cA:b)*:c cB:b)*:d):1 - 1 (REDXOR (REPLICATE (SEL@A (AND _A:a _B:a)*:a):1 cA:b)*:c):1 - 1 (REDXOR (SEL@0 (REPLICATE (NOT _A:a):a cA:a)*:b):c):1 - 1 (REPLICATE (NOT (REPLICATE (REPLICATE _A:a cA:b)*:c cA:b)*:b):b cA:b)*:d - 1 (REPLICATE (REPLICATE (REPLICATE (REPLICATE _A:1 cA:a)*:b cB:a)*:c cB:a)*:a cB:a):d - 1 (REPLICATE (REPLICATE (REPLICATE (SEL@A _A:a):1 cA:b)*:c cB:b)*:d cB:b)*:b - 1 (REPLICATE (REPLICATE (SEL@A (AND _A:a _B:a)*:a):1 cA:b)*:c cB:b)*:d - 1 (REPLICATE (SEL@A (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a):1 cA:b)*:c - 1 (SEL@0 (REPLICATE (NOT (REPLICATE _A:a cA:b)*:b):b cA:b)*:c):d - diff --git a/test_regress/t/t_dfg_stats_patterns_pre_inline.py b/test_regress/t/t_dfg_stats_patterns_pre_inline.py deleted file mode 100755 index c5d54600c..000000000 --- a/test_regress/t/t_dfg_stats_patterns_pre_inline.py +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env python3 -# DESCRIPTION: Verilator: Verilog Test driver/expect definition -# -# 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-FileCopyrightText: 2024 Wilson Snyder -# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 - -import vltest_bootstrap - -test.scenarios('vlt') -test.top_filename = "t/t_dfg_stats_patterns.v" - -test.compile(verilator_flags2=["--stats --no-skip-identical -fno-dfg-post-inline -fno-dfg-scoped"]) - -fn = test.glob_one(test.obj_dir + "/" + test.vm_prefix + "__stats_dfg_patterns*") -test.files_identical(fn, test.golden_filename) - -test.passes() diff --git a/test_regress/t/t_dfg_stats_patterns_scoped.py b/test_regress/t/t_dfg_stats_patterns_scoped.py deleted file mode 100755 index a191c01ea..000000000 --- a/test_regress/t/t_dfg_stats_patterns_scoped.py +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env python3 -# DESCRIPTION: Verilator: Verilog Test driver/expect definition -# -# 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-FileCopyrightText: 2024 Wilson Snyder -# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 - -import vltest_bootstrap - -test.scenarios('vlt') -test.top_filename = "t/t_dfg_stats_patterns.v" - -test.compile( - verilator_flags2=["--stats --no-skip-identical -fno-dfg-pre-inline -fno-dfg-post-inline"]) - -fn = test.glob_one(test.obj_dir + "/" + test.vm_prefix + "__stats_dfg_patterns*") -test.files_identical(fn, test.golden_filename) - -test.passes() diff --git a/test_regress/t/t_dfg_synthesis.py b/test_regress/t/t_dfg_synthesis.py index 1fafff18e..bad50c846 100755 --- a/test_regress/t/t_dfg_synthesis.py +++ b/test_regress/t/t_dfg_synthesis.py @@ -70,13 +70,10 @@ test.compile(verilator_flags2=[ "--stats", "--build", "--fdfg-synthesize-all", - "-fno-dfg-pre-inline", - "-fno-dfg-post-inline", "--exe", "+incdir+" + test.obj_dir, "-Mdir", test.obj_dir + "/obj_opt", "--prefix", "Vopt", - "-fno-const-before-dfg", # Otherwise V3Const makes testing painful "-fno-split", # Dfg will take care of it "--debug", "--debugi", "0", "--dumpi-tree", "0", "-CFLAGS \"-I .. -I ../obj_ref\"", @@ -85,13 +82,13 @@ test.compile(verilator_flags2=[ ]) # yapf:disable test.file_grep(test.obj_dir + "/obj_opt/Vopt__stats.txt", - r'DFG scoped Synthesis, synt / always blocks considered\s+(\d+)$', + r'DFG, Synthesis, synt / always blocks considered\s+(\d+)$', nAlwaysSynthesized + nAlwaysReverted + nAlwaysNotSynthesized) test.file_grep(test.obj_dir + "/obj_opt/Vopt__stats.txt", - r'DFG scoped Synthesis, synt / always blocks synthesized\s+(\d+)$', + r'DFG, Synthesis, synt / always blocks synthesized\s+(\d+)$', nAlwaysSynthesized + nAlwaysReverted) test.file_grep(test.obj_dir + "/obj_opt/Vopt__stats.txt", - r'DFG scoped Synthesis, synt / reverted \(multidrive\)\s+(\d)$', nAlwaysReverted) + r'DFG, Synthesis, synt / reverted \(multidrive\)\s+(\d)$', nAlwaysReverted) # Execute test to check equivalence test.execute(executable=test.obj_dir + "/obj_opt/Vopt") diff --git a/test_regress/t/t_dfg_synthesis_pre_inline.cpp b/test_regress/t/t_dfg_synthesis_pre_inline.cpp deleted file mode 100644 index d8bffdbaf..000000000 --- a/test_regress/t/t_dfg_synthesis_pre_inline.cpp +++ /dev/null @@ -1,60 +0,0 @@ -// -// DESCRIPTION: Verilator: DFG optimizer equivalence testing -// -// This file ONLY is placed under the Creative Commons Public Domain. -// SPDX-FileCopyrightText: 2022 Geza Lore -// SPDX-License-Identifier: CC0-1.0 -// - -#include -#include - -#include -#include -#include - -void rngUpdate(uint64_t& x) { - x ^= x << 13; - x ^= x >> 7; - x ^= x << 17; -} - -int main(int, char**) { - // Create contexts - VerilatedContext ctx; - - // Create models - Vref ref{&ctx}; - Vopt opt{&ctx}; - - uint64_t rand_a = 0x5aef0c8dd70a4497; - uint64_t rand_b = 0xf0c0a8dd75ae4497; - uint64_t srand_a = 0x00fa8dcc7ae4957; - uint64_t srand_b = 0x0fa8dc7ae3c9574; - - for (size_t n = 0; n < 200000; ++n) { - // Update rngs - rngUpdate(rand_a); - rngUpdate(rand_b); - rngUpdate(srand_a); - rngUpdate(srand_b); - - // Assign inputs - ref.rand_a = opt.rand_a = rand_a; - ref.rand_b = opt.rand_b = rand_b; - ref.srand_a = opt.srand_a = srand_a; - ref.srand_b = opt.srand_b = srand_b; - - // Evaluate both models - ref.eval(); - opt.eval(); - - // Check equivalence -#include "checks.h" - - // increment time - ctx.timeInc(1); - } - - std::cout << "*-* All Finished *-*\n"; -} diff --git a/test_regress/t/t_dfg_synthesis_pre_inline.py b/test_regress/t/t_dfg_synthesis_pre_inline.py deleted file mode 100755 index 7636b80f9..000000000 --- a/test_regress/t/t_dfg_synthesis_pre_inline.py +++ /dev/null @@ -1,98 +0,0 @@ -#!/usr/bin/env python3 -# DESCRIPTION: Verilator: Verilog Test driver/expect definition -# -# 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-FileCopyrightText: 2025 Wilson Snyder -# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 - -import vltest_bootstrap - -test.scenarios('vlt_all') -test.sim_time = 2000000 - -if not os.path.exists(test.root + "/.git"): - test.skip("Not in a git repository") - -# Generate the equivalence checks and declaration boilerplate -rdFile = test.top_filename -plistFile = test.obj_dir + "/portlist.vh" -pdeclFile = test.obj_dir + "/portdecl.vh" -checkFile = test.obj_dir + "/checks.h" -nAlwaysSynthesized = 0 -nAlwaysNotSynthesized = 0 -nAlwaysReverted = 0 -with open(rdFile, 'r', encoding="utf8") as rdFh, \ - open(plistFile, 'w', encoding="utf8") as plistFh, \ - open(pdeclFile, 'w', encoding="utf8") as pdeclFh, \ - open(checkFile, 'w', encoding="utf8") as checkFh: - for line in rdFh: - if re.search(r'^\s*always.*//\s*nosynth$', line): - nAlwaysNotSynthesized += 1 - elif re.search(r'^\s*always.*//\s*revert$', line): - nAlwaysReverted += 1 - elif re.search(r'^\s*always', line): - nAlwaysSynthesized += 1 - line = line.split("//")[0] - m = re.search(r'`signal\((\w+),', line) - if not m: - continue - sig = m.group(1) - plistFh.write(sig + ",\n") - pdeclFh.write("output " + sig + ";\n") - checkFh.write("if (ref." + sig + " != opt." + sig + ") {\n") - checkFh.write(" std::cout << \"Mismatched " + sig + "\" << std::endl;\n") - checkFh.write(" std::cout << \"Ref: 0x\" << std::hex << (ref." + sig + - " + 0) << std::endl;\n") - checkFh.write(" std::cout << \"Opt: 0x\" << std::hex << (opt." + sig + - " + 0) << std::endl;\n") - checkFh.write(" std::exit(1);\n") - checkFh.write("}\n") - -# Compile un-optimized -test.compile(verilator_flags2=[ - "--stats", - "--build", - "-fno-dfg", - "+incdir+" + test.obj_dir, - "-Mdir", test.obj_dir + "/obj_ref", - "--prefix", "Vref", - "-Wno-UNOPTFLAT" -]) # yapf:disable - -test.file_grep_not(test.obj_dir + "/obj_ref/Vref__stats.txt", r'DFG.*Synthesis') - -# Compile optimized - also builds executable -test.compile(verilator_flags2=[ - "--stats", - "--build", - "--fdfg-synthesize-all", - "-fno-dfg-post-inline", - "-fno-dfg-scoped", - "--exe", - "+incdir+" + test.obj_dir, - "-Mdir", test.obj_dir + "/obj_opt", - "--prefix", "Vopt", - "-fno-const-before-dfg", # Otherwise V3Const makes testing painful - "-fno-split", # Dfg will take care of it - "--debug", "--debugi", "0", "--dumpi-tree", "0", - "-CFLAGS \"-I .. -I ../obj_ref\"", - "../obj_ref/Vref__ALL.a", - "../../t/" + test.name + ".cpp" -]) # yapf:disable - -test.file_grep(test.obj_dir + "/obj_opt/Vopt__stats.txt", - r'DFG pre inline Synthesis, synt / always blocks considered\s+(\d+)$', - nAlwaysSynthesized + nAlwaysReverted + nAlwaysNotSynthesized) -test.file_grep(test.obj_dir + "/obj_opt/Vopt__stats.txt", - r'DFG pre inline Synthesis, synt / always blocks synthesized\s+(\d+)$', - nAlwaysSynthesized + nAlwaysReverted) -test.file_grep(test.obj_dir + "/obj_opt/Vopt__stats.txt", - r'DFG pre inline Synthesis, synt / reverted \(multidrive\)\s+(\d)$', - nAlwaysReverted) - -# Execute test to check equivalence -test.execute(executable=test.obj_dir + "/obj_opt/Vopt") - -test.passes() diff --git a/test_regress/t/t_dfg_synthesis_pre_inline.v b/test_regress/t/t_dfg_synthesis_pre_inline.v deleted file mode 100644 index 3bd47ef87..000000000 --- a/test_regress/t/t_dfg_synthesis_pre_inline.v +++ /dev/null @@ -1,34 +0,0 @@ -// DESCRIPTION: Verilator: Verilog Test module -// -// This file ONLY is placed under the Creative Commons Public Domain. -// SPDX-FileCopyrightText: 2025 Geza Lore -// SPDX-License-Identifier: CC0-1.0 - -`define signal(name, expr) wire [$bits(expr)-1:0] ``name = expr - -module t ( -`include "portlist.vh" // Boilerplate generated by t_dfg_break_cycles.py - rand_a, rand_b, srand_a, srand_b -); - -`include "portdecl.vh" // Boilerplate generated by t_dfg_break_cycles.py - - input rand_a; - input rand_b; - input srand_a; - input srand_b; - wire logic [63:0] rand_a; - wire logic [63:0] rand_b; - wire logic signed [63:0] srand_a; - wire logic signed [63:0] srand_b; - - ////////////////////////////////////////////////////////////////////////// - - logic concat_lhs_a; - logic concat_lhs_b; - always_comb begin - {concat_lhs_a, concat_lhs_b} = rand_a[1:0] + rand_b[1:0]; - end - `signal(CONCAT_LHS, {concat_lhs_a, concat_lhs_b}); - -endmodule diff --git a/test_regress/t/t_dfg_true_cycle_bad.out b/test_regress/t/t_dfg_true_cycle_bad.out index ca504772f..14cea0dd8 100644 --- a/test_regress/t/t_dfg_true_cycle_bad.out +++ b/test_regress/t/t_dfg_true_cycle_bad.out @@ -4,6 +4,6 @@ ... For warning description see https://verilator.org/warn/UNOPTFLAT?v=latest ... Use "/* verilator lint_off UNOPTFLAT */" and lint_on around source to disable this message. t/t_dfg_true_cycle_bad.v:10:23: Example path: o - t/t_dfg_true_cycle_bad.v:12:20: Example path: ASSIGNW + t/t_dfg_true_cycle_bad.v:12:17: Example path: ASSIGNW t/t_dfg_true_cycle_bad.v:10:23: Example path: o %Error: Exiting due to diff --git a/test_regress/t/t_flag_deprecated_bad.out b/test_regress/t/t_flag_deprecated_bad.out index cc4d3ff01..50206313e 100644 --- a/test_regress/t/t_flag_deprecated_bad.out +++ b/test_regress/t/t_flag_deprecated_bad.out @@ -4,4 +4,7 @@ %Warning-DEPRECATED: Option order-clock-delay is deprecated and has no effect. %Warning-DEPRECATED: Option '--clk' is deprecated and has no effect. %Warning-DEPRECATED: Option '--no-clk' is deprecated and has no effect. +%Warning-DEPRECATED: Option '-fno-dfg-pre-inline' is deprecated and has no effect +%Warning-DEPRECATED: Option '-fno-dfg-post-inline' is deprecated and has no effect +%Warning-DEPRECATED: Option '-fno-dfg-scoped' is deprecated, use '-fno-dfg' instead. %Error: Exiting due to diff --git a/test_regress/t/t_flag_deprecated_bad.py b/test_regress/t/t_flag_deprecated_bad.py index 8b192c851..48fd92091 100755 --- a/test_regress/t/t_flag_deprecated_bad.py +++ b/test_regress/t/t_flag_deprecated_bad.py @@ -11,7 +11,9 @@ import vltest_bootstrap test.scenarios('vlt') -test.lint(verilator_flags2=["--trace-fst-thread --order-clock-delay --clk foo --no-clk bar"], +test.lint(verilator_flags2=[ + "--trace-fst-thread --order-clock-delay --clk foo --no-clk bar -fno-dfg-pre-inline -fno-dfg-post-inline -fno-dfg-scoped" +], fails=True, expect_filename=test.golden_filename) diff --git a/test_regress/t/t_inst_tree_inl1_pub0.py b/test_regress/t/t_inst_tree_inl1_pub0.py index 488ba092e..443c7b9b1 100755 --- a/test_regress/t/t_inst_tree_inl1_pub0.py +++ b/test_regress/t/t_inst_tree_inl1_pub0.py @@ -14,10 +14,8 @@ test.top_filename = "t/t_inst_tree.v" out_filename = test.obj_dir + "/V" + test.name + ".tree.json" -test.compile(v_flags2=[ - "--no-json-edit-nums", "-fno-dfg-post-inline", "-fno-dfg-scoped", test.t_dir + - "/t_inst_tree_inl1_pub0.vlt" -]) +test.compile( + v_flags2=["--no-json-edit-nums", "-fno-dfg", test.t_dir + "/t_inst_tree_inl1_pub0.vlt"]) if test.vlt_all: test.file_grep( diff --git a/test_regress/t/t_inst_tree_inl1_pub1.py b/test_regress/t/t_inst_tree_inl1_pub1.py index 463aaa038..67900ceaf 100755 --- a/test_regress/t/t_inst_tree_inl1_pub1.py +++ b/test_regress/t/t_inst_tree_inl1_pub1.py @@ -15,8 +15,7 @@ test.top_filename = "t/t_inst_tree.v" out_filename = test.obj_dir + "/V" + test.name + ".tree.json" test.compile(v_flags2=[ - "--no-json-edit-nums", "-fno-dfg-post-inline", "t/" + test.name + - ".vlt", test.wno_unopthreads_for_few_cores + "--no-json-edit-nums", "t/" + test.name + ".vlt", test.wno_unopthreads_for_few_cores ]) if test.vlt_all: diff --git a/test_regress/t/t_json_only_first.out b/test_regress/t/t_json_only_first.out index 4d4a7361a..3b494015d 100644 --- a/test_regress/t/t_json_only_first.out +++ b/test_regress/t/t_json_only_first.out @@ -46,10 +46,10 @@ "stmtsp": [ {"type":"ASSIGNW","name":"","addr":"(IB)","loc":"d,56:12,56:13","dtypep":"(G)", "rhsp": [ - {"type":"VARREF","name":"d","addr":"(JB)","loc":"d,52:17,52:18","dtypep":"(G)","access":"RD","varp":"(Z)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"} + {"type":"VARREF","name":"d","addr":"(JB)","loc":"d,56:14,56:15","dtypep":"(G)","access":"RD","varp":"(Z)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"} ], "lhsp": [ - {"type":"VARREF","name":"q","addr":"(KB)","loc":"d,56:12,56:13","dtypep":"(G)","access":"WR","varp":"(CB)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"} + {"type":"VARREF","name":"q","addr":"(KB)","loc":"d,56:10,56:11","dtypep":"(G)","access":"WR","varp":"(CB)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"} ],"timingControlp": [],"strengthSpecp": []} ]} ]}, @@ -88,19 +88,18 @@ ]} ],"filesp": [], "miscsp": [ - {"type":"TYPETABLE","name":"","addr":"(C)","loc":"a,0:0,0:0","constraintRefp":"UNLINKED","emptyQueuep":"UNLINKED","queueIndexp":"UNLINKED","streamp":"UNLINKED","voidp":"(YB)", + {"type":"TYPETABLE","name":"","addr":"(C)","loc":"a,0:0,0:0","constraintRefp":"UNLINKED","emptyQueuep":"UNLINKED","queueIndexp":"UNLINKED","streamp":"UNLINKED","voidp":"UNLINKED", "typesp": [ {"type":"BASICDTYPE","name":"logic","addr":"(MB)","loc":"d,37:15,37:20","dtypep":"(MB)","keyword":"logic","range":"31:0","generic":true,"signed":true,"rangep": []}, {"type":"BASICDTYPE","name":"logic","addr":"(I)","loc":"d,39:11,39:14","dtypep":"(I)","keyword":"logic","generic":true,"rangep": []}, {"type":"BASICDTYPE","name":"logic","addr":"(G)","loc":"d,16:15,16:16","dtypep":"(G)","keyword":"logic","range":"3:0","generic":true,"rangep": []}, - {"type":"BASICDTYPE","name":"bit","addr":"(OB)","loc":"d,21:14,21:15","dtypep":"(OB)","keyword":"bit","range":"31:0","generic":true,"signed":true,"rangep": []}, - {"type":"VOIDDTYPE","name":"","addr":"(YB)","loc":"a,0:0,0:0","dtypep":"(YB)"} + {"type":"BASICDTYPE","name":"bit","addr":"(OB)","loc":"d,21:14,21:15","dtypep":"(OB)","keyword":"bit","range":"31:0","generic":true,"signed":true,"rangep": []} ]}, {"type":"CONSTPOOL","name":"","addr":"(D)","loc":"a,0:0,0:0", "modulep": [ - {"type":"MODULE","name":"@CONST-POOL@","addr":"(ZB)","loc":"a,0:0,0:0","origName":"@CONST-POOL@","verilogName":"@CONST-POOL@","level":0,"timeunit":"NONE","inlinesp": [], + {"type":"MODULE","name":"@CONST-POOL@","addr":"(YB)","loc":"a,0:0,0:0","origName":"@CONST-POOL@","verilogName":"@CONST-POOL@","level":0,"timeunit":"NONE","inlinesp": [], "stmtsp": [ - {"type":"SCOPE","name":"@CONST-POOL@","addr":"(AC)","loc":"a,0:0,0:0","aboveScopep":"UNLINKED","aboveCellp":"UNLINKED","modp":"(ZB)","varsp": [],"blocksp": [],"inlinesp": []} + {"type":"SCOPE","name":"@CONST-POOL@","addr":"(ZB)","loc":"a,0:0,0:0","aboveScopep":"UNLINKED","aboveCellp":"UNLINKED","modp":"(YB)","varsp": [],"blocksp": [],"inlinesp": []} ]} ]} ]} diff --git a/test_regress/t/t_json_only_flat.out b/test_regress/t/t_json_only_flat.out index 5f3c90b13..fe90f25e0 100644 --- a/test_regress/t/t_json_only_flat.out +++ b/test_regress/t/t_json_only_flat.out @@ -157,10 +157,10 @@ "stmtsp": [ {"type":"ASSIGNW","name":"","addr":"(JD)","loc":"d,56:12,56:13","dtypep":"(H)", "rhsp": [ - {"type":"VARREF","name":"t.between","addr":"(KD)","loc":"d,18:15,18:22","dtypep":"(H)","access":"RD","varp":"(O)","varScopep":"(UB)","classOrPackagep":"UNLINKED"} + {"type":"VARREF","name":"t.between","addr":"(KD)","loc":"d,56:14,56:15","dtypep":"(H)","access":"RD","varp":"(O)","varScopep":"(UB)","classOrPackagep":"UNLINKED"} ], "lhsp": [ - {"type":"VARREF","name":"q","addr":"(LD)","loc":"d,56:12,56:13","dtypep":"(H)","access":"WR","varp":"(G)","varScopep":"(CB)","classOrPackagep":"UNLINKED"} + {"type":"VARREF","name":"q","addr":"(LD)","loc":"d,56:10,56:11","dtypep":"(H)","access":"WR","varp":"(G)","varScopep":"(CB)","classOrPackagep":"UNLINKED"} ],"timingControlp": [],"strengthSpecp": []} ]} ],"inlinesp": []} @@ -168,19 +168,18 @@ ]} ],"filesp": [], "miscsp": [ - {"type":"TYPETABLE","name":"","addr":"(C)","loc":"a,0:0,0:0","constraintRefp":"UNLINKED","emptyQueuep":"UNLINKED","queueIndexp":"UNLINKED","streamp":"UNLINKED","voidp":"(MD)", + {"type":"TYPETABLE","name":"","addr":"(C)","loc":"a,0:0,0:0","constraintRefp":"UNLINKED","emptyQueuep":"UNLINKED","queueIndexp":"UNLINKED","streamp":"UNLINKED","voidp":"UNLINKED", "typesp": [ {"type":"BASICDTYPE","name":"logic","addr":"(Q)","loc":"d,37:15,37:20","dtypep":"(Q)","keyword":"logic","range":"31:0","generic":true,"signed":true,"rangep": []}, {"type":"BASICDTYPE","name":"logic","addr":"(J)","loc":"d,39:11,39:14","dtypep":"(J)","keyword":"logic","generic":true,"rangep": []}, {"type":"BASICDTYPE","name":"logic","addr":"(H)","loc":"d,16:15,16:16","dtypep":"(H)","keyword":"logic","range":"3:0","generic":true,"rangep": []}, - {"type":"BASICDTYPE","name":"bit","addr":"(S)","loc":"d,21:14,21:15","dtypep":"(S)","keyword":"bit","range":"31:0","generic":true,"signed":true,"rangep": []}, - {"type":"VOIDDTYPE","name":"","addr":"(MD)","loc":"a,0:0,0:0","dtypep":"(MD)"} + {"type":"BASICDTYPE","name":"bit","addr":"(S)","loc":"d,21:14,21:15","dtypep":"(S)","keyword":"bit","range":"31:0","generic":true,"signed":true,"rangep": []} ]}, {"type":"CONSTPOOL","name":"","addr":"(D)","loc":"a,0:0,0:0", "modulep": [ - {"type":"MODULE","name":"@CONST-POOL@","addr":"(ND)","loc":"a,0:0,0:0","origName":"@CONST-POOL@","verilogName":"@CONST-POOL@","level":0,"timeunit":"NONE","inlinesp": [], + {"type":"MODULE","name":"@CONST-POOL@","addr":"(MD)","loc":"a,0:0,0:0","origName":"@CONST-POOL@","verilogName":"@CONST-POOL@","level":0,"timeunit":"NONE","inlinesp": [], "stmtsp": [ - {"type":"SCOPE","name":"@CONST-POOL@","addr":"(OD)","loc":"a,0:0,0:0","aboveScopep":"UNLINKED","aboveCellp":"UNLINKED","modp":"(ND)","varsp": [],"blocksp": [],"inlinesp": []} + {"type":"SCOPE","name":"@CONST-POOL@","addr":"(ND)","loc":"a,0:0,0:0","aboveScopep":"UNLINKED","aboveCellp":"UNLINKED","modp":"(MD)","varsp": [],"blocksp": [],"inlinesp": []} ]} ]} ]} diff --git a/test_regress/t/t_json_only_flat_vlvbound.out b/test_regress/t/t_json_only_flat_vlvbound.out index 4e8ea1590..c1eb1e09c 100644 --- a/test_regress/t/t_json_only_flat_vlvbound.out +++ b/test_regress/t/t_json_only_flat_vlvbound.out @@ -329,7 +329,7 @@ ]} ],"filesp": [], "miscsp": [ - {"type":"TYPETABLE","name":"","addr":"(C)","loc":"a,0:0,0:0","constraintRefp":"UNLINKED","emptyQueuep":"UNLINKED","queueIndexp":"UNLINKED","streamp":"UNLINKED","voidp":"(IG)", + {"type":"TYPETABLE","name":"","addr":"(C)","loc":"a,0:0,0:0","constraintRefp":"UNLINKED","emptyQueuep":"UNLINKED","queueIndexp":"UNLINKED","streamp":"UNLINKED","voidp":"UNLINKED", "typesp": [ {"type":"BASICDTYPE","name":"bit","addr":"(BD)","loc":"d,18:18,18:19","dtypep":"(BD)","keyword":"bit","generic":true,"rangep": []}, {"type":"BASICDTYPE","name":"bit","addr":"(ID)","loc":"d,19:34,19:39","dtypep":"(ID)","keyword":"bit","range":"1:0","generic":true,"rangep": []}, @@ -343,14 +343,13 @@ {"type":"BASICDTYPE","name":"logic","addr":"(KD)","loc":"d,19:20,19:21","dtypep":"(KD)","keyword":"logic","range":"1:0","generic":true,"rangep": []}, {"type":"BASICDTYPE","name":"logic","addr":"(ND)","loc":"d,19:20,19:21","dtypep":"(ND)","keyword":"logic","range":"3:0","generic":true,"signed":true,"rangep": []}, {"type":"BASICDTYPE","name":"logic","addr":"(CE)","loc":"d,18:24,18:26","dtypep":"(CE)","keyword":"logic","range":"31:0","generic":true,"rangep": []}, - {"type":"BASICDTYPE","name":"bit","addr":"(WC)","loc":"d,18:12,18:13","dtypep":"(WC)","keyword":"bit","range":"31:0","generic":true,"signed":true,"rangep": []}, - {"type":"VOIDDTYPE","name":"","addr":"(IG)","loc":"a,0:0,0:0","dtypep":"(IG)"} + {"type":"BASICDTYPE","name":"bit","addr":"(WC)","loc":"d,18:12,18:13","dtypep":"(WC)","keyword":"bit","range":"31:0","generic":true,"signed":true,"rangep": []} ]}, {"type":"CONSTPOOL","name":"","addr":"(D)","loc":"a,0:0,0:0", "modulep": [ - {"type":"MODULE","name":"@CONST-POOL@","addr":"(JG)","loc":"a,0:0,0:0","origName":"@CONST-POOL@","verilogName":"@CONST-POOL@","level":0,"timeunit":"NONE","inlinesp": [], + {"type":"MODULE","name":"@CONST-POOL@","addr":"(IG)","loc":"a,0:0,0:0","origName":"@CONST-POOL@","verilogName":"@CONST-POOL@","level":0,"timeunit":"NONE","inlinesp": [], "stmtsp": [ - {"type":"SCOPE","name":"@CONST-POOL@","addr":"(KG)","loc":"a,0:0,0:0","aboveScopep":"UNLINKED","aboveCellp":"UNLINKED","modp":"(JG)","varsp": [],"blocksp": [],"inlinesp": []} + {"type":"SCOPE","name":"@CONST-POOL@","addr":"(JG)","loc":"a,0:0,0:0","aboveScopep":"UNLINKED","aboveCellp":"UNLINKED","modp":"(IG)","varsp": [],"blocksp": [],"inlinesp": []} ]} ]} ]} diff --git a/test_regress/t/t_json_only_primary_io.out b/test_regress/t/t_json_only_primary_io.out index 0533de594..8160496f8 100644 --- a/test_regress/t/t_json_only_primary_io.out +++ b/test_regress/t/t_json_only_primary_io.out @@ -26,10 +26,10 @@ "stmtsp": [ {"type":"ASSIGNW","name":"","addr":"(X)","loc":"d,26:16,26:17","dtypep":"(G)", "rhsp": [ - {"type":"VARREF","name":"ready_reg","addr":"(Y)","loc":"d,18:8,18:17","dtypep":"(G)","access":"RD","varp":"(K)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"} + {"type":"VARREF","name":"ready_reg","addr":"(Y)","loc":"d,26:18,26:27","dtypep":"(G)","access":"RD","varp":"(K)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"} ], "lhsp": [ - {"type":"VARREF","name":"ready","addr":"(Z)","loc":"d,26:16,26:17","dtypep":"(G)","access":"WR","varp":"(J)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"} + {"type":"VARREF","name":"ready","addr":"(Z)","loc":"d,26:10,26:15","dtypep":"(G)","access":"WR","varp":"(J)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"} ],"timingControlp": [],"strengthSpecp": []} ]} ]}, @@ -44,29 +44,28 @@ "rhsp": [ {"type":"AND","name":"","addr":"(CB)","loc":"d,34:19,34:20","dtypep":"(G)", "lhsp": [ - {"type":"VARREF","name":"a1","addr":"(DB)","loc":"d,30:16,30:18","dtypep":"(G)","access":"RD","varp":"(O)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"} + {"type":"VARREF","name":"a1","addr":"(DB)","loc":"d,34:16,34:18","dtypep":"(G)","access":"RD","varp":"(O)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"} ], "rhsp": [ - {"type":"VARREF","name":"a2","addr":"(EB)","loc":"d,31:16,31:18","dtypep":"(G)","access":"RD","varp":"(R)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"} + {"type":"VARREF","name":"a2","addr":"(EB)","loc":"d,34:21,34:23","dtypep":"(G)","access":"RD","varp":"(R)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"} ]} ], "lhsp": [ - {"type":"VARREF","name":"zn","addr":"(FB)","loc":"d,34:13,34:14","dtypep":"(G)","access":"WR","varp":"(U)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"} + {"type":"VARREF","name":"zn","addr":"(FB)","loc":"d,34:10,34:12","dtypep":"(G)","access":"WR","varp":"(U)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"} ],"timingControlp": [],"strengthSpecp": []} ]} ]} ],"filesp": [], "miscsp": [ - {"type":"TYPETABLE","name":"","addr":"(C)","loc":"a,0:0,0:0","constraintRefp":"UNLINKED","emptyQueuep":"UNLINKED","queueIndexp":"UNLINKED","streamp":"UNLINKED","voidp":"(GB)", + {"type":"TYPETABLE","name":"","addr":"(C)","loc":"a,0:0,0:0","constraintRefp":"UNLINKED","emptyQueuep":"UNLINKED","queueIndexp":"UNLINKED","streamp":"UNLINKED","voidp":"UNLINKED", "typesp": [ - {"type":"BASICDTYPE","name":"logic","addr":"(G)","loc":"d,30:16,30:18","dtypep":"(G)","keyword":"logic","generic":true,"rangep": []}, - {"type":"VOIDDTYPE","name":"","addr":"(GB)","loc":"a,0:0,0:0","dtypep":"(GB)"} + {"type":"BASICDTYPE","name":"logic","addr":"(G)","loc":"d,30:16,30:18","dtypep":"(G)","keyword":"logic","generic":true,"rangep": []} ]}, {"type":"CONSTPOOL","name":"","addr":"(D)","loc":"a,0:0,0:0", "modulep": [ - {"type":"MODULE","name":"@CONST-POOL@","addr":"(HB)","loc":"a,0:0,0:0","origName":"@CONST-POOL@","verilogName":"@CONST-POOL@","level":0,"timeunit":"NONE","inlinesp": [], + {"type":"MODULE","name":"@CONST-POOL@","addr":"(GB)","loc":"a,0:0,0:0","origName":"@CONST-POOL@","verilogName":"@CONST-POOL@","level":0,"timeunit":"NONE","inlinesp": [], "stmtsp": [ - {"type":"SCOPE","name":"@CONST-POOL@","addr":"(IB)","loc":"a,0:0,0:0","aboveScopep":"UNLINKED","aboveCellp":"UNLINKED","modp":"(HB)","varsp": [],"blocksp": [],"inlinesp": []} + {"type":"SCOPE","name":"@CONST-POOL@","addr":"(HB)","loc":"a,0:0,0:0","aboveScopep":"UNLINKED","aboveCellp":"UNLINKED","modp":"(GB)","varsp": [],"blocksp": [],"inlinesp": []} ]} ]} ]} diff --git a/test_regress/t/t_lint_always_comb_multidriven_bad.out b/test_regress/t/t_lint_always_comb_multidriven_bad.out index 21f5d90b1..b33646869 100644 --- a/test_regress/t/t_lint_always_comb_multidriven_bad.out +++ b/test_regress/t/t_lint_always_comb_multidriven_bad.out @@ -49,7 +49,6 @@ 40 | always_comb out6 = d; | ^~~~ %Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven_bad.v:17:14: Bit [0] of signal 'out2' have multiple combinational drivers. This can cause performance degradation. - : ... note: In instance 't' t/t_lint_always_comb_multidriven_bad.v:28:15: ... Location of offending driver 28 | assign out2 = d; | ^ @@ -57,7 +56,6 @@ 29 | always_comb out2 = 1'b0; | ^ %Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven_bad.v:19:14: Bit [0] of signal 'out4' have multiple combinational drivers. This can cause performance degradation. - : ... note: In instance 't' t/t_lint_always_comb_multidriven_bad.v:34:20: ... Location of offending driver 34 | always_comb out4 = 1'b0; | ^ @@ -65,7 +63,6 @@ 35 | assign out4 = d; | ^ %Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven_bad.v:20:14: Bit [0] of signal 'out5' have multiple combinational drivers. This can cause performance degradation. - : ... note: In instance 't' t/t_lint_always_comb_multidriven_bad.v:37:20: ... Location of offending driver 37 | always_comb out5 = 1'b0; | ^ @@ -73,7 +70,6 @@ 38 | always_comb out5 = d; | ^ %Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven_bad.v:21:14: Bit [0] of signal 'out6' have multiple combinational drivers. This can cause performance degradation. - : ... note: In instance 't' t/t_lint_always_comb_multidriven_bad.v:40:20: ... Location of offending driver 40 | always_comb out6 = d; | ^ diff --git a/test_regress/t/t_lint_always_comb_multidriven_public_bad.out b/test_regress/t/t_lint_always_comb_multidriven_public_bad.out index 21f5d90b1..e0cbd0e53 100644 --- a/test_regress/t/t_lint_always_comb_multidriven_public_bad.out +++ b/test_regress/t/t_lint_always_comb_multidriven_public_bad.out @@ -48,32 +48,28 @@ t/t_lint_always_comb_multidriven_bad.v:40:15: ... Location of other write 40 | always_comb out6 = d; | ^~~~ -%Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven_bad.v:17:14: Bit [0] of signal 'out2' have multiple combinational drivers. This can cause performance degradation. - : ... note: In instance 't' +%Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven_bad.v:17:14: Bit [0] of signal 't.out2' have multiple combinational drivers. This can cause performance degradation. t/t_lint_always_comb_multidriven_bad.v:28:15: ... Location of offending driver 28 | assign out2 = d; | ^ t/t_lint_always_comb_multidriven_bad.v:29:20: ... Location of offending driver 29 | always_comb out2 = 1'b0; | ^ -%Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven_bad.v:19:14: Bit [0] of signal 'out4' have multiple combinational drivers. This can cause performance degradation. - : ... note: In instance 't' +%Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven_bad.v:19:14: Bit [0] of signal 't.out4' have multiple combinational drivers. This can cause performance degradation. t/t_lint_always_comb_multidriven_bad.v:34:20: ... Location of offending driver 34 | always_comb out4 = 1'b0; | ^ t/t_lint_always_comb_multidriven_bad.v:35:15: ... Location of offending driver 35 | assign out4 = d; | ^ -%Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven_bad.v:20:14: Bit [0] of signal 'out5' have multiple combinational drivers. This can cause performance degradation. - : ... note: In instance 't' +%Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven_bad.v:20:14: Bit [0] of signal 't.out5' have multiple combinational drivers. This can cause performance degradation. t/t_lint_always_comb_multidriven_bad.v:37:20: ... Location of offending driver 37 | always_comb out5 = 1'b0; | ^ t/t_lint_always_comb_multidriven_bad.v:38:20: ... Location of offending driver 38 | always_comb out5 = d; | ^ -%Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven_bad.v:21:14: Bit [0] of signal 'out6' have multiple combinational drivers. This can cause performance degradation. - : ... note: In instance 't' +%Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven_bad.v:21:14: Bit [0] of signal 't.out6' have multiple combinational drivers. This can cause performance degradation. t/t_lint_always_comb_multidriven_bad.v:40:20: ... Location of offending driver 40 | always_comb out6 = d; | ^ diff --git a/test_regress/t/t_lint_multidriven_coverage_bad.out b/test_regress/t/t_lint_multidriven_coverage_bad.out index 7e06c4ffb..3e57a7563 100644 --- a/test_regress/t/t_lint_multidriven_coverage_bad.out +++ b/test_regress/t/t_lint_multidriven_coverage_bad.out @@ -1,5 +1,4 @@ -%Warning-MULTIDRIVEN: t/t_lint_multidriven_coverage_bad.v:13:15: Bit [0] of signal 'w' have multiple combinational drivers. This can cause performance degradation. - : ... note: In instance 't' +%Warning-MULTIDRIVEN: t/t_lint_multidriven_coverage_bad.v:13:15: Bit [0] of signal 't.w' have multiple combinational drivers. This can cause performance degradation. t/t_lint_multidriven_coverage_bad.v:15:15: ... Location of offending driver 15 | assign w[0] = a; | ^ diff --git a/test_regress/t/t_opt_const_dfg.py b/test_regress/t/t_opt_const_dfg.py index 88bf99d4f..eb5626311 100755 --- a/test_regress/t/t_opt_const_dfg.py +++ b/test_regress/t/t_opt_const_dfg.py @@ -18,7 +18,7 @@ test.compile(verilator_flags2=["-Wno-UNOPTTHREADS", "--stats", test.pli_filename test.execute() if test.vlt: - test.file_grep(test.stats, r'Optimizations, Const bit op reduction\s+(\d+)', 42) + test.file_grep(test.stats, r'Optimizations, Const bit op reduction\s+(\d+)', 43) test.file_grep(test.stats, r'SplitVar, packed variables split automatically\s+(\d+)', 1) test.passes()