diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index ea3a37db7d..473f89f4cb 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -684,7 +684,14 @@ class GateInline final { size_t m_statExcluded = 0; // Statistic tracking // METHODS - static bool excludedWide(GateVarVertex* const vVtxp) { + static bool isCheapWide(const GateLogicVertex* const lVtxp, const AstNodeExpr* const rhsp) { + if (const AstSel* const selp = VN_CAST(rhsp, Sel)) { + if (selp->lsbConst() % VL_EDATASIZE == 0) return true; + } + return lVtxp->slow() || VN_IS(rhsp, NodeVarRef) || VN_IS(rhsp, Const) + || VN_IS(rhsp, ArraySel); + } + static bool excludedWide(GateVarVertex* const vVtxp, const AstNodeExpr* const rhsp) { // Handle wides with logic drivers. if (!vVtxp->varScp()->isWide() || vVtxp->inEmpty() || vVtxp->varScp()->widthWords() <= v3Global.opt.expandLimit()) @@ -693,8 +700,7 @@ class GateInline final { const GateLogicVertex* const lVtxp = vVtxp->inEdges().frontp()->fromp()->as(); - if (lVtxp->slow() || VN_IS(lVtxp->nodep(), AssignAlias)) - return false; // Do not optimize consts, aliases and slow parts. + if (isCheapWide(lVtxp, rhsp)) return false; // Exclude from inlining variables READ multiple times that are initialized by wide // assigns. @@ -790,12 +796,6 @@ class GateInline final { // Can't inline if non-reducible, etc if (!vVtxp->reducible()) continue; - if (excludedWide(vVtxp)) { - ++m_statExcluded; - UINFO(9, "Gate inline exclude '" << vVtxp->name() << "'" << endl); - vVtxp->clearReducible("Excluded wide"); // Check once. - continue; - } // Grab the driving logic GateLogicVertex* const lVtxp @@ -813,6 +813,12 @@ class GateInline final { if (!okVisitor.isSimple()) continue; // If the varScope is already removed from logicp, no need to try substitution. if (!okVisitor.varAssigned(vVtxp->varScp())) continue; + if (excludedWide(vVtxp, okVisitor.substitutionp())) { + ++m_statExcluded; + UINFO(9, "Gate inline exclude '" << vVtxp->name() << "'" << endl); + vVtxp->clearReducible("Excluded wide"); // Check once. + continue; + } // Does it read multiple source variables? if (okVisitor.readVscps().size() > 1) { diff --git a/test_regress/t/t_duplicate_wide_expr.v b/test_regress/t/t_duplicate_wide_expr.v deleted file mode 100644 index 5a6d1d26d3..0000000000 --- a/test_regress/t/t_duplicate_wide_expr.v +++ /dev/null @@ -1,82 +0,0 @@ -// DESCRIPTION: Verilator: Verilog Test module -// -// This file ONLY is placed under the Creative Commons Public Domain, for -// any use, without warranty, 2024 by Antmicro. -// SPDX-License-Identifier: CC0-1.0 - -localparam N = 256; // Wider than expand limit. - -module t( - clk, - i, - o, - o_assign, - o_single, - o_outside, - o_non_blocking, - o_sel, - o_swizzle, - o_small, - o_multiple1, - o_multiple2 - ); - input clk; - input wire [N-1:0] i; - output wire [N-1:0][2:0] o; - output wire [N-1:0] o_single; - output logic [N-1:0] o_outside; - output logic [N:0] o_multiple1; - output logic [N:0] o_multiple2; - output logic [N-1:0] o_sel; - output logic [N-1:0] o_assign; - output logic [N-1:0] o_non_blocking; - output logic [N:0] o_swizzle; - output logic [65:0] o_small; - - // Shouldn't be inlined - wire [N-1:0] wide_non_simple = N << i; - wire [N:0] wide_multiple = N >> i; - - // Should be inlined - wire [N-1:0] wide_const_expr = 1 >> (N-1); - wire [N-1:0] wide_const = 256'h1234_5678_aaaa_bbbb; - wire [N-1:0] wide_single = N << i; - wire [N-1:0] wide_outside = N ~^ i; - wire [N-1:0] wide_assign = i; - wire [N-1:0][2:0] wide_assign_dim; - wire [N:0][N:0] wide_swizzle = 66049'(N & i); - wire [65:0] wide_small = N << i * i / N; - - assign wide_assign_dim = o; - for (genvar n = 0; n < N - 1; ++n) begin - assign o[n][0] = i[N-1-n] | wide_non_simple[N-1-n]; - assign o[n][1] = i[N-1-n] & wide_const_expr[N-1-n]; - assign o[n][2] = i[N-1-n] ~& wide_const[N-1-n]; - assign o_assign[n] = wide_assign[N-1-n]; - assign o_swizzle[n] = 1'(wide_swizzle[n][n+1:n]); - end - - for (genvar n = 0; n < 65; ++n) begin - assign o_small[n] = i[n] ^ wide_small[n]; - end - - for (genvar n = 0; n < N; ++n) begin - always @(posedge clk) begin - o_non_blocking[n] <= wide_const[N-1-n] & wide_non_simple[N-1-n]; - end - end - - assign o_single = i ~| wide_single; - assign o_multiple1 = wide_multiple | i + 1; - assign o_multiple2 = wide_multiple | i + 2; - - sub sub(.i(i), .wide_outside(wide_outside), .o_outside(o_outside)); -endmodule - -module sub(input wire [N-1:0] i, input wire [N-1:0] wide_outside, output logic [N-1:0] o_outside); - initial begin - for (integer n = 0; n < N ; ++n) begin - o_outside[n] = i[N-1-n] | wide_outside[N-1-n]; - end - end -endmodule diff --git a/test_regress/t/t_duplicate_wide_expr.py b/test_regress/t/t_gate_inline_wide_exclude_multiple.py similarity index 76% rename from test_regress/t/t_duplicate_wide_expr.py rename to test_regress/t/t_gate_inline_wide_exclude_multiple.py index 1867115dac..516288695e 100755 --- a/test_regress/t/t_duplicate_wide_expr.py +++ b/test_regress/t/t_gate_inline_wide_exclude_multiple.py @@ -11,9 +11,9 @@ test.scenarios('vlt') -test.compile(verilator_flags2=['--stats', '--expand-limit 5']) +test.lint(verilator_flags2=['--stats', '--expand-limit 5']) -test.file_grep(test.stats, r'Optimizations, Gate excluded wide expressions\s+(\d+)', 3) -test.file_grep(test.stats, r'Optimizations, expand wides\s+(\d+)', 162) +test.file_grep(test.stats, r'Optimizations, Gate excluded wide expressions\s+(\d+)', 2) +test.file_grep(test.stats, r'Optimizations, Gate sigs deleted\s+(\d+)', 4) test.passes() diff --git a/test_regress/t/t_gate_inline_wide_exclude_multiple.v b/test_regress/t/t_gate_inline_wide_exclude_multiple.v new file mode 100644 index 0000000000..fc090eb823 --- /dev/null +++ b/test_regress/t/t_gate_inline_wide_exclude_multiple.v @@ -0,0 +1,27 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2024 by Antmicro. +// SPDX-License-Identifier: CC0-1.0 + +localparam N = 256; // Wider than expand limit. + +module t( + input wire [N-1:0] i, + output logic [N-1:0] o_multiple1, + output logic [N-1:0] o_multiple2, + output wire [N-1:0] o + ); + + // Exclude from inline wide expressions referenced multiple times. + wire [N-1:0] wide_multiple_assigns = N >> i; + wire [N-1:0] wide = N << i; + + for (genvar n = 0; n < N - 1; ++n) begin + assign o[n] = i[N-1-n] | wide[N-1-n]; + end + + assign o_multiple1 = wide_multiple_assigns | i + 1; + assign o_multiple2 = wide_multiple_assigns | i + 2; +endmodule + diff --git a/test_regress/t/t_gate_inline_wide_noexclude_arraysel.py b/test_regress/t/t_gate_inline_wide_noexclude_arraysel.py new file mode 100755 index 0000000000..16d0c0d48f --- /dev/null +++ b/test_regress/t/t_gate_inline_wide_noexclude_arraysel.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2024 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 + +import vltest_bootstrap + +test.scenarios('vlt') + +test.lint(verilator_flags2=['--stats', '--expand-limit 5']) + +test.file_grep(test.stats, r'Optimizations, Gate excluded wide expressions\s+(\d+)', 0) +test.file_grep(test.stats, r'Optimizations, Gate sigs deleted\s+(\d+)', 1) + +test.passes() diff --git a/test_regress/t/t_gate_inline_wide_noexclude_arraysel.v b/test_regress/t/t_gate_inline_wide_noexclude_arraysel.v new file mode 100644 index 0000000000..74c7594103 --- /dev/null +++ b/test_regress/t/t_gate_inline_wide_noexclude_arraysel.v @@ -0,0 +1,20 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2024 by Antmicro. +// SPDX-License-Identifier: CC0-1.0 + +module t; + logic [255:0] arrd [0:0] = '{ 1 }; + logic [255:0] y0; + + // Do not exclude from inlining wide arraysels. + always_comb y0 = arrd[0]; + + always_comb begin + if (y0 != 1 && y0 != 0) begin + $stop; + end + end +endmodule + diff --git a/test_regress/t/t_gate_inline_wide_noexclude_const.py b/test_regress/t/t_gate_inline_wide_noexclude_const.py new file mode 100755 index 0000000000..00b053a42f --- /dev/null +++ b/test_regress/t/t_gate_inline_wide_noexclude_const.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2024 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 + +import vltest_bootstrap + +test.scenarios('vlt') + +test.lint(verilator_flags2=['--stats', '--expand-limit 5']) + +test.file_grep(test.stats, r'Optimizations, Gate excluded wide expressions\s+(\d+)', 0) +test.file_grep(test.stats, r'Optimizations, Gate sigs deleted\s+(\d+)', 2) + +test.passes() diff --git a/test_regress/t/t_gate_inline_wide_noexclude_const.v b/test_regress/t/t_gate_inline_wide_noexclude_const.v new file mode 100644 index 0000000000..2f356d1ff9 --- /dev/null +++ b/test_regress/t/t_gate_inline_wide_noexclude_const.v @@ -0,0 +1,20 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2024 by Antmicro. +// SPDX-License-Identifier: CC0-1.0 + +module t; + logic [255:0] arrd = 256'b0; + logic [255:0] y0; + + // Do not exclude from inlining wide variables with const assignments. + always_comb y0 = 256'(arrd[0]); + + always_comb begin + if (y0 != 1 && y0 != 0) begin + $stop; + end + end +endmodule + diff --git a/test_regress/t/t_gate_inline_wide_noexclude_other_scope.py b/test_regress/t/t_gate_inline_wide_noexclude_other_scope.py new file mode 100755 index 0000000000..0226ac927b --- /dev/null +++ b/test_regress/t/t_gate_inline_wide_noexclude_other_scope.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2024 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 + +import vltest_bootstrap + +test.scenarios('vlt') + +test.lint(verilator_flags2=['--stats', '--expand-limit 5']) + +test.file_grep(test.stats, r'Optimizations, Gate excluded wide expressions\s+(\d+)', 0) + +test.passes() diff --git a/test_regress/t/t_gate_inline_wide_noexclude_other_scope.v b/test_regress/t/t_gate_inline_wide_noexclude_other_scope.v new file mode 100644 index 0000000000..2181f9504b --- /dev/null +++ b/test_regress/t/t_gate_inline_wide_noexclude_other_scope.v @@ -0,0 +1,26 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2024 by Antmicro. +// SPDX-License-Identifier: CC0-1.0 + +localparam N = 256; // Wider than expand limit. + +module t( + input wire [N-1:0] i, + output wire [N-1:0] o + ); + + // Do not exclude from inlining wides referenced in different scope. + wire [N-1:0] wide = N ~^ i; + + sub sub(i, wide, o); +endmodule + +module sub(input wire [N-1:0] i, input wire [N-1:0] wide, output logic [N-1:0] o); + initial begin + for (integer n = 0; n < N ; ++n) begin + o[n] = i[N-1-n] | wide[N-1-n]; + end + end +endmodule diff --git a/test_regress/t/t_gate_inline_wide_noexclude_sel.py b/test_regress/t/t_gate_inline_wide_noexclude_sel.py new file mode 100755 index 0000000000..28148d5852 --- /dev/null +++ b/test_regress/t/t_gate_inline_wide_noexclude_sel.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2024 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 + +import vltest_bootstrap + +test.scenarios('vlt') + +test.lint(verilator_flags2=['--stats', '--expand-limit 5']) + +test.file_grep(test.stats, r'Optimizations, Gate excluded wide expressions\s+(\d+)', 1) +test.file_grep(test.stats, r'Optimizations, Gate sigs deleted\s+(\d+)', 9) + +test.passes() diff --git a/test_regress/t/t_gate_inline_wide_noexclude_sel.v b/test_regress/t/t_gate_inline_wide_noexclude_sel.v new file mode 100644 index 0000000000..931ca0d629 --- /dev/null +++ b/test_regress/t/t_gate_inline_wide_noexclude_sel.v @@ -0,0 +1,44 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2024 by Antmicro. +// SPDX-License-Identifier: CC0-1.0 + +module t ( + output reg [1020:0] res1, + output reg [1020:0] res2, + output reg [1022:0] res3, + output reg [1022:0] res4 + ); + always_inline always_inline(res1, res2); + dont_inline dont_inline(res3, res4); +endmodule + +module always_inline( + output reg [1020:0] res1, + output reg [1020:0] res2 + ); + + wire [1023:0] a; + wire [478:0] b; + + assign b = a[510:32]; + assign res1 = {542'b0, b}; + assign res2 = {542'b1, b}; +endmodule + +// SEL does not have proper offset so we do not have guarantee that it will be +// emitted as '[' operator, thus we do not exclude it from inlining. +module dont_inline( + output reg [1022:0] res1, + output reg [1022:0] res2 + ); + + wire [1023:0] a; + wire [480:0] b; + + // LSB % 32 != 0 + assign b = a[510:30]; + assign res1 = {542'b0, b}; + assign res2 = {542'b1, b}; +endmodule diff --git a/test_regress/t/t_gate_inline_wide_noexclude_small_wide.py b/test_regress/t/t_gate_inline_wide_noexclude_small_wide.py new file mode 100755 index 0000000000..0226ac927b --- /dev/null +++ b/test_regress/t/t_gate_inline_wide_noexclude_small_wide.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2024 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 + +import vltest_bootstrap + +test.scenarios('vlt') + +test.lint(verilator_flags2=['--stats', '--expand-limit 5']) + +test.file_grep(test.stats, r'Optimizations, Gate excluded wide expressions\s+(\d+)', 0) + +test.passes() diff --git a/test_regress/t/t_gate_inline_wide_noexclude_small_wide.v b/test_regress/t/t_gate_inline_wide_noexclude_small_wide.v new file mode 100644 index 0000000000..bbb3022a38 --- /dev/null +++ b/test_regress/t/t_gate_inline_wide_noexclude_small_wide.v @@ -0,0 +1,21 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2024 by Antmicro. +// SPDX-License-Identifier: CC0-1.0 + +localparam N = 65; // Wide but narrower than expand limit + +module t( + input wire [N-1:0] i, + output wire [N-1:0] o + ); + + // Do not exclude from inlining wides small enough to be handled by + // V3Expand. + wire [65:0] wide_small = N << i * i / N; + + for (genvar n = 0; n < N; ++n) begin + assign o[n] = i[n] ^ wide_small[n]; + end +endmodule diff --git a/test_regress/t/t_gate_inline_wide_noexclude_varref.py b/test_regress/t/t_gate_inline_wide_noexclude_varref.py new file mode 100755 index 0000000000..bab7603d68 --- /dev/null +++ b/test_regress/t/t_gate_inline_wide_noexclude_varref.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2024 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 + +import vltest_bootstrap + +test.scenarios('vlt') + +test.lint(verilator_flags2=['--stats', '--expand-limit 5']) + +test.file_grep(test.stats, r'Optimizations, Gate excluded wide expressions\s+(\d+)', 0) +test.file_grep(test.stats, r'Optimizations, Gate sigs deleted\s+(\d+)', 3) + +test.passes() diff --git a/test_regress/t/t_gate_inline_wide_noexclude_varref.v b/test_regress/t/t_gate_inline_wide_noexclude_varref.v new file mode 100644 index 0000000000..4b4b94d64a --- /dev/null +++ b/test_regress/t/t_gate_inline_wide_noexclude_varref.v @@ -0,0 +1,17 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2024 by Antmicro. +// SPDX-License-Identifier: CC0-1.0 + +module t(input [255:0] clk); + // Do not exclude from inlining wide reference assignments. + mod1 mod1(clk); + mod2 mod2(clk); +endmodule + +module mod1(input [255:0] clk); +endmodule + +module mod2(input [255:0] clk); +endmodule