Fix exponential expansion in V3Gate (#7550)

Unfortunate constellation of combinational assignments could be inlined
by V3Gate yielding an exponential expansion (added test used to consume
4GB+ memory and generate 3GB+ code).
This commit is contained in:
Geza Lore 2026-05-07 22:01:08 -05:00 committed by GitHub
parent db8b6ce26d
commit 7c5069c7df
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 80 additions and 13 deletions

View File

@ -693,7 +693,9 @@ class GateInline final {
for (V3GraphEdge& edge : vVtxp->outEdges()) {
const GateLogicVertex* const dstVtxp = edge.top()->as<GateLogicVertex>();
// Ignore slow code, or if the destination is not used
if (!dstVtxp->slow() && !dstVtxp->outEmpty()) n += edge.weight();
if (dstVtxp->slow()) continue;
if (dstVtxp->outEmpty() && !dstVtxp->consumed()) continue;
n += edge.weight();
if (n > 1) break;
}
if (n > 1) continue;
@ -1308,6 +1310,10 @@ void V3Gate::gateAll(AstNetlist* netlistp) {
graphp->removeRedundantEdgesSum(&V3GraphEdge::followAlwaysTrue);
if (dumpGraphLevel() >= 6) graphp->dumpDotFilePrefixed("gate_simp");
// Remove unused logic
GateUnused::apply(*graphp);
if (dumpGraphLevel() >= 3) graphp->dumpDotFilePrefixed("gate_unused");
// Inline variables
GateInline::apply(*graphp);
if (dumpGraphLevel() >= 6) graphp->dumpDotFilePrefixed("gate_inline");

View File

@ -48,6 +48,6 @@ test.compile(
test.execute()
# Must be <<9000 above to prove this worked
test.file_grep(test.stats, r'Optimizations, Gate sigs deleted\s+(\d+)', 8554)
test.file_grep(test.stats, r'Optimizations, Gate sigs deleted\s+(\d+)', 8550)
test.passes()

View File

@ -12,14 +12,17 @@
: ... note: In instance 't.non_parametrized_initial'
158 | do ; while(0);
| ^~
%Warning-UNUSEDLOOP: t/t_lint_unusedloop_removed_bad.v:114:5: Loop condition is always false
114 | while(always_zero < 0) begin
%Warning-UNUSEDLOOP: t/t_lint_unusedloop_removed_bad.v:136:5: Loop is not used and will be optimized out
136 | while(param_unused_while < always_zero) begin
| ^~~~~
%Warning-UNUSEDLOOP: t/t_lint_unusedloop_removed_bad.v:156:5: Loop condition is always false
%Warning-UNUSEDLOOP: t/t_lint_unusedloop_removed_bad.v:156:5: Loop is not used and will be optimized out
156 | while(always_false);
| ^~~~~
%Warning-UNUSEDLOOP: t/t_lint_unusedloop_removed_bad.v:157:5: Loop condition is always false
157 | while(always_zero < 0);
%Warning-UNUSEDLOOP: t/t_lint_unusedloop_removed_bad.v:280:5: Loop is not used and will be optimized out
280 | while (m_2_ticked);
| ^~~~~
%Warning-UNUSEDLOOP: t/t_lint_unusedloop_removed_bad.v:114:5: Loop condition is always false
114 | while(always_zero < 0) begin
| ^~~~~
%Warning-UNUSEDLOOP: t/t_lint_unusedloop_removed_bad.v:171:5: Loop condition is always false
171 | while(always_false) begin
@ -33,10 +36,4 @@
%Warning-UNUSEDLOOP: t/t_lint_unusedloop_removed_bad.v:190:5: Loop condition is always false
190 | for (int i = 0; i < always_zero; i++)
| ^~~
%Warning-UNUSEDLOOP: t/t_lint_unusedloop_removed_bad.v:136:5: Loop is not used and will be optimized out
136 | while(param_unused_while < always_zero) begin
| ^~~~~
%Warning-UNUSEDLOOP: t/t_lint_unusedloop_removed_bad.v:280:5: Loop is not used and will be optimized out
280 | while (m_2_ticked);
| ^~~~~
%Error: Exiting due to

View File

@ -0,0 +1,21 @@
#!/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: 2026 Wilson Snyder
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
import vltest_bootstrap
test.scenarios('vlt')
test.compile(verilator_flags2=["--stats"])
memUsageMB = int(test.file_grep(test.stats, r'Peak Memory Usage \(MB\) +(\d+)')[0])
if memUsageMB > 128 and not test.have_dev_asan:
test.error("Consumed over 128MB memory")
test.passes()

View File

@ -0,0 +1,43 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain.
// SPDX-FileCopyrightText: 2026 Wilson Snyder
// SPDX-License-Identifier: CC0-1.0
module top(
input wire [31:0] a
);
wire [31:0] w00, w01, w02, w03, w04, w05, w06, w07, w08, w09;
wire [31:0] w10, w11, w12, w13, w14, w15, w16, w17, w18, w19;
// V3Gate used to inline all the continuous assignments into
// the always_comb block, resultingin an exponential increase
// in AST size.
always_comb begin
$display(w19);
end
assign w19 = w18 + (w18 >> 1);
assign w18 = w17 + (w17 >> 1);
assign w17 = w16 + (w16 >> 1);
assign w16 = w15 + (w15 >> 1);
assign w15 = w14 + (w14 >> 1);
assign w14 = w13 + (w13 >> 1);
assign w13 = w12 + (w12 >> 1);
assign w12 = w11 + (w11 >> 1);
assign w11 = w10 + (w10 >> 1);
assign w10 = w09 + (w09 >> 1);
assign w09 = w08 + (w08 >> 1);
assign w08 = w07 + (w07 >> 1);
assign w07 = w06 + (w06 >> 1);
assign w06 = w05 + (w05 >> 1);
assign w05 = w04 + (w04 >> 1);
assign w04 = w03 + (w03 >> 1);
assign w03 = w02 + (w02 >> 1);
assign w02 = w01 + (w01 >> 1);
assign w01 = w00 + (w00 >> 1);
assign w00 = a + (a >> 1);
endmodule