diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index 1ddac0799..d5dfbaad4 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -681,8 +681,44 @@ class GateInline final { std::unordered_map m_hasPending; size_t m_statInlined = 0; // Statistic tracking - signals inlined size_t m_statRefs = 0; // Statistic tracking + size_t m_statExcluded = 0; // Statistic tracking // METHODS + static bool isCheapWide(const AstNodeExpr* exprp) { + if (const AstSel* const selp = VN_CAST(exprp, Sel)) { + if (selp->lsbConst() % VL_EDATASIZE != 0) return false; + exprp = selp->fromp(); + } + if (const AstArraySel* const aselp = VN_CAST(exprp, ArraySel)) exprp = aselp->fromp(); + return VN_IS(exprp, Const) || VN_IS(exprp, NodeVarRef); + } + static bool excludedWide(GateVarVertex* const vVtxp, const AstNodeExpr* const rhsp) { + // Handle wides with logic drivers that are too wide for V3Expand. + if (!vVtxp->varScp()->isWide() // + || vVtxp->varScp()->widthWords() <= v3Global.opt.expandLimit() // + || vVtxp->inEmpty() // + || isCheapWide(rhsp)) + return false; + + const GateLogicVertex* const lVtxp + = vVtxp->inEdges().frontp()->fromp()->as(); + + // Exclude from inlining variables READ multiple times. + // To decouple actives thus simplifying scheduling, exclude only those + // VarRefs that are referenced under the same active as they were assigned. + if (const AstActive* const primaryActivep = lVtxp->activep()) { + size_t reads = 0; + for (const V3GraphEdge& edge : vVtxp->outEdges()) { + const GateLogicVertex* const lvp = edge.top()->as(); + if (lvp->activep() != primaryActivep) continue; + + reads += edge.weight(); + if (reads > 1) return true; + } + } + return false; + } + void recordSubstitution(AstVarScope* vscp, AstNodeExpr* substp, AstNode* logicp) { m_hasPending.emplace(logicp, ++m_ord); // It's OK if already present const auto pair = m_substitutions(logicp).emplace(vscp, nullptr); @@ -777,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) { @@ -876,6 +918,7 @@ class GateInline final { ~GateInline() { V3Stats::addStat("Optimizations, Gate sigs deleted", m_statInlined); V3Stats::addStat("Optimizations, Gate inputs replaced", m_statRefs); + V3Stats::addStat("Optimizations, Gate excluded wide expressions", m_statExcluded); } public: diff --git a/test_regress/t/t_gate_inline_wide_exclude_multiple.py b/test_regress/t/t_gate_inline_wide_exclude_multiple.py new file mode 100755 index 000000000..516288695 --- /dev/null +++ b/test_regress/t/t_gate_inline_wide_exclude_multiple.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+)', 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 000000000..5e2ae1a80 --- /dev/null +++ b/test_regress/t/t_gate_inline_wide_exclude_multiple.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 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 000000000..16d0c0d48 --- /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 000000000..282929316 --- /dev/null +++ b/test_regress/t/t_gate_inline_wide_noexclude_arraysel.v @@ -0,0 +1,19 @@ +// 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 000000000..00b053a42 --- /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 000000000..d45648982 --- /dev/null +++ b/test_regress/t/t_gate_inline_wide_noexclude_const.v @@ -0,0 +1,19 @@ +// 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 000000000..0226ac927 --- /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 000000000..2181f9504 --- /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 000000000..28148d585 --- /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 000000000..931ca0d62 --- /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 000000000..0226ac927 --- /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 000000000..bbb3022a3 --- /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 000000000..bab7603d6 --- /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 000000000..4b4b94d64 --- /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