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 decaddbb7..166824082 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -1964,7 +1964,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 @@ -2024,7 +2023,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; @@ -2206,8 +2204,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 36e24baf3..65b129df1 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'; @@ -877,10 +856,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; @@ -898,7 +875,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; } @@ -911,13 +888,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 f0b4d714b..6c42faa3b 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -307,15 +307,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 @@ -329,15 +322,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()); @@ -355,7 +343,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 @@ -370,7 +358,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(); } @@ -398,7 +386,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()); @@ -409,7 +397,7 @@ static void process() { } // Cleanup - V3Const::constifyAll(v3Global.rootp()); + if (v3Global.opt.fConstBeforeDfg()) V3Const::constifyAll(v3Global.rootp()); V3Dead::deadifyDTypesScoped(v3Global.rootp()); v3Global.checkTree(); @@ -429,10 +417,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()