mirror of
https://github.com/verilator/verilator.git
synced 2024-12-28 18:27:34 +00:00
Improve optimization of duplicate wide expressions (#5637)
Prevent inlining of expensive wide expressions in V3Gate (#5637)
This commit is contained in:
parent
9656311521
commit
58ddf997e3
@ -681,8 +681,44 @@ class GateInline final {
|
||||
std::unordered_map<AstNode*, size_t> 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<GateLogicVertex>();
|
||||
|
||||
// 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<GateLogicVertex>();
|
||||
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:
|
||||
|
19
test_regress/t/t_gate_inline_wide_exclude_multiple.py
Executable file
19
test_regress/t/t_gate_inline_wide_exclude_multiple.py
Executable file
@ -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()
|
26
test_regress/t/t_gate_inline_wide_exclude_multiple.v
Normal file
26
test_regress/t/t_gate_inline_wide_exclude_multiple.v
Normal file
@ -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
|
19
test_regress/t/t_gate_inline_wide_noexclude_arraysel.py
Executable file
19
test_regress/t/t_gate_inline_wide_noexclude_arraysel.py
Executable file
@ -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()
|
19
test_regress/t/t_gate_inline_wide_noexclude_arraysel.v
Normal file
19
test_regress/t/t_gate_inline_wide_noexclude_arraysel.v
Normal file
@ -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
|
19
test_regress/t/t_gate_inline_wide_noexclude_const.py
Executable file
19
test_regress/t/t_gate_inline_wide_noexclude_const.py
Executable file
@ -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()
|
19
test_regress/t/t_gate_inline_wide_noexclude_const.v
Normal file
19
test_regress/t/t_gate_inline_wide_noexclude_const.v
Normal file
@ -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
|
18
test_regress/t/t_gate_inline_wide_noexclude_other_scope.py
Executable file
18
test_regress/t/t_gate_inline_wide_noexclude_other_scope.py
Executable file
@ -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()
|
26
test_regress/t/t_gate_inline_wide_noexclude_other_scope.v
Normal file
26
test_regress/t/t_gate_inline_wide_noexclude_other_scope.v
Normal file
@ -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
|
19
test_regress/t/t_gate_inline_wide_noexclude_sel.py
Executable file
19
test_regress/t/t_gate_inline_wide_noexclude_sel.py
Executable file
@ -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()
|
44
test_regress/t/t_gate_inline_wide_noexclude_sel.v
Normal file
44
test_regress/t/t_gate_inline_wide_noexclude_sel.v
Normal file
@ -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
|
18
test_regress/t/t_gate_inline_wide_noexclude_small_wide.py
Executable file
18
test_regress/t/t_gate_inline_wide_noexclude_small_wide.py
Executable file
@ -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()
|
21
test_regress/t/t_gate_inline_wide_noexclude_small_wide.v
Normal file
21
test_regress/t/t_gate_inline_wide_noexclude_small_wide.v
Normal file
@ -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
|
19
test_regress/t/t_gate_inline_wide_noexclude_varref.py
Executable file
19
test_regress/t/t_gate_inline_wide_noexclude_varref.py
Executable file
@ -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()
|
17
test_regress/t/t_gate_inline_wide_noexclude_varref.v
Normal file
17
test_regress/t/t_gate_inline_wide_noexclude_varref.v
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user