Fix streaming with descending unpacked arrays and unpacked-to-queue (#7287)

This commit is contained in:
Yilou Wang 2026-03-20 14:51:35 +01:00 committed by GitHub
parent 9180eebdba
commit 998ec5b1d7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 133 additions and 11 deletions

View File

@ -2417,6 +2417,46 @@ static inline void VL_REVCOPY_Q(VlQueue<T>& q, const VlQueue<T>& from, int lbits
}
}
// Reverse element order of an unpacked array in-place.
// Used by emitter for descending-range arrays after VL_UNPACK_*.
template <typename T_Value, std::size_t N_Depth>
static inline void VL_UNPACK_REVERSED(VlUnpacked<T_Value, N_Depth>& q) {
for (size_t i = 0; i < N_Depth / 2; ++i) {
const T_Value tmp = q[i];
q[i] = q[N_Depth - 1 - i];
q[N_Depth - 1 - i] = tmp;
}
}
// Return a reversed copy of an unpacked array.
// Used by emitter for descending-range arrays before VL_PACK_*.
template <typename T_Value, std::size_t N_Depth>
static inline VlUnpacked<T_Value, N_Depth>
VL_PACK_REVERSED(const VlUnpacked<T_Value, N_Depth>& q) {
VlUnpacked<T_Value, N_Depth> ret;
for (size_t i = 0; i < N_Depth; ++i) ret[i] = q[N_Depth - 1 - i];
return ret;
}
// Overloads for VlUnpacked source -> VlQueue destination
template <typename T, std::size_t N_Depth>
static inline void VL_COPY_Q(VlQueue<T>& q, const VlUnpacked<T, N_Depth>& from, int lbits,
int srcElementBits, int dstElementBits) {
VlQueue<T> srcQ;
srcQ.renew(N_Depth);
for (size_t i = 0; i < N_Depth; ++i) srcQ.atWrite(i) = from[i];
VL_COPY_Q(q, srcQ, lbits, srcElementBits, dstElementBits);
}
template <typename T, std::size_t N_Depth>
static inline void VL_REVCOPY_Q(VlQueue<T>& q, const VlUnpacked<T, N_Depth>& from, int lbits,
int srcElementBits, int dstElementBits) {
VlQueue<T> srcQ;
srcQ.renew(N_Depth);
for (size_t i = 0; i < N_Depth; ++i) srcQ.atWrite(i) = from[N_Depth - 1 - i];
VL_COPY_Q(q, srcQ, lbits, srcElementBits, dstElementBits);
}
//======================================================================
// Expressions needing insert/select

View File

@ -2389,6 +2389,32 @@ class ConstVisitor final : public VNVisitor {
AstNodeDType* const dstDTypep = dstp->dtypep()->skipRefp();
AstNodeExpr* const srcp = nodep->rhsp()->unlinkFrBack();
const AstNodeDType* const srcDTypep = srcp->dtypep()->skipRefp();
// Handle unpacked/queue/dynarray source -> queue/dynarray dest via
// CvtArrayToArray (StreamL reverses, so reverse=true)
if ((VN_IS(srcDTypep, UnpackArrayDType) || VN_IS(srcDTypep, QueueDType)
|| VN_IS(srcDTypep, DynArrayDType))
&& (VN_IS(dstDTypep, QueueDType) || VN_IS(dstDTypep, DynArrayDType))) {
int blockSize = 1;
if (const AstConst* const constp
= VN_CAST(VN_AS(streamp, StreamL)->rhsp(), Const)) {
blockSize = constp->toSInt();
if (VL_UNLIKELY(blockSize <= 0)) blockSize = 1;
}
int srcElementBits = 0;
if (const AstNodeDType* const elemDtp = srcDTypep->subDTypep()) {
srcElementBits = elemDtp->width();
}
int dstElementBits = 0;
if (const AstNodeDType* const elemDtp = dstDTypep->subDTypep()) {
dstElementBits = elemDtp->width();
}
nodep->lhsp(dstp);
nodep->rhsp(new AstCvtArrayToArray{srcp->fileline(), srcp, dstDTypep, true,
blockSize, dstElementBits, srcElementBits});
nodep->dtypep(dstDTypep);
VL_DO_DANGLING(pushDeletep(streamp), streamp);
return true;
}
const int sWidth = srcp->width();
const int dWidth = dstp->width();
// Connect the rhs to the stream operator and update its width
@ -2420,6 +2446,44 @@ class ConstVisitor final : public VNVisitor {
AstNodeExpr* const dstp = VN_AS(streamp, StreamR)->lhsp()->unlinkFrBack();
AstNodeDType* const dstDTypep = dstp->dtypep()->skipRefp();
AstNodeExpr* srcp = nodep->rhsp()->unlinkFrBack();
// Handle unpacked/queue/dynarray source -> queue/dynarray dest via
// CvtArrayToArray (StreamR does not reverse, so reverse=false).
// V3Width may have wrapped the source in CvtArrayToPacked; unwrap it.
if (VN_IS(dstDTypep, QueueDType) || VN_IS(dstDTypep, DynArrayDType)) {
AstNodeExpr* origSrcp = srcp;
if (AstCvtArrayToPacked* const cvtp = VN_CAST(srcp, CvtArrayToPacked)) {
origSrcp = cvtp->fromp();
}
const AstNodeDType* const origSrcDTypep = origSrcp->dtypep()->skipRefp();
if (VN_IS(origSrcDTypep, UnpackArrayDType) || VN_IS(origSrcDTypep, QueueDType)
|| VN_IS(origSrcDTypep, DynArrayDType)) {
int srcElementBits = 0;
if (const AstNodeDType* const elemDtp = origSrcDTypep->subDTypep()) {
srcElementBits = elemDtp->width();
}
int dstElementBits = 0;
if (const AstNodeDType* const elemDtp = dstDTypep->subDTypep()) {
dstElementBits = elemDtp->width();
}
if (VN_IS(srcp, CvtArrayToPacked)) {
origSrcp = VN_AS(srcp, CvtArrayToPacked)->fromp()->unlinkFrBack();
VL_DO_DANGLING(pushDeletep(srcp), srcp);
srcp = origSrcp;
}
// Descending unpacked arrays need element reversal
bool reverse = false;
if (const AstUnpackArrayDType* const unpackDtp
= VN_CAST(origSrcDTypep, UnpackArrayDType)) {
reverse = !unpackDtp->declRange().ascending();
}
nodep->lhsp(dstp);
nodep->rhsp(new AstCvtArrayToArray{srcp->fileline(), srcp, dstDTypep, reverse,
1, dstElementBits, srcElementBits});
nodep->dtypep(dstDTypep);
VL_DO_DANGLING(pushDeletep(streamp), streamp);
return true;
}
}
const int sWidth = srcp->width();
const int dWidth = dstp->width();
if (VN_IS(dstDTypep, UnpackArrayDType)) {

View File

@ -456,12 +456,23 @@ public:
void visit(AstCvtArrayToPacked* nodep) override {
AstNodeDType* const fromDtp = nodep->fromp()->dtypep()->skipRefp();
AstNodeDType* const elemDtp = fromDtp->subDTypep()->skipRefp();
const bool descending = [&]() {
if (const AstUnpackArrayDType* const unpackDtp = VN_CAST(fromDtp, UnpackArrayDType))
return !unpackDtp->declRange().ascending();
return false;
}();
puts("VL_PACK_");
emitIQW(nodep);
puts("_");
emitRU(fromDtp);
emitIQW(elemDtp);
emitOpName(nodep, "(%nw, %rw, %P, %li)", nodep->fromp(), elemDtp, nullptr);
if (descending) {
// Wrap source in VL_PACK_REVERSED so VL_PACK sees ascending order
emitOpName(nodep, "(%nw, %rw, %P, VL_PACK_REVERSED(%li))", nodep->fromp(), elemDtp,
nullptr);
} else {
emitOpName(nodep, "(%nw, %rw, %P, %li)", nodep->fromp(), elemDtp, nullptr);
}
}
void visit(AstCvtUnpackedToQueue* nodep) override {
@ -499,6 +510,7 @@ public:
bool paren = true;
bool decind = false;
bool rhs = true;
bool reverseUnpack = false; // Set for descending CvtPackedToArray
if (AstSel* const selp = VN_CAST(nodep->lhsp(), Sel)) {
UASSERT_OBJ(selp->widthMin() == selp->widthConst(), selp, "Width mismatch");
if (selp->widthMin() == 1) {
@ -567,6 +579,11 @@ public:
puts(", ");
rhs = false;
iterateAndNextConstNull(castp->fromp());
// Descending unpacked dest: reverse after unpack
if (const AstUnpackArrayDType* const unpackDtp
= VN_CAST(nodep->dtypep()->skipRefp(), UnpackArrayDType)) {
if (!unpackDtp->declRange().ascending()) reverseUnpack = true;
}
} else if (const AstCvtArrayToArray* const castp
= VN_CAST(nodep->rhsp(), CvtArrayToArray)) {
if (castp->reverse()) {
@ -618,6 +635,11 @@ public:
if (paren) puts(")");
if (decind) ofp()->blockDec();
puts(";\n");
if (reverseUnpack) {
puts("VL_UNPACK_REVERSED(");
iterateAndNextConstNull(nodep->lhsp());
puts(");\n");
}
}
void visit(AstAssocSel* nodep) override {
iterateAndNextConstNull(nodep->fromp());

View File

@ -111,23 +111,19 @@ module t (
// 2D packed array into unpacked array
if (unpacked_siz_dout != '{8'h01, 8'h23, 8'h45, 8'h67}) $stop;
if (unpacked_asc_dout != '{8'h01, 8'h23, 8'h45, 8'h67}) $stop;
// TODO: VL_UNPACK does not account for descending unpacked array
// index direction -- re-enable once fixed.
// if (unpacked_des_dout != '{8'h76, 8'h54, 8'h32, 8'h10}) $stop;
if (unpacked_des_dout != '{8'h76, 8'h54, 8'h32, 8'h10}) $stop;
// 2D unpacked array into packed array
if (packed_siz_dout != '{8'h01, 8'h23, 8'h45, 8'h67}) $stop;
if (packed_asc_dout != '{8'h01, 8'h23, 8'h45, 8'h67}) $stop;
// TODO: Descending-range packed array streaming + pattern comparison
// if (packed_des_dout != '{8'h76, 8'h54, 8'h32, 8'h10}) $stop;
if (packed_des_dout != '{8'h76, 8'h54, 8'h32, 8'h10}) $stop;
// 2D packed array into queue
if (packed_siz_queue_dout != '{8'h01, 8'h23, 8'h45, 8'h67}) $stop;
if (packed_asc_queue_dout != '{8'h01, 8'h23, 8'h45, 8'h67}) $stop;
if (packed_des_queue_dout != '{8'h76, 8'h54, 8'h32, 8'h10}) $stop;
// TODO: Streaming from unpacked array into queue produces empty
// queue -- re-enable once fixed.
// if (unpacked_siz_queue_dout != '{8'h01, 8'h23, 8'h45, 8'h67}) $stop;
// if (unpacked_asc_queue_dout != '{8'h01, 8'h23, 8'h45, 8'h67}) $stop;
// if (unpacked_des_queue_dout != '{8'h76, 8'h54, 8'h32, 8'h10}) $stop;
// 2D unpacked array into queue
if (unpacked_siz_queue_dout != '{8'h01, 8'h23, 8'h45, 8'h67}) $stop;
if (unpacked_asc_queue_dout != '{8'h01, 8'h23, 8'h45, 8'h67}) $stop;
if (unpacked_des_queue_dout != '{8'h76, 8'h54, 8'h32, 8'h10}) $stop;
end
if (cyc == 3) begin