diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 843937ccb..6f56bc6e2 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -1297,23 +1297,32 @@ class ConstVisitor final : public VNVisitor { if (nodep->widthMin() != 1) return false; if (!v3Global.opt.fConstBitOpTree()) return false; - string debugPrefix; + const int width = nodep->width(); + AstNodeExpr* rootp = nodep; + unsigned externalOps = 0; + // Reach past a plain making AND + if (const AstAnd* const andp = VN_CAST(nodep, And)) { + if (isConst(andp->lhsp(), 1)) { + rootp = andp->rhsp(); + externalOps = 1; + } + } + + // Only optimize if rootp is in fact the root of a tree of identical + // operations, otherwise analysis on an eventually unoptimizable unablanced + // tree can go O(N^2) as we would re-analyze every time as we move up the + // tree, repeatedly re-discover the sub-tree is not optimizable. + if (rootp->type() == nodep->backp()->type()) return false; + + std::string debugPrefix; if (debug() >= 9) { // LCOV_EXCL_START static int s_c = 0; - debugPrefix = "- matchBitOpTree["; - debugPrefix += cvtToStr(++s_c); - debugPrefix += "] "; + debugPrefix = "- matchBitOpTree[" + std::to_string(++s_c) + "] "; nodep->dumpTree(debugPrefix + "INPUT: "); } // LCOV_EXCL_STOP - AstNode* newp = nullptr; - const AstAnd* const andp = VN_CAST(nodep, And); - const int width = nodep->width(); - if (andp && isConst(andp->lhsp(), 1)) { // 1 & BitOpTree - newp = ConstBitOpTreeVisitor::simplify(andp->rhsp(), width, 1, m_statBitOpReduction); - } else { // BitOpTree - newp = ConstBitOpTreeVisitor::simplify(nodep, width, 0, m_statBitOpReduction); - } + AstNodeExpr* const newp + = ConstBitOpTreeVisitor::simplify(rootp, width, externalOps, m_statBitOpReduction); if (newp) { nodep->replaceWithKeepDType(newp); diff --git a/test_regress/t/t_opt_const.py b/test_regress/t/t_opt_const.py index fa7ed5a17..5cf4b936b 100755 --- a/test_regress/t/t_opt_const.py +++ b/test_regress/t/t_opt_const.py @@ -16,7 +16,7 @@ test.compile(verilator_flags2=["-Wno-UNOPTTHREADS", "-fno-dfg", "--stats", test. test.execute() if test.vlt: - test.file_grep(test.stats, r'Optimizations, Const bit op reduction\s+(\d+)', 44) + test.file_grep(test.stats, r'Optimizations, Const bit op reduction\s+(\d+)', 49) test.file_grep(test.stats, r'SplitVar, packed variables split automatically\s+(\d+)', 1) test.passes() diff --git a/test_regress/t/t_opt_const_cov.py b/test_regress/t/t_opt_const_cov.py index e2403b28b..f1c93b8d2 100755 --- a/test_regress/t/t_opt_const_cov.py +++ b/test_regress/t/t_opt_const_cov.py @@ -16,6 +16,6 @@ test.compile(verilator_flags2=["-Wno-UNOPTTHREADS", "--stats", "--coverage", "-- test.execute() if test.vlt: - test.file_grep(test.stats, r'Optimizations, Const bit op reduction\s+(\d+)', 478) + test.file_grep(test.stats, r'Optimizations, Const bit op reduction\s+(\d+)', 550) test.passes() diff --git a/test_regress/t/t_opt_const_dfg.py b/test_regress/t/t_opt_const_dfg.py index 7fd8decd0..6fd2ea9bc 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+)', 37) + 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() diff --git a/test_regress/t/t_opt_const_no_expand.py b/test_regress/t/t_opt_const_no_expand.py index e42265a8d..e72a9737f 100755 --- a/test_regress/t/t_opt_const_no_expand.py +++ b/test_regress/t/t_opt_const_no_expand.py @@ -19,6 +19,6 @@ test.compile(verilator_flags2=[ test.execute() if test.vlt: - test.file_grep(test.stats, r'Optimizations, Const bit op reduction\s+(\d+)', 1) + test.file_grep(test.stats, r'Optimizations, Const bit op reduction\s+(\d+)', 4) test.passes() diff --git a/test_regress/t/t_opt_const_red.py b/test_regress/t/t_opt_const_red.py index ab1e823fe..66ad3d212 100755 --- a/test_regress/t/t_opt_const_red.py +++ b/test_regress/t/t_opt_const_red.py @@ -16,6 +16,6 @@ test.compile(verilator_flags2=["-Wno-UNOPTTHREADS", "--stats"]) test.execute() if test.vlt: - test.file_grep(test.stats, r'Optimizations, Const bit op reduction\s+(\d+)', 158) + test.file_grep(test.stats, r'Optimizations, Const bit op reduction\s+(\d+)', 160) test.passes()