Fix DFG misoptimizing bound checks (#7755)
Signed-off-by: Jakub Michalski <jmichalski@antmicro.com>
This commit is contained in:
parent
964474837f
commit
853ee5df17
|
|
@ -620,6 +620,12 @@ DfgVertex::DfgVertex(DfgGraph& dfg, VDfgType type, FileLine* flp, const DfgDataT
|
|||
dfg.addVertex(*this);
|
||||
}
|
||||
|
||||
bool DfgVertex::unsafe() const {
|
||||
if (is<DfgMux>()) return true;
|
||||
if (is<DfgArraySel>()) return !as<DfgArraySel>()->bitp()->is<DfgConst>();
|
||||
return false;
|
||||
}
|
||||
|
||||
void DfgVertex::typeCheck(const DfgGraph& dfg) const {
|
||||
|
||||
#define CHECK(cond, msg) \
|
||||
|
|
|
|||
|
|
@ -195,6 +195,8 @@ public:
|
|||
UASSERT_OBJ(m_dtype.isPacked(), this, "Non packed vertex has no 'width'");
|
||||
return m_dtype.size();
|
||||
}
|
||||
// Has terminating side-effect
|
||||
bool unsafe() const;
|
||||
|
||||
// Type check vertex (for debugging)
|
||||
void typeCheck(const DfgGraph& dfg) const;
|
||||
|
|
|
|||
|
|
@ -2269,7 +2269,7 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
}
|
||||
|
||||
void visit(DfgLogAnd* const vtxp) override {
|
||||
if (binary(vtxp)) return;
|
||||
if (binary(vtxp) || vtxp->rhsp()->unsafe()) return;
|
||||
|
||||
DfgVertex* const lhsp = vtxp->lhsp();
|
||||
DfgVertex* const rhsp = vtxp->rhsp();
|
||||
|
|
@ -2287,11 +2287,11 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
}
|
||||
|
||||
void visit(DfgLogIf* const vtxp) override {
|
||||
if (binary(vtxp)) return;
|
||||
if (binary(vtxp) || vtxp->rhsp()->unsafe()) return;
|
||||
}
|
||||
|
||||
void visit(DfgLogOr* const vtxp) override {
|
||||
if (binary(vtxp)) return;
|
||||
if (binary(vtxp) || vtxp->rhsp()->unsafe()) return;
|
||||
|
||||
DfgVertex* const lhsp = vtxp->lhsp();
|
||||
DfgVertex* const rhsp = vtxp->rhsp();
|
||||
|
|
@ -2890,13 +2890,13 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
}
|
||||
|
||||
if (vtxp->dtype() == m_bitDType) {
|
||||
if (isSame(condp, thenp)) { // a ? a : b becomes a | b
|
||||
if (isSame(condp, thenp) && !elsep->unsafe()) { // a ? a : b becomes a | b
|
||||
APPLYING(REPLACE_COND_WITH_THEN_BRANCH_COND) {
|
||||
replace(make<DfgOr>(vtxp, condp, elsep));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (isSame(condp, elsep)) { // a ? b : a becomes a & b
|
||||
if (isSame(condp, elsep) && !thenp->unsafe()) { // a ? b : a becomes a & b
|
||||
APPLYING(REPLACE_COND_WITH_ELSE_BRANCH_COND) {
|
||||
replace(make<DfgAnd>(vtxp, condp, thenp));
|
||||
return;
|
||||
|
|
@ -2905,28 +2905,28 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
}
|
||||
|
||||
if (vtxp->width() <= VL_QUADSIZE) {
|
||||
if (isZero(thenp)) { // a ? 0 : b becomes ~a & b
|
||||
if (isZero(thenp) && !elsep->unsafe()) { // a ? 0 : b becomes ~a & b
|
||||
APPLYING(REPLACE_COND_WITH_THEN_BRANCH_ZERO) {
|
||||
DfgVertex* const maskp = replicate(vtxp, make<DfgNot>(condp, condp));
|
||||
replace(make<DfgAnd>(vtxp, maskp, elsep));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (isOnes(thenp)) { // a ? 1 : b becomes a | b
|
||||
if (isOnes(thenp) && !elsep->unsafe()) { // a ? 1 : b becomes a | b
|
||||
APPLYING(REPLACE_COND_WITH_THEN_BRANCH_ONES) {
|
||||
DfgVertex* const maskp = replicate(vtxp, condp);
|
||||
replace(make<DfgOr>(vtxp, maskp, elsep));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (isZero(elsep)) { // a ? b : 0 becomes a & b
|
||||
if (isZero(elsep) && !thenp->unsafe()) { // a ? b : 0 becomes a & b
|
||||
APPLYING(REPLACE_COND_WITH_ELSE_BRANCH_ZERO) {
|
||||
DfgVertex* const maskp = replicate(vtxp, condp);
|
||||
replace(make<DfgAnd>(vtxp, maskp, thenp));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (isOnes(elsep)) { // a ? b : 1 becomes ~a | b
|
||||
if (isOnes(elsep) && !thenp->unsafe()) { // a ? b : 1 becomes ~a | b
|
||||
APPLYING(REPLACE_COND_WITH_ELSE_BRANCH_ONES) {
|
||||
DfgVertex* const maskp = replicate(vtxp, make<DfgNot>(condp, condp));
|
||||
replace(make<DfgOr>(vtxp, maskp, thenp));
|
||||
|
|
@ -2935,7 +2935,8 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
}
|
||||
|
||||
if (DfgOr* const tOrp = thenp->cast<DfgOr>()) {
|
||||
if (isSame(tOrp->lhsp(), elsep)) { // a ? b | c : b becomes b | (a & c)
|
||||
if (isSame(tOrp->lhsp(), elsep)
|
||||
&& !tOrp->rhsp()->unsafe()) { // a ? b | c : b becomes b | (a & c)
|
||||
APPLYING(REPLACE_COND_THEN_OR_LHS) {
|
||||
DfgVertex* const maskp = replicate(vtxp, condp);
|
||||
DfgAnd* const andp = make<DfgAnd>(vtxp, maskp, tOrp->rhsp());
|
||||
|
|
@ -2943,7 +2944,8 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
return;
|
||||
}
|
||||
}
|
||||
if (isSame(tOrp->rhsp(), elsep)) { // a ? b | c : c becomes c | (a & b)
|
||||
if (isSame(tOrp->rhsp(), elsep)
|
||||
&& !tOrp->lhsp()->unsafe()) { // a ? b | c : c becomes c | (a & b)
|
||||
APPLYING(REPLACE_COND_THEN_OR_RHS) {
|
||||
DfgVertex* const maskp = replicate(vtxp, condp);
|
||||
DfgAnd* const andp = make<DfgAnd>(vtxp, maskp, tOrp->lhsp());
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# 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-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=["-runtime-debug"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Antmicro
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
|
||||
module t (
|
||||
input clk
|
||||
);
|
||||
wire mem_wire;
|
||||
bit [15:0] idx = 65535;
|
||||
bit mem_reg[0:34000];
|
||||
assign mem_wire = mem_reg[idx];
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (idx < 65533) begin
|
||||
$display("oob_val %d", mem_wire);
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
else begin
|
||||
idx <= idx - 1;
|
||||
mem_reg[idx] <= 0;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
Loading…
Reference in New Issue