Fix DFG misoptimizing bound checks
Signed-off-by: Jakub Michalski <jmichalski@antmicro.com>
This commit is contained in:
parent
276f2f344d
commit
76e204f261
|
|
@ -620,6 +620,12 @@ DfgVertex::DfgVertex(DfgGraph& dfg, VDfgType type, FileLine* flp, const DfgDataT
|
||||||
dfg.addVertex(*this);
|
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 {
|
void DfgVertex::typeCheck(const DfgGraph& dfg) const {
|
||||||
|
|
||||||
#define CHECK(cond, msg) \
|
#define CHECK(cond, msg) \
|
||||||
|
|
|
||||||
|
|
@ -195,6 +195,8 @@ public:
|
||||||
UASSERT_OBJ(m_dtype.isPacked(), this, "Non packed vertex has no 'width'");
|
UASSERT_OBJ(m_dtype.isPacked(), this, "Non packed vertex has no 'width'");
|
||||||
return m_dtype.size();
|
return m_dtype.size();
|
||||||
}
|
}
|
||||||
|
// Has terminating side-effect
|
||||||
|
bool unsafe() const;
|
||||||
|
|
||||||
// Type check vertex (for debugging)
|
// Type check vertex (for debugging)
|
||||||
void typeCheck(const DfgGraph& dfg) const;
|
void typeCheck(const DfgGraph& dfg) const;
|
||||||
|
|
|
||||||
|
|
@ -2269,7 +2269,7 @@ class V3DfgPeephole final : public DfgVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(DfgLogAnd* const vtxp) override {
|
void visit(DfgLogAnd* const vtxp) override {
|
||||||
if (binary(vtxp)) return;
|
if (binary(vtxp) || vtxp->rhsp()->unsafe()) return;
|
||||||
|
|
||||||
DfgVertex* const lhsp = vtxp->lhsp();
|
DfgVertex* const lhsp = vtxp->lhsp();
|
||||||
DfgVertex* const rhsp = vtxp->rhsp();
|
DfgVertex* const rhsp = vtxp->rhsp();
|
||||||
|
|
@ -2287,11 +2287,11 @@ class V3DfgPeephole final : public DfgVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(DfgLogIf* const vtxp) override {
|
void visit(DfgLogIf* const vtxp) override {
|
||||||
if (binary(vtxp)) return;
|
if (binary(vtxp) || vtxp->rhsp()->unsafe()) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(DfgLogOr* const vtxp) override {
|
void visit(DfgLogOr* const vtxp) override {
|
||||||
if (binary(vtxp)) return;
|
if (binary(vtxp) || vtxp->rhsp()->unsafe()) return;
|
||||||
|
|
||||||
DfgVertex* const lhsp = vtxp->lhsp();
|
DfgVertex* const lhsp = vtxp->lhsp();
|
||||||
DfgVertex* const rhsp = vtxp->rhsp();
|
DfgVertex* const rhsp = vtxp->rhsp();
|
||||||
|
|
@ -2890,13 +2890,13 @@ class V3DfgPeephole final : public DfgVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vtxp->dtype() == m_bitDType) {
|
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) {
|
APPLYING(REPLACE_COND_WITH_THEN_BRANCH_COND) {
|
||||||
replace(make<DfgOr>(vtxp, condp, elsep));
|
replace(make<DfgOr>(vtxp, condp, elsep));
|
||||||
return;
|
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) {
|
APPLYING(REPLACE_COND_WITH_ELSE_BRANCH_COND) {
|
||||||
replace(make<DfgAnd>(vtxp, condp, thenp));
|
replace(make<DfgAnd>(vtxp, condp, thenp));
|
||||||
return;
|
return;
|
||||||
|
|
@ -2905,28 +2905,28 @@ class V3DfgPeephole final : public DfgVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vtxp->width() <= VL_QUADSIZE) {
|
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) {
|
APPLYING(REPLACE_COND_WITH_THEN_BRANCH_ZERO) {
|
||||||
DfgVertex* const maskp = replicate(vtxp, make<DfgNot>(condp, condp));
|
DfgVertex* const maskp = replicate(vtxp, make<DfgNot>(condp, condp));
|
||||||
replace(make<DfgAnd>(vtxp, maskp, elsep));
|
replace(make<DfgAnd>(vtxp, maskp, elsep));
|
||||||
return;
|
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) {
|
APPLYING(REPLACE_COND_WITH_THEN_BRANCH_ONES) {
|
||||||
DfgVertex* const maskp = replicate(vtxp, condp);
|
DfgVertex* const maskp = replicate(vtxp, condp);
|
||||||
replace(make<DfgOr>(vtxp, maskp, elsep));
|
replace(make<DfgOr>(vtxp, maskp, elsep));
|
||||||
return;
|
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) {
|
APPLYING(REPLACE_COND_WITH_ELSE_BRANCH_ZERO) {
|
||||||
DfgVertex* const maskp = replicate(vtxp, condp);
|
DfgVertex* const maskp = replicate(vtxp, condp);
|
||||||
replace(make<DfgAnd>(vtxp, maskp, thenp));
|
replace(make<DfgAnd>(vtxp, maskp, thenp));
|
||||||
return;
|
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) {
|
APPLYING(REPLACE_COND_WITH_ELSE_BRANCH_ONES) {
|
||||||
DfgVertex* const maskp = replicate(vtxp, make<DfgNot>(condp, condp));
|
DfgVertex* const maskp = replicate(vtxp, make<DfgNot>(condp, condp));
|
||||||
replace(make<DfgOr>(vtxp, maskp, thenp));
|
replace(make<DfgOr>(vtxp, maskp, thenp));
|
||||||
|
|
@ -2935,7 +2935,8 @@ class V3DfgPeephole final : public DfgVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DfgOr* const tOrp = thenp->cast<DfgOr>()) {
|
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) {
|
APPLYING(REPLACE_COND_THEN_OR_LHS) {
|
||||||
DfgVertex* const maskp = replicate(vtxp, condp);
|
DfgVertex* const maskp = replicate(vtxp, condp);
|
||||||
DfgAnd* const andp = make<DfgAnd>(vtxp, maskp, tOrp->rhsp());
|
DfgAnd* const andp = make<DfgAnd>(vtxp, maskp, tOrp->rhsp());
|
||||||
|
|
@ -2943,7 +2944,8 @@ class V3DfgPeephole final : public DfgVisitor {
|
||||||
return;
|
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) {
|
APPLYING(REPLACE_COND_THEN_OR_RHS) {
|
||||||
DfgVertex* const maskp = replicate(vtxp, condp);
|
DfgVertex* const maskp = replicate(vtxp, condp);
|
||||||
DfgAnd* const andp = make<DfgAnd>(vtxp, maskp, tOrp->lhsp());
|
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