Fix queue slice LHS assignment being silently discarded (#7270)
This commit is contained in:
parent
8925762077
commit
3bb0ea63ad
|
|
@ -638,6 +638,24 @@ public:
|
|||
VlQueue sliceBackBack(int32_t lsb, int32_t msb) const {
|
||||
return slice(m_deque.size() - 1 - lsb, m_deque.size() - 1 - msb);
|
||||
}
|
||||
// Assign src elements to q[lsb:msb]
|
||||
void sliceAssign(int32_t lsb, int32_t msb, const VlQueue& src) {
|
||||
const int32_t sz = static_cast<int32_t>(m_deque.size());
|
||||
const int32_t srcSz = static_cast<int32_t>(src.m_deque.size());
|
||||
if (VL_UNLIKELY(sz <= 0 || srcSz <= 0)) return;
|
||||
if (VL_UNLIKELY(lsb < 0)) lsb = 0;
|
||||
if (VL_UNLIKELY(lsb >= sz)) lsb = sz - 1;
|
||||
if (VL_UNLIKELY(msb >= sz)) msb = sz - 1;
|
||||
const int32_t count = std::min(msb - lsb + 1, srcSz);
|
||||
if (VL_UNLIKELY(count <= 0)) return;
|
||||
std::copy_n(src.m_deque.begin(), count, m_deque.begin() + lsb);
|
||||
}
|
||||
void sliceAssignFrontBack(int32_t lsb, int32_t msb, const VlQueue& src) {
|
||||
sliceAssign(lsb, m_deque.size() - 1 - msb, src);
|
||||
}
|
||||
void sliceAssignBackBack(int32_t lsb, int32_t msb, const VlQueue& src) {
|
||||
sliceAssign(m_deque.size() - 1 - lsb, m_deque.size() - 1 - msb, src);
|
||||
}
|
||||
|
||||
// For save/restore
|
||||
const_iterator begin() const { return m_deque.begin(); }
|
||||
|
|
|
|||
|
|
@ -802,6 +802,9 @@ public:
|
|||
DYN_RESIZE,
|
||||
DYN_SIZE,
|
||||
DYN_SLICE,
|
||||
DYN_SLICE_ASSIGN,
|
||||
DYN_SLICE_ASSIGN_BACK_BACK,
|
||||
DYN_SLICE_ASSIGN_FRONT_BACK,
|
||||
DYN_SLICE_BACK_BACK,
|
||||
DYN_SLICE_FRONT_BACK,
|
||||
EVENT_CLEAR_FIRED,
|
||||
|
|
@ -943,6 +946,9 @@ inline std::ostream& operator<<(std::ostream& os, const VCMethod& rhs) {
|
|||
{DYN_RESIZE, "resize", false}, \
|
||||
{DYN_SIZE, "size", true}, \
|
||||
{DYN_SLICE, "slice", true}, \
|
||||
{DYN_SLICE_ASSIGN, "sliceAssign", false}, \
|
||||
{DYN_SLICE_ASSIGN_BACK_BACK, "sliceAssignBackBack", false}, \
|
||||
{DYN_SLICE_ASSIGN_FRONT_BACK, "sliceAssignFrontBack", false}, \
|
||||
{DYN_SLICE_BACK_BACK, "sliceBackBack", true}, \
|
||||
{DYN_SLICE_FRONT_BACK, "sliceFrontBack", true}, \
|
||||
{EVENT_CLEAR_FIRED, "clearFired", false}, \
|
||||
|
|
|
|||
|
|
@ -6026,6 +6026,42 @@ class WidthVisitor final : public VNVisitor {
|
|||
return;
|
||||
}
|
||||
|
||||
// Queue slice on LHS: q[a:b] = rhs -> q.sliceAssign(a, b, rhs)
|
||||
// The LHS was lowered from AstSelExtract to CMethodHard(DYN_SLICE)
|
||||
// by V3WidthSel; that returns a temporary copy so the assignment is
|
||||
// silently discarded. Transform into a mutating sliceAssign call.
|
||||
if (AstCMethodHard* const slicep = VN_CAST(nodep->lhsp(), CMethodHard)) {
|
||||
VCMethod assignMethod;
|
||||
if (slicep->method() == VCMethod::DYN_SLICE) {
|
||||
assignMethod = VCMethod::DYN_SLICE_ASSIGN;
|
||||
} else if (slicep->method() == VCMethod::DYN_SLICE_BACK_BACK) {
|
||||
assignMethod = VCMethod::DYN_SLICE_ASSIGN_BACK_BACK;
|
||||
} else if (slicep->method() == VCMethod::DYN_SLICE_FRONT_BACK) {
|
||||
assignMethod = VCMethod::DYN_SLICE_ASSIGN_FRONT_BACK;
|
||||
} else {
|
||||
assignMethod = VCMethod::_ENUM_MAX; // not a slice
|
||||
}
|
||||
if (assignMethod != VCMethod::_ENUM_MAX) {
|
||||
UINFO(9, "LHS queue slice -> sliceAssign: " << nodep);
|
||||
AstNodeExpr* const fromp = slicep->fromp()->unlinkFrBack();
|
||||
// Collect existing slice index pins (lsb, msb)
|
||||
AstNodeExpr* const lsbp = slicep->pinsp()->unlinkFrBack();
|
||||
AstNodeExpr* const msbp = slicep->pinsp()->unlinkFrBack();
|
||||
AstNodeExpr* const rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstCMethodHard* const newp
|
||||
= new AstCMethodHard{nodep->fileline(), fromp, assignMethod};
|
||||
newp->addPinsp(lsbp);
|
||||
newp->addPinsp(msbp);
|
||||
newp->addPinsp(rhsp);
|
||||
newp->didWidth(true);
|
||||
newp->protect(false);
|
||||
newp->dtypeSetVoid();
|
||||
nodep->replaceWith(newp->makeStmt());
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (nodep->hasDType() && nodep->dtypep()->isEvent()) {
|
||||
checkEventAssignment(nodep);
|
||||
v3Global.setAssignsEvents();
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 PlanV GmbH
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
`define stop $stop
|
||||
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
||||
|
||||
module t;
|
||||
initial begin
|
||||
int q[$];
|
||||
|
||||
// Basic slice assignment: overwrite middle elements
|
||||
q = '{10, 20, 30, 40, 50};
|
||||
q[1:3] = '{99, 88, 77};
|
||||
`checkh(q[0], 10);
|
||||
`checkh(q[1], 99);
|
||||
`checkh(q[2], 88);
|
||||
`checkh(q[3], 77);
|
||||
`checkh(q[4], 50);
|
||||
`checkh(q.size, 5);
|
||||
|
||||
// Slice assignment at start
|
||||
q = '{10, 20, 30, 40, 50};
|
||||
q[0:1] = '{11, 22};
|
||||
`checkh(q[0], 11);
|
||||
`checkh(q[1], 22);
|
||||
`checkh(q[2], 30);
|
||||
`checkh(q[3], 40);
|
||||
`checkh(q[4], 50);
|
||||
|
||||
// Slice assignment at end
|
||||
q = '{10, 20, 30, 40, 50};
|
||||
q[3:4] = '{44, 55};
|
||||
`checkh(q[0], 10);
|
||||
`checkh(q[1], 20);
|
||||
`checkh(q[2], 30);
|
||||
`checkh(q[3], 44);
|
||||
`checkh(q[4], 55);
|
||||
|
||||
// Single-element slice
|
||||
q = '{10, 20, 30, 40, 50};
|
||||
q[2:2] = '{66};
|
||||
`checkh(q[0], 10);
|
||||
`checkh(q[1], 20);
|
||||
`checkh(q[2], 66);
|
||||
`checkh(q[3], 40);
|
||||
`checkh(q[4], 50);
|
||||
|
||||
// Verify size unchanged after all operations
|
||||
`checkh(q.size, 5);
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
Loading…
Reference in New Issue