Fix queue slice LHS assignment being silently discarded (#7270)

This commit is contained in:
Yilou Wang 2026-03-17 20:10:49 +01:00 committed by GitHub
parent 8925762077
commit 3bb0ea63ad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 135 additions and 0 deletions

View File

@ -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(); }

View File

@ -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}, \

View File

@ -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();

View File

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

View File

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