diff --git a/src/V3AstInlines.h b/src/V3AstInlines.h index e31960429..8a4477060 100644 --- a/src/V3AstInlines.h +++ b/src/V3AstInlines.h @@ -146,6 +146,7 @@ bool AstBasicDType::ascending() const { bool AstActive::hasClocked() const { return m_sentreep->hasClocked(); } bool AstActive::hasCombo() const { return m_sentreep->hasCombo(); } +bool AstActive::hasStatic() const { return m_sentreep->hasStatic(); } AstAlways::AstAlways(AstAssignW* assignp) : ASTGEN_SUPER_Always(assignp->fileline(), assignp) diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index 32a38ca0b..93cc01fdc 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -432,6 +432,7 @@ public: // METHODS inline bool hasClocked() const; inline bool hasCombo() const; + inline bool hasStatic() const; }; class AstAlias final : public AstNode { // Alias construct - Used for source level net alias, and also for variable aliases internally diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index ca15a0bb6..e24fd54ef 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -47,6 +47,7 @@ class GateEitherVertex VL_NOT_FINAL : public V3GraphVertex { bool m_reducible = true; // True if this node should be able to be eliminated bool m_dedupable = true; // True if this node should be able to be deduped bool m_consumed = false; // Output goes to something meaningful + bool m_staticInit = false; // True if this node is a static initializer public: explicit GateEitherVertex(V3Graph* graphp) : V3GraphVertex{graphp} {} @@ -56,10 +57,12 @@ public: bool reducible() const { return m_reducible; } bool dedupable() const { return m_dedupable; } bool consumed() const { return m_consumed; } + bool staticInit() const { return m_staticInit; } void setConsumed(const char* /*consumedReason*/) { // if (!m_consumed) UINFO(0, "\t\tSetConsumed " << consumedReason << " " << this); m_consumed = true; } + void setStaticInit() { m_staticInit = true; } void clearReducible(const char* /*nonReducibleReason*/) { // UINFO(0, " NR: " << nonReducibleReason << " " << name()); m_reducible = false; @@ -196,6 +199,7 @@ class GateBuildVisitor final : public VNVisitorConst { const AstScope* m_scopep = nullptr; // Current scope being processed AstActive* m_activep = nullptr; // Current active bool m_inClockedActive = false; // Underneath clocked active + bool m_inStaticActive = false; // Underneath static active bool m_inSenItem = false; // Underneath AstSenItem; any varrefs are clocks // METHODS @@ -219,6 +223,8 @@ class GateBuildVisitor final : public VNVisitorConst { m_logicVertexp->clearReducibleAndDedupable(nonReducibleReason); } else if (m_inClockedActive) { m_logicVertexp->clearReducible("Clocked logic"); // but dedupable + } else if (m_inStaticActive) { + m_logicVertexp->setStaticInit(); } if (consumeReason) m_logicVertexp->setConsumed(consumeReason); checkNode(nodep); @@ -242,8 +248,10 @@ class GateBuildVisitor final : public VNVisitorConst { UASSERT_OBJ(!m_activep, nodep, "Should not nest"); VL_RESTORER(m_activep); VL_RESTORER(m_inClockedActive); + VL_RESTORER(m_inStaticActive); m_activep = nodep; m_inClockedActive = nodep->hasClocked(); + m_inStaticActive = nodep->hasStatic(); // AstVarScope::user2 -> bool: Signal used in SenItem in *this* active block const VNUser2InUse user2InUse; @@ -700,6 +708,9 @@ class GateInline final { if (!VN_IS(substp, NodeVarRef)) continue; } + // Only inline static initializer if constant known at compile time + if (lVtxp->staticInit() && !VN_IS(substp, Const)) continue; + // Process it ++m_statInlined; diff --git a/test_regress/t/t_struct_initial_assign.py b/test_regress/t/t_struct_initial_assign.py index f3c898f62..c1140f359 100755 --- a/test_regress/t/t_struct_initial_assign.py +++ b/test_regress/t/t_struct_initial_assign.py @@ -13,6 +13,6 @@ test.scenarios('simulator') test.compile(verilator_flags2=["--timing"]) -test.execute(fails=test.vlt_all) # Issue #5381 +test.execute() test.passes() diff --git a/test_regress/t/t_struct_initial_assign.v b/test_regress/t/t_struct_initial_assign.v index a72732926..56c6aaf26 100644 --- a/test_regress/t/t_struct_initial_assign.v +++ b/test_regress/t/t_struct_initial_assign.v @@ -15,7 +15,7 @@ module t ( input clk ); - str_t bar_in; + str_t bar_in = '0; // Set bar_in to 0 initially str_t bar_out; Sub sub ( @@ -28,8 +28,6 @@ module t ( integer i; str_t initOut; - bar_in = '0; // Set bar_in to 0 initially - // Wait for the first falling edge of the clock @(negedge clk);