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()) {
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);
iterateCheckUInt32(nodep, "argument", stepp, BOTH);
if (!VN_IS(stepp, Const)) {
stepp->v3fatalSrc("Unsupported: enum next/prev with non-const argument");
} else {
const uint32_t stepWidth = VN_AS(stepp, Const)->toUInt();
if (stepWidth == 0) {
// Step of 0 "legalizes" like $cast, use .next.prev
AstMethodCall* const newp = new AstMethodCall{
nodep->fileline(),
new AstMethodCall{nodep->fileline(), nodep->fromp()->unlinkFrBack(),
"next", nullptr},
"prev", nullptr};
// No dtype assigned, we will recurse the new method and replace
nodep->replaceWith(newp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
return;
} else if (stepWidth != 1) {
// Unroll of enumVar.next(k) to enumVar.next(1).next(k - 1)
nodep->pinsp()->unlinkFrBack();
AstMethodCall* const clonep = nodep->cloneTree(false);
VN_AS(stepp, Const)->num().setLong(1);
AstConst* const constp = new AstConst(nodep->fileline(), stepWidth - 1);
AstArg* const argp = new AstArg{nodep->fileline(), "", constp};
AstMethodCall* const newp
= 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;
}
stepp->v3warn(E_UNSUPPORTED,
"Unsupported: enum next/prev with non-constant argument");
AstNodeExpr* const newp = new AstConst{stepp->fileline(), 1};
stepp->replaceWith(newp);
stepp = newp;
}
const uint32_t stepWidth = VN_AS(stepp, Const)->toUInt();
if (stepWidth == 0) {
// Step of 0 "legalizes" like $cast, use .next.prev
AstMethodCall* const newp = new AstMethodCall{
nodep->fileline(),
new AstMethodCall{nodep->fileline(), nodep->fromp()->unlinkFrBack(),
"next", nullptr},
"prev", nullptr};
// No dtype assigned, we will recurse the new method and replace
nodep->replaceWith(newp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
return;
} else if (stepWidth != 1) {
// Unroll of enumVar.next(k) to enumVar.next(1).next(k - 1)
nodep->pinsp()->unlinkFrBack();
AstMethodCall* const clonep = nodep->cloneTree(false);
VN_AS(stepp, Const)->num().setLong(1);
AstConst* const constp = new AstConst(nodep->fileline(), stepWidth - 1);
AstArg* const argp = new AstArg{nodep->fileline(), "", constp};
AstMethodCall* const newp
= 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

View File

@ -40,7 +40,7 @@ module t (/*AUTOARG*/
`checkh(e.next(2), E01);
`checkh(e.next(1).next(1).next(1), 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(1), E01);
`checkh(e.prev(1).prev(1), E04);
@ -57,6 +57,8 @@ module t (/*AUTOARG*/
`checks(all, "E01E03E04");
end
localparam THREE = 3;
// Check runtime
always @ (posedge clk) begin
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
: ... note: In instance 't'
%Error-UNSUPPORTED: t/t_enum_type_methods_bad.v:24:14: Unsupported: enum next/prev with non-constant argument
: ... note: In instance 't'
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