diff --git a/src/V3Assert.cpp b/src/V3Assert.cpp index 160121c0b..77214da14 100644 --- a/src/V3Assert.cpp +++ b/src/V3Assert.cpp @@ -659,6 +659,34 @@ class AssertVisitor final : public VNVisitor { iterateChildren(nodep); } + if (nodep->user2()) { + // Combine consecutive assertOn checks if possible + if (AstIf* const backp = VN_CAST(nodep->backp(), If)) { + if (backp->nextp() == nodep // + && backp->user2() // + && backp->condp()->sameTree(nodep->condp())) { + ++m_statAssertOnCombined; + backp->addThensp(nodep->thensp()->unlinkFrBackWithNext()); + nodep->unlinkFrBack(); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + return; + } + } + // Combine nested assertOn checks if possible + if (nodep->thensp() && !nodep->thensp()->nextp() && isEmptyStmt(nodep->elsesp())) { + AstIf* const checkp = VN_CAST(nodep->thensp(), If); + if (checkp // + && checkp->user2() // + && checkp->condp()->sameTree(nodep->condp())) { + ++m_statAssertOnCombined; + nodep->addThensp(checkp->thensp()->unlinkFrBackWithNext()); + VL_DO_DANGLING(checkp->unlinkFrBack(), checkp); + return; + } + } + return; + } + // Swap assertOn check with single statement 'if' statement to bubble up for combining // Note we can't just swap the conditions as they two Ifs have different flags, // so swapping the Ifs themeselves then swapping back the bodies. @@ -684,20 +712,6 @@ class AssertVisitor final : public VNVisitor { } } } - - // Combine consecutive assertOn checks if possible - if (nodep->user2()) { - if (AstIf* const backp = VN_CAST(nodep->backp(), If)) { - if (backp->nextp() == nodep // - && backp->user2() // - && backp->condp()->sameTree(nodep->condp())) { - ++m_statAssertOnCombined; - backp->addThensp(nodep->thensp()->unlinkFrBackWithNext()); - nodep->unlinkFrBack(); - VL_DO_DANGLING(pushDeletep(nodep), nodep); - } - } - } } //========== Case assertions diff --git a/test_regress/t/t_assert_opt_check.py b/test_regress/t/t_assert_opt_check.py index b7652f1ab..884e2876c 100755 --- a/test_regress/t/t_assert_opt_check.py +++ b/test_regress/t/t_assert_opt_check.py @@ -15,7 +15,7 @@ test.compile(verilator_flags2=['--binary', '--stats']) test.execute(check_finished=True) -test.file_grep(test.stats, r'Assertions, assertOn checks combined\s+(\d+)', 2) -test.file_grep(test.stats, r'Assertions, assertOn checks hoisted\s+(\d+)', 11) +test.file_grep(test.stats, r'Assertions, assertOn checks combined\s+(\d+)', 3) +test.file_grep(test.stats, r'Assertions, assertOn checks hoisted\s+(\d+)', 15) test.passes() diff --git a/test_regress/t/t_assert_opt_check.v b/test_regress/t/t_assert_opt_check.v index ccfea327e..7d0f54537 100644 --- a/test_regress/t/t_assert_opt_check.v +++ b/test_regress/t/t_assert_opt_check.v @@ -58,4 +58,12 @@ module t; end end + // Should combine the 2 nested assertOn checks after hoisting + always @(posedge clk) begin + if (assertEnable) begin + // This is an 'assert' with another 'assert' in the fail branch + assert(cntB - 100 == cntA); else assert(cntB == cntA + 100); + end + end + endmodule