Support queue[$-1] selects.

This commit is contained in:
Wilson Snyder 2023-04-01 15:23:39 -04:00
parent 90e049c674
commit 9ffd0a4e70
5 changed files with 124 additions and 29 deletions

View File

@ -413,6 +413,10 @@ public:
return m_deque[index]; return m_deque[index];
} }
} }
// Access with an index counted from end (e.g. q[$])
T_Value& atBack(int32_t index) { return at(m_deque.size() - 1 - index); }
const T_Value& atBack(int32_t index) const { return at(m_deque.size() - 1 - index); }
// function void q.insert(index, value); // function void q.insert(index, value);
void insert(int32_t index, const T_Value& value) { void insert(int32_t index, const T_Value& value) {
if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) return; if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) return;
@ -428,6 +432,12 @@ public:
for (int32_t i = lsb; i <= msb; ++i) out.push_back(m_deque[i]); for (int32_t i = lsb; i <= msb; ++i) out.push_back(m_deque[i]);
return out; return out;
} }
VlQueue sliceFrontBack(int32_t lsb, int32_t msb) const {
return slice(lsb, m_deque.size() - 1 - msb);
}
VlQueue sliceBackBack(int32_t lsb, int32_t msb) const {
return slice(m_deque.size() - 1 - lsb, m_deque.size() - 1 - msb);
}
// For save/restore // For save/restore
const_iterator begin() const { return m_deque.begin(); } const_iterator begin() const { return m_deque.begin(); }

View File

@ -1297,15 +1297,15 @@ private:
if (const auto* const varp = VN_CAST(nodep->backp(), Var)) { if (const auto* const varp = VN_CAST(nodep->backp(), Var)) {
if (varp->isParam()) return; // Ok, leave if (varp->isParam()) return; // Ok, leave
} }
// queue_slice[#:$] AstNode* backp = nodep->backp();
if (const auto* const selp = VN_CAST(nodep->backp(), SelExtract)) { if (VN_IS(backp, Sub)) backp = backp->backp();
if (VN_IS(selp->fromp()->dtypep(), QueueDType)) { if (const auto* const selp = VN_CAST(backp, SelExtract)) {
nodep->replaceWith( if (VN_IS(selp->fromp()->dtypep(), QueueDType)) return;
new AstConst(nodep->fileline(), AstConst::Signed32{}, 0x7FFFFFFF));
VL_DO_DANGLING(nodep->deleteTree(), nodep);
return;
}
} }
if (const auto* const selp = VN_CAST(backp, SelBit)) {
if (VN_IS(selp->fromp()->dtypep(), QueueDType)) return;
}
// queue_slice[#:$] and queue_bitsel[$] etc handled in V3WidthSel
nodep->v3warn(E_UNSUPPORTED, "Unsupported/illegal unbounded ('$') in this context."); nodep->v3warn(E_UNSUPPORTED, "Unsupported/illegal unbounded ('$') in this context.");
} }
void visit(AstIsUnbounded* nodep) override { void visit(AstIsUnbounded* nodep) override {

View File

@ -190,6 +190,18 @@ private:
} }
} }
AstNodeExpr* selQueueBackness(AstNode* nodep) {
if (VN_IS(nodep, Unbounded)) { // e.g. "[$]"
return new AstConst{nodep->fileline(), AstConst::Signed32{}, 0};
} else if (VN_IS(nodep, Sub) && VN_IS(VN_CAST(nodep, Sub)->lhsp(), Unbounded)) {
// e.g. "q[$ - 1]", where 1 is subnodep
AstNodeExpr* subrhsp = VN_CAST(nodep, Sub)->rhsp()->unlinkFrBack();
return subrhsp;
} else {
return nullptr;
}
}
void warnTri(AstNode* nodep) { void warnTri(AstNode* nodep) {
if (VN_IS(nodep, Const) && VN_AS(nodep, Const)->num().isFourState()) { if (VN_IS(nodep, Const) && VN_AS(nodep, Const)->num().isFourState()) {
nodep->v3error( nodep->v3error(
@ -250,8 +262,7 @@ private:
VL_DO_DANGLING(pushDeletep(nodep), nodep); VL_DO_DANGLING(pushDeletep(nodep), nodep);
} else if (const AstAssocArrayDType* const adtypep = VN_CAST(ddtypep, AssocArrayDType)) { } else if (const AstAssocArrayDType* const adtypep = VN_CAST(ddtypep, AssocArrayDType)) {
// SELBIT(array, index) -> ASSOCSEL(array, index) // SELBIT(array, index) -> ASSOCSEL(array, index)
AstNodeExpr* const subp = rhsp; AstAssocSel* const newp = new AstAssocSel{nodep->fileline(), fromp, rhsp};
AstAssocSel* const newp = new AstAssocSel{nodep->fileline(), fromp, subp};
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off array reference newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off array reference
if (debug() >= 9) newp->dumpTree("- SELBTn: "); if (debug() >= 9) newp->dumpTree("- SELBTn: ");
nodep->replaceWith(newp); nodep->replaceWith(newp);
@ -259,24 +270,26 @@ private:
} else if (const AstWildcardArrayDType* const adtypep } else if (const AstWildcardArrayDType* const adtypep
= VN_CAST(ddtypep, WildcardArrayDType)) { = VN_CAST(ddtypep, WildcardArrayDType)) {
// SELBIT(array, index) -> WILDCARDSEL(array, index) // SELBIT(array, index) -> WILDCARDSEL(array, index)
AstNodeExpr* const subp = rhsp; AstWildcardSel* const newp = new AstWildcardSel{nodep->fileline(), fromp, rhsp};
AstWildcardSel* const newp = new AstWildcardSel{nodep->fileline(), fromp, subp};
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off array reference newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off array reference
if (debug() >= 9) newp->dumpTree("- SELBTn: "); if (debug() >= 9) newp->dumpTree("- SELBTn: ");
nodep->replaceWith(newp); nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep); VL_DO_DANGLING(pushDeletep(nodep), nodep);
} else if (const AstDynArrayDType* const adtypep = VN_CAST(ddtypep, DynArrayDType)) { } else if (const AstDynArrayDType* const adtypep = VN_CAST(ddtypep, DynArrayDType)) {
// SELBIT(array, index) -> CMETHODCALL(queue, "at", index) // SELBIT(array, index) -> CMETHODCALL(queue, "at", index)
AstNodeExpr* const subp = rhsp; AstCMethodHard* const newp = new AstCMethodHard{nodep->fileline(), fromp, "at", rhsp};
AstCMethodHard* const newp = new AstCMethodHard{nodep->fileline(), fromp, "at", subp};
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off queue reference newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off queue reference
if (debug() >= 9) newp->dumpTree("- SELBTq: "); if (debug() >= 9) newp->dumpTree("- SELBTq: ");
nodep->replaceWith(newp); nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep); VL_DO_DANGLING(pushDeletep(nodep), nodep);
} else if (const AstQueueDType* const adtypep = VN_CAST(ddtypep, QueueDType)) { } else if (const AstQueueDType* const adtypep = VN_CAST(ddtypep, QueueDType)) {
// SELBIT(array, index) -> CMETHODCALL(queue, "at", index) // SELBIT(array, index) -> CMETHODCALL(queue, "at", index)
AstNodeExpr* const subp = rhsp; AstCMethodHard* newp;
AstCMethodHard* const newp = new AstCMethodHard{nodep->fileline(), fromp, "at", subp}; if (AstNodeExpr* const backnessp = selQueueBackness(rhsp)) {
newp = new AstCMethodHard{nodep->fileline(), fromp, "atBack", backnessp};
} else {
newp = new AstCMethodHard{nodep->fileline(), fromp, "at", rhsp};
}
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off queue reference newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off queue reference
if (debug() >= 9) newp->dumpTree("- SELBTq: "); if (debug() >= 9) newp->dumpTree("- SELBTq: ");
nodep->replaceWith(newp); nodep->replaceWith(newp);
@ -338,19 +351,43 @@ private:
V3Const::constifyParamsEdit(nodep->leftp()); // May relink pointed to node V3Const::constifyParamsEdit(nodep->leftp()); // May relink pointed to node
V3Const::constifyParamsEdit(nodep->rightp()); // May relink pointed to node V3Const::constifyParamsEdit(nodep->rightp()); // May relink pointed to node
// if (debug() >= 9) nodep->dumpTree("- SELEX3: "); // if (debug() >= 9) nodep->dumpTree("- SELEX3: ");
AstNodeExpr* const fromp = nodep->fromp()->unlinkFrBack();
const FromData fromdata = fromDataForArray(nodep, fromp);
AstNodeDType* const ddtypep = fromdata.m_dtypep;
const VNumRange fromRange = fromdata.m_fromRange;
if (VN_IS(ddtypep, QueueDType)) {
AstNodeExpr* const qleftp = nodep->rhsp()->unlinkFrBack();
AstNodeExpr* const qrightp = nodep->thsp()->unlinkFrBack();
AstNodeExpr* const qleftBacknessp = selQueueBackness(qleftp);
AstNodeExpr* const qrightBacknessp = selQueueBackness(qrightp);
// Use special methods to refer to back rather than math using
// queue size, this allows a single queue reference, to support
// for equations in side effects that select the queue to
// operate upon.
std::string name = (qleftBacknessp ? "sliceBackBack"
: qrightBacknessp ? "sliceFrontBack"
: "slice");
auto* const newp = new AstCMethodHard{nodep->fileline(), fromp, name,
qleftBacknessp ? qleftBacknessp : qleftp};
newp->addPinsp(qrightBacknessp ? qrightBacknessp : qrightp);
newp->dtypep(ddtypep);
newp->didWidth(true);
newp->protect(false);
UINFO(6, " new " << newp << endl);
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
return;
}
// Non-queue
checkConstantOrReplace(nodep->leftp(), checkConstantOrReplace(nodep->leftp(),
"First value of [a:b] isn't a constant, maybe you want +: or -:"); "First value of [a:b] isn't a constant, maybe you want +: or -:");
checkConstantOrReplace(nodep->rightp(), checkConstantOrReplace(nodep->rightp(),
"Second value of [a:b] isn't a constant, maybe you want +: or -:"); "Second value of [a:b] isn't a constant, maybe you want +: or -:");
AstNodeExpr* const fromp = nodep->fromp()->unlinkFrBack();
AstNodeExpr* const msbp = nodep->rhsp()->unlinkFrBack(); AstNodeExpr* const msbp = nodep->rhsp()->unlinkFrBack();
AstNodeExpr* const lsbp = nodep->thsp()->unlinkFrBack(); AstNodeExpr* const lsbp = nodep->thsp()->unlinkFrBack();
int32_t msb = VN_AS(msbp, Const)->toSInt(); int32_t msb = VN_AS(msbp, Const)->toSInt();
int32_t lsb = VN_AS(lsbp, Const)->toSInt(); int32_t lsb = VN_AS(lsbp, Const)->toSInt();
const int32_t elem = (msb > lsb) ? (msb - lsb + 1) : (lsb - msb + 1); const int32_t elem = (msb > lsb) ? (msb - lsb + 1) : (lsb - msb + 1);
const FromData fromdata = fromDataForArray(nodep, fromp);
AstNodeDType* const ddtypep = fromdata.m_dtypep;
const VNumRange fromRange = fromdata.m_fromRange;
if (VN_IS(ddtypep, UnpackArrayDType)) { if (VN_IS(ddtypep, UnpackArrayDType)) {
// Slice extraction // Slice extraction
if (fromRange.elements() == elem if (fromRange.elements() == elem
@ -453,15 +490,6 @@ private:
// if (debug() >= 9) newp->dumpTree("- SELEXnew: "); // if (debug() >= 9) newp->dumpTree("- SELEXnew: ");
nodep->replaceWith(newp); nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep); VL_DO_DANGLING(pushDeletep(nodep), nodep);
} else if (VN_IS(ddtypep, QueueDType)) {
auto* const newp = new AstCMethodHard{nodep->fileline(), fromp, "slice", msbp};
msbp->addNext(lsbp);
newp->dtypep(ddtypep);
newp->didWidth(true);
newp->protect(false);
UINFO(6, " new " << newp << endl);
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
} else { // nullptr=bad extract, or unknown node type } else { // nullptr=bad extract, or unknown node type
nodep->v3error("Illegal range select; type already selected, or bad dimension: " nodep->v3error("Illegal range select; type already selected, or bad dimension: "
<< "data type is " << fromdata.m_errp->prettyDTypeNameQ()); << "data type is " << fromdata.m_errp->prettyDTypeNameQ());

21
test_regress/t/t_queue_back.pl Executable file
View File

@ -0,0 +1,21 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2022 by Wilson Snyder. 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-License-Identifier: LGPL-3.0-only OR Artistic-2.0
scenarios(simulator => 1);
compile(
);
execute(
check_finished => 1,
);
ok(1);
1;

View File

@ -0,0 +1,36 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2023 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
module t(/*AUTOARG*/);
int q[$];
int r;
initial begin
q = { 20, 30, 40 };
r = q[$];
if (r != 40) $stop;
r = q[$-1];
if (r != 30) $stop;
q = q[0:$-1]; // void'(q.pop_back()) or q.delete(q.size-1)
if (q.size != 2) $stop;
if (q[0] != 20) $stop;
if (q[1] != 30) $stop;
q = { 20, 30, 40 };
q = q[$-1:$];
if (q.size != 2) $stop;
if (q[0] != 30) $stop;
if (q[1] != 40) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule