Improve optimization of duplicate wide expressions (#5637)

Prevent inlining of expensive wide expressions in V3Gate (#5637)
This commit is contained in:
Bartłomiej Chmiel 2024-12-11 12:45:31 +01:00 committed by GitHub
parent 9656311521
commit 58ddf997e3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 346 additions and 0 deletions

View File

@ -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:

View 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()

View 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

View 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()

View 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

View 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()

View 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

View 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()

View 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

View 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()

View 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

View 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()

View 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

View 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()

View 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