Optimize labels as final `if` block statements (#5744).

This commit is contained in:
Wilson Snyder 2025-01-25 10:29:35 -05:00
parent 694f2ff7c7
commit 05c7a3b90b
4 changed files with 111 additions and 9 deletions

View File

@ -25,6 +25,7 @@ Verilator 5.033 devel
* Improve hierarchical DPI wrapper scheduling performance (#2583) (#5734). [Bartłomiej Chmiel, Antmicro Ltd.]
* Improve VPI write errors (#5712). [Andrew Nolte]
* Improve `resetall support (#5728) (#5730). [Ethan Sifferman]
* Optimize labels as final `if` block statements (#5744).
* Fix error message when call task as a function (#3089). [Matthew Ballance]
* Fix VPI iteration over hierarchy (#5314) (#5731). [Natan Kreimer]
* Fix constrained random for > 64-bit associative arrays (#5670) (#5682). [Yilou Wang]

View File

@ -2266,6 +2266,19 @@ class ConstVisitor final : public VNVisitor {
}
return false;
}
bool replaceJumpGoNext(AstJumpGo* nodep, AstNode* abovep) {
// If JumpGo has an upper JumpBlock that is to same label, then
// code will by normal sequential operation do the JUMPGO and it
// can be removed.
if (nodep->nextp()) return false; // Label jumps other statements
AstJumpBlock* const aboveBlockp = VN_CAST(abovep, JumpBlock);
if (!aboveBlockp) return false;
if (aboveBlockp != nodep->labelp()->blockp()) return false;
if (aboveBlockp->endStmtsp() != nodep->labelp()) return false;
UINFO(4, "JUMPGO => last remove " << nodep << endl);
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
return true;
}
// Boolean replacements
bool operandBoolShift(const AstNode* nodep) {
@ -3158,8 +3171,9 @@ class ConstVisitor final : public VNVisitor {
nodep->condp(new AstLogAnd{lowerIfp->fileline(), condp, lowerCondp});
lowerIfp->replaceWith(lowerThensp);
VL_DO_DANGLING(pushDeletep(lowerIfp), lowerIfp);
} else if (operandBoolShift(nodep->condp())) {
replaceBoolShift(nodep->condp());
} else {
// Optimizations that don't reform the IF itself
if (operandBoolShift(nodep->condp())) replaceBoolShift(nodep->condp());
}
}
}
@ -3390,14 +3404,14 @@ class ConstVisitor final : public VNVisitor {
}
// If last statement in a jump label we have JumpLabel(...., JumpGo)
// Often caused by "return" in a Verilog function. The Go is pointless, remove.
if (replaceJumpGoNext(nodep, nodep->abovep())) return;
// Also optimize If with a then or else's final statement being this JumpGo
// We only do single ifs... Ideally we'd look at control flow and delete any
// Jumps where any following control flow point is the label
if (!nodep->nextp()) {
if (AstJumpBlock* const aboveBlockp = VN_CAST(nodep->abovep(), JumpBlock)) {
if (aboveBlockp == nodep->labelp()->blockp()) {
if (aboveBlockp->endStmtsp() == nodep->labelp()) {
UINFO(4, "JUMPGO => last remove " << nodep << endl);
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
return;
}
if (AstNodeIf* const aboveIfp = VN_CAST(nodep->abovep(), NodeIf)) {
if (!aboveIfp->nextp()) {
if (replaceJumpGoNext(nodep, aboveIfp->abovep())) return;
}
}
}

View File

@ -0,0 +1,20 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2025 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('simulator')
test.compile(verilator_flags2=['--stats'])
test.file_grep(test.stats, r'Node count, JUMPGO + 3 *$')
test.execute()
test.passes()

View File

@ -0,0 +1,67 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2025 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
class uvm_object;
endclass
class uvm_callback;
endclass
class uvm_callbacks #(type T=uvm_object, type CB=uvm_callback);
bit m_registered = 1;
virtual function bit m_is_registered(uvm_object obj, uvm_callback cb);
if (m_is_for_me(cb) && m_am_i_a(obj)) begin
return m_registered;
end
endfunction
virtual function bit m_is_for_me(uvm_callback cb);
CB this_cb;
// verilator lint_off WIDTHTRUNC
return ($cast(this_cb, cb));
// verilator lint_on WIDTHTRUNC
endfunction
virtual function bit m_am_i_a(uvm_object obj);
T this_t;
// verilator lint_off WIDTHTRUNC
return ($cast(this_t, obj));
// verilator lint_on WIDTHTRUNC
endfunction
endclass
class my_object extends uvm_object;
endclass
class my_callback extends uvm_callback;
endclass
class other_object extends uvm_object;
endclass
module t;
initial begin
my_object obj;
other_object oobj;
my_callback cb;
uvm_callbacks#(my_object, my_callback) ucs;
bit i;
obj = new;
oobj = new;
cb = new;
ucs = new;
i = ucs.m_is_registered(obj, cb);
if (i !== 1) $stop;
i = ucs.m_is_registered(oobj, cb);
if (i !== 0) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule