mirror of
https://github.com/verilator/verilator.git
synced 2026-10-06 01:54:01 +02:00
Fix break under foreach loop (#3230).
Internals: Move Foreach handling into V3Width.
This commit is contained in:
+9
-73
@@ -413,13 +413,8 @@ private:
|
||||
}
|
||||
|
||||
virtual void visit(AstForeach* nodep) override {
|
||||
// FOREACH(array,loopvars,body)
|
||||
// -> BEGIN(declare vars, loopa=lowest; WHILE(loopa<=highest, ... body))
|
||||
// nodep->dumpTree(cout, "-foreach-old:");
|
||||
// FOREACH(array, loopvars, body)
|
||||
UINFO(9, "FOREACH " << nodep << endl);
|
||||
// nodep->dumpTree(cout, "-foreach-in:");
|
||||
AstNode* newp = nodep->bodysp();
|
||||
if (newp) newp->unlinkFrBackWithNext();
|
||||
// Separate iteration vars from base from variable
|
||||
// Input:
|
||||
// v--- arrayp
|
||||
@@ -433,81 +428,22 @@ private:
|
||||
// 3. ASTSELLOOPVARS(first, var0..var1))
|
||||
// 4. DOT(DOT(first, second), ASTSELBIT(third, var0))
|
||||
AstNode* bracketp = nodep->arrayp();
|
||||
AstNode* firstVarsp = nullptr;
|
||||
while (AstDot* dotp = VN_CAST(bracketp, Dot)) { bracketp = dotp->rhsp(); }
|
||||
while (AstDot* dotp = VN_CAST(bracketp, Dot)) bracketp = dotp->rhsp();
|
||||
if (AstSelBit* const selp = VN_CAST(bracketp, SelBit)) {
|
||||
firstVarsp = selp->rhsp()->unlinkFrBackWithNext();
|
||||
selp->replaceWith(selp->fromp()->unlinkFrBack());
|
||||
// Convert to AstSelLoopVars so V3LinkDot knows what's being defined
|
||||
AstNode* const newp
|
||||
= new AstSelLoopVars{selp->fileline(), selp->fromp()->unlinkFrBack(),
|
||||
selp->rhsp()->unlinkFrBackWithNext()};
|
||||
selp->replaceWith(newp);
|
||||
VL_DO_DANGLING(selp->deleteTree(), selp);
|
||||
} else if (AstSelLoopVars* const selp = VN_CAST(bracketp, SelLoopVars)) {
|
||||
firstVarsp = selp->elementsp()->unlinkFrBackWithNext();
|
||||
selp->replaceWith(selp->fromp()->unlinkFrBack());
|
||||
VL_DO_DANGLING(selp->deleteTree(), selp);
|
||||
// Ok
|
||||
} else {
|
||||
nodep->v3error(
|
||||
"Syntax error; foreach missing bracketed index variable (IEEE 1800-2017 12.7.3)");
|
||||
"Syntax error; foreach missing bracketed loop variable (IEEE 1800-2017 12.7.3)");
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
return;
|
||||
}
|
||||
AstNode* const arrayp = nodep->arrayp(); // Maybe different node since bracketp looked
|
||||
if (!VN_IS(arrayp, ParseRef) && !VN_IS(arrayp, Dot)) {
|
||||
// Code below needs to use other then attributes to figure out the bounds
|
||||
// Also need to deal with queues, etc
|
||||
arrayp->v3warn(E_UNSUPPORTED, "Unsupported: foreach on non-simple variable reference");
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
return;
|
||||
}
|
||||
// Split into for loop
|
||||
// Must do innermost (last) variable first
|
||||
int dimension = 1;
|
||||
AstNode* lastVarsp = firstVarsp;
|
||||
while (lastVarsp->nextp()) {
|
||||
lastVarsp = lastVarsp->nextp();
|
||||
dimension++;
|
||||
}
|
||||
for (AstNode* varsp = lastVarsp; varsp; varsp = varsp->backp()) {
|
||||
UINFO(9, "foreachVar " << varsp << endl);
|
||||
FileLine* const fl = varsp->fileline();
|
||||
AstNode* const varp
|
||||
= new AstVar(fl, AstVarType::BLOCKTEMP, varsp->name(), nodep->findSigned32DType());
|
||||
// These will be the left and right dimensions and size of the array:
|
||||
AstNode* const leftp = new AstAttrOf(
|
||||
fl, AstAttrType::DIM_LEFT, arrayp->cloneTree(false), new AstConst(fl, dimension));
|
||||
AstNode* const rightp = new AstAttrOf(
|
||||
fl, AstAttrType::DIM_RIGHT, arrayp->cloneTree(false), new AstConst(fl, dimension));
|
||||
AstNode* const sizep = new AstAttrOf(
|
||||
fl, AstAttrType::DIM_SIZE, arrayp->cloneTree(false), new AstConst(fl, dimension));
|
||||
AstNode* const stmtsp = varp;
|
||||
// Assign left-dimension into the loop var:
|
||||
stmtsp->addNext(
|
||||
new AstAssign(fl, new AstVarRef(fl, varp->name(), VAccess::WRITE), leftp));
|
||||
// This will turn into a constant bool for static arrays
|
||||
AstNode* const notemptyp = new AstGt(fl, sizep, new AstConst(fl, 0));
|
||||
// This will turn into a bool constant, indicating whether
|
||||
// we count the loop variable up or down:
|
||||
AstNode* const countupp
|
||||
= new AstLte(fl, leftp->cloneTree(true), rightp->cloneTree(true));
|
||||
AstNode* const comparep = new AstCond(
|
||||
fl, countupp->cloneTree(true),
|
||||
// Left increments up to right
|
||||
new AstLte(fl, new AstVarRef(fl, varp->name(), VAccess::READ),
|
||||
rightp->cloneTree(true)),
|
||||
// Left decrements down to right
|
||||
new AstGte(fl, new AstVarRef(fl, varp->name(), VAccess::READ), rightp));
|
||||
// This will reduce to comparep for static arrays
|
||||
AstNode* const condp = new AstAnd(fl, notemptyp, comparep);
|
||||
AstNode* const incp = new AstAssign(
|
||||
fl, new AstVarRef(fl, varp->name(), VAccess::WRITE),
|
||||
new AstAdd(fl, new AstVarRef(fl, varp->name(), VAccess::READ),
|
||||
new AstCond(fl, countupp, new AstConst(fl, 1), new AstConst(fl, -1))));
|
||||
stmtsp->addNext(new AstWhile(fl, condp, newp, incp));
|
||||
newp = new AstBegin(nodep->fileline(), "", stmtsp, false, true);
|
||||
dimension--;
|
||||
}
|
||||
// newp->dumpTree(cout, "-foreach-new:");
|
||||
VL_DO_DANGLING(firstVarsp->deleteTree(), firstVarsp);
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeModule* nodep) override {
|
||||
|
||||
Reference in New Issue
Block a user