Support enum.next with a parameter

This commit is contained in:
Wilson Snyder 2025-08-16 21:06:35 -04:00
parent 36c4a24661
commit 7126293086
5 changed files with 1003 additions and 995 deletions

View File

@ -3550,38 +3550,43 @@ class WidthVisitor final : public VNVisitor {
} }
if (nodep->name() != "name" && nodep->pinsp()) { if (nodep->name() != "name" && nodep->pinsp()) {
AstNodeExpr* const stepp = methodArg(nodep, 0); AstNodeExpr* stepp = methodArg(nodep, 0);
VL_DO_DANGLING(V3Const::constifyParamsNoWarnEdit(stepp), stepp);
stepp = methodArg(nodep, 0);
nodep->fileline()->modifyWarnOff(V3ErrorCode::WIDTHEXPAND, true); nodep->fileline()->modifyWarnOff(V3ErrorCode::WIDTHEXPAND, true);
iterateCheckUInt32(nodep, "argument", stepp, BOTH); iterateCheckUInt32(nodep, "argument", stepp, BOTH);
if (!VN_IS(stepp, Const)) { if (!VN_IS(stepp, Const)) {
stepp->v3fatalSrc("Unsupported: enum next/prev with non-const argument"); stepp->v3warn(E_UNSUPPORTED,
} else { "Unsupported: enum next/prev with non-constant argument");
const uint32_t stepWidth = VN_AS(stepp, Const)->toUInt(); AstNodeExpr* const newp = new AstConst{stepp->fileline(), 1};
if (stepWidth == 0) { stepp->replaceWith(newp);
// Step of 0 "legalizes" like $cast, use .next.prev stepp = newp;
AstMethodCall* const newp = new AstMethodCall{ }
nodep->fileline(), const uint32_t stepWidth = VN_AS(stepp, Const)->toUInt();
new AstMethodCall{nodep->fileline(), nodep->fromp()->unlinkFrBack(), if (stepWidth == 0) {
"next", nullptr}, // Step of 0 "legalizes" like $cast, use .next.prev
"prev", nullptr}; AstMethodCall* const newp = new AstMethodCall{
// No dtype assigned, we will recurse the new method and replace nodep->fileline(),
nodep->replaceWith(newp); new AstMethodCall{nodep->fileline(), nodep->fromp()->unlinkFrBack(),
VL_DO_DANGLING(nodep->deleteTree(), nodep); "next", nullptr},
return; "prev", nullptr};
} else if (stepWidth != 1) { // No dtype assigned, we will recurse the new method and replace
// Unroll of enumVar.next(k) to enumVar.next(1).next(k - 1) nodep->replaceWith(newp);
nodep->pinsp()->unlinkFrBack(); VL_DO_DANGLING(nodep->deleteTree(), nodep);
AstMethodCall* const clonep = nodep->cloneTree(false); return;
VN_AS(stepp, Const)->num().setLong(1); } else if (stepWidth != 1) {
AstConst* const constp = new AstConst(nodep->fileline(), stepWidth - 1); // Unroll of enumVar.next(k) to enumVar.next(1).next(k - 1)
AstArg* const argp = new AstArg{nodep->fileline(), "", constp}; nodep->pinsp()->unlinkFrBack();
AstMethodCall* const newp AstMethodCall* const clonep = nodep->cloneTree(false);
= new AstMethodCall{nodep->fileline(), clonep, nodep->name(), argp}; VN_AS(stepp, Const)->num().setLong(1);
// No dtype assigned, we will recurse the new method and replace AstConst* const constp = new AstConst(nodep->fileline(), stepWidth - 1);
nodep->replaceWith(newp); AstArg* const argp = new AstArg{nodep->fileline(), "", constp};
VL_DO_DANGLING(nodep->deleteTree(), nodep); AstMethodCall* const newp
return; = new AstMethodCall{nodep->fileline(), clonep, nodep->name(), argp};
} // No dtype assigned, we will recurse the new method and replace
nodep->replaceWith(newp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
return;
} }
} }
AstNodeExpr* const newp AstNodeExpr* const newp

View File

@ -40,7 +40,7 @@ module t (/*AUTOARG*/
`checkh(e.next(2), E01); `checkh(e.next(2), E01);
`checkh(e.next(1).next(1).next(1), E03); `checkh(e.next(1).next(1).next(1), E03);
`checkh(e.next(1).next(2), E03); `checkh(e.next(1).next(2), E03);
`checkh(e.next(3), E03); `checkh(e.next(THREE), E03);
`checkh(e.prev, E01); `checkh(e.prev, E01);
`checkh(e.prev(1), E01); `checkh(e.prev(1), E01);
`checkh(e.prev(1).prev(1), E04); `checkh(e.prev(1).prev(1), E04);
@ -57,6 +57,8 @@ module t (/*AUTOARG*/
`checks(all, "E01E03E04"); `checks(all, "E01E03E04");
end end
localparam THREE = 3;
// Check runtime // Check runtime
always @ (posedge clk) begin always @ (posedge clk) begin
cyc <= cyc + 1; cyc <= cyc + 1;

View File

@ -1,5 +1,6 @@
%Error: Internal Error: t/t_enum_type_methods_bad.v:24:14: ../V3Width.cpp:#: Unsupported: enum next/prev with non-const argument %Error-UNSUPPORTED: t/t_enum_type_methods_bad.v:24:14: Unsupported: enum next/prev with non-constant argument
: ... note: In instance 't' : ... note: In instance 't'
24 | e.next(increment); 24 | e.next(increment);
| ^~~~~~~~~ | ^~~~~~~~~
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error: Exiting due to

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff