diff --git a/Changes b/Changes index 2d24b7418..1c9166ce4 100644 --- a/Changes +++ b/Changes @@ -13,6 +13,7 @@ Verilator 4.223 devel **Minor:** +* Fix hang with large case statement optimization (#3405). [Mike Urbach] Verilator 4.222 2022-05-02 diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 9152d8cd6..759033185 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -769,6 +769,9 @@ public: class ConstVisitor final : public VNVisitor { private: + // CONSTANTS + static constexpr unsigned CONCAT_MERGABLE_MAX_DEPTH = 10; // Limit alg recursion + // NODE STATE // ** only when m_warn/m_doExpensive is set. If state is needed other times, // ** must track down everywhere V3Const is called and make sure no overlaps. @@ -1420,11 +1423,12 @@ private: if (rend == rfromp->width() && lstart->toSInt() == 0) return true; return false; } - bool concatMergeable(const AstNode* lhsp, const AstNode* rhsp) { + bool concatMergeable(const AstNode* lhsp, const AstNode* rhsp, unsigned depth) { // determine if {a OP b, c OP d} => {a, c} OP {b, d} is advantageous if (!v3Global.opt.oAssemble()) return false; // opt disabled if (lhsp->type() != rhsp->type()) return false; if (!ifConcatMergeableBiop(lhsp)) return false; + if (depth > CONCAT_MERGABLE_MAX_DEPTH) return false; // As worse case O(n^2) algorithm const AstNodeBiop* const lp = VN_CAST(lhsp, NodeBiop); const AstNodeBiop* const rp = VN_CAST(rhsp, NodeBiop); @@ -1434,11 +1438,12 @@ private: const bool rad = ifMergeAdjacent(lp->rhsp(), rp->rhsp()); if (lad && rad) return true; // {a[] & b[]&c[], a[] & b[]&c[]} - if (lad && concatMergeable(lp->rhsp(), rp->rhsp())) return true; + if (lad && concatMergeable(lp->rhsp(), rp->rhsp(), depth + 1)) return true; // {a[]&b[] & c[], a[]&b[] & c[]} - if (rad && concatMergeable(lp->lhsp(), rp->lhsp())) return true; + if (rad && concatMergeable(lp->lhsp(), rp->lhsp(), depth + 1)) return true; // {(a[]&b[])&(c[]&d[]), (a[]&b[])&(c[]&d[])} - if (concatMergeable(lp->lhsp(), rp->lhsp()) && concatMergeable(lp->rhsp(), rp->rhsp())) { + if (concatMergeable(lp->lhsp(), rp->lhsp(), depth + 1) + && concatMergeable(lp->rhsp(), rp->rhsp(), depth + 1)) { return true; } return false; @@ -1698,7 +1703,7 @@ private: AstNode* const lrp = lp->rhsp()->cloneTree(false); AstNode* const rlp = rp->lhsp()->cloneTree(false); AstNode* const rrp = rp->rhsp()->cloneTree(false); - if (concatMergeable(lp, rp)) { + if (concatMergeable(lp, rp, 0)) { AstConcat* const newlp = new AstConcat(rlp->fileline(), llp, rlp); AstConcat* const newrp = new AstConcat(rrp->fileline(), lrp, rrp); // use the lhs to replace the parent concat @@ -3368,7 +3373,7 @@ private: TREEOPV("AstConcat{$lhsp.isZero, $rhsp}", "replaceExtend(nodep, nodep->rhsp())"); // CONCAT(a[1],a[0]) -> a[1:0] TREEOPV("AstConcat{$lhsp.castSel, $rhsp.castSel, ifAdjacentSel(VN_AS($lhsp,,Sel),,VN_AS($rhsp,,Sel))}", "replaceConcatSel(nodep)"); - TREEOPV("AstConcat{ifConcatMergeableBiop($lhsp), concatMergeable($lhsp,,$rhsp)}", "replaceConcatMerge(nodep)"); + TREEOPV("AstConcat{ifConcatMergeableBiop($lhsp), concatMergeable($lhsp,,$rhsp,,0)}", "replaceConcatMerge(nodep)"); // Common two-level operations that can be simplified TREEOP ("AstAnd {$lhsp.castConst,matchAndCond(nodep)}", "DONE"); TREEOP ("AstAnd {$lhsp.castConst, $rhsp.castOr, matchMaskedOr(nodep)}", "DONE"); diff --git a/test_regress/t/t_concat_or.pl b/test_regress/t/t_concat_or.pl new file mode 100755 index 000000000..4409f8046 --- /dev/null +++ b/test_regress/t/t_concat_or.pl @@ -0,0 +1,18 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Wilson Snyder. 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-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + verilator_flags2 => ["--lint-only"], + ); + +ok(1); +1; diff --git a/test_regress/t/t_concat_or.v b/test_regress/t/t_concat_or.v new file mode 100644 index 000000000..17b05cb4b --- /dev/null +++ b/test_regress/t/t_concat_or.v @@ -0,0 +1,72 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/ + // Outputs + i299, + // Inputs + i190, i191, i192, i193, i194, i195, i196, i197, i198, i199, i200, i201, i202, + i203, i204, i205, i182, i183, i184, i185, i186, i187, i188, i189, i206, i282, + i284, i286, i287, i289, i290, i294, i34, i288, i31, i296, i37, i38 + ); + input [3:0] i190; + input [3:0] i191; + input [3:0] i192; + input [3:0] i193; + input [3:0] i194; + input [3:0] i195; + input [3:0] i196; + input [3:0] i197; + input [3:0] i198; + input [3:0] i199; + input [3:0] i200; + input [3:0] i201; + input [3:0] i202; + input [3:0] i203; + input [3:0] i204; + input [3:0] i205; + input [3:0] i182; + input [3:0] i183; + input [3:0] i184; + input [3:0] i185; + input [3:0] i186; + input [3:0] i187; + input [3:0] i188; + input [3:0] i189; + input [3:0] i206; + input [3:0] i282; + input [3:0] i284; + input [3:0] i286; + input [3:0] i287; + input [3:0] i289; + input [3:0] i290; + input [3:0] i294; + input [3:0] i34; + input [3:0] i288; + input [3:0] i31; + input [3:0] i296; + input [3:0] i37; + input [3:0] i38; + + output [3:0] i299; + assign i299 = { i296[2:0] | i31[3:1] | i282[3:1] | i284[3:1] | i34[3:1] + | i286[3:1] | i287[3:1] | i37[3:1] | i38[3:1] + | i288[3:1] | i289[3:1] | i290[3:1] | i182[3:1] + | i183[3:1] | i184[3:1] | i185[3:1] | i186[3:1] + | i187[3:1] | i188[3:1] | i189[3:1] | i190[3:1] + | i191[3:1] | i192[3:1] | i193[3:1] | i194[3:1] + | i195[3:1] | i196[3:1] | i197[3:1] | i198[3:1] + | i199[3:1] | i200[3:1] | i201[3:1] | i202[3:1] + | i203[3:1] | i204[3:1] | i205[3:1] | i206[3:1] + , + i294[0] | i289[0] | i290[0] | i182[0] | i183[0] + | i184[0] | i185[0] | i186[0] | i187[0] | i188[0] + | i189[0] | i190[0] | i191[0] | i192[0] | i193[0] + | i194[0] | i195[0] | i196[0] | i197[0] | i198[0] + | i199[0] | i200[0] | i201[0] | i202[0] | i203[0] + | i204[0] | i205[0] | i206[0] }; + +endmodule