Internals: Simplify AstForeach header handling (#7126)

Rename AstSelLoopVars to AstForeachHeader, and make it a non-NodeExpr.
Tweak parser to always create an AstForeachHeader, so no need to fix it
up later.
This commit is contained in:
Geza Lore
2026-02-22 18:57:12 +00:00
committed by GitHub
parent e238a2ca5e
commit da51021b0a
12 changed files with 110 additions and 158 deletions
+18 -19
View File
@@ -1738,10 +1738,10 @@ class ConstraintExprVisitor final : public VNVisitor {
// Convert to plain foreach
FileLine* const fl = nodep->fileline();
if (!nodep->stmtsp()) {
if (!nodep->bodyp()) {
nodep->unlinkFrBack();
} else if (m_wantSingle) {
AstNodeExpr* const itemp = editSingle(fl, nodep->stmtsp());
AstNodeExpr* const itemp = editSingle(fl, nodep->bodyp());
AstCStmt* const cstmtp = new AstCStmt{fl};
cstmtp->add("ret += \" \";\n");
cstmtp->add("ret += ");
@@ -1751,16 +1751,15 @@ class ConstraintExprVisitor final : public VNVisitor {
cexprp->dtypeSetString();
cexprp->add("([&]{\nstd::string ret;\n");
cexprp->add(new AstBegin{
fl, "", new AstForeach{fl, nodep->arrayp()->unlinkFrBack(), cstmtp}, true});
fl, "", new AstForeach{fl, nodep->headerp()->unlinkFrBack(), cstmtp}, true});
cexprp->add("return ret.empty() ? \"#b1\" : \"(bvand\" + ret + \")\";\n})()");
nodep->replaceWith(new AstSFormatF{fl, "%@", false, cexprp});
} else {
iterateAndNextNull(nodep->stmtsp());
nodep->replaceWith(
new AstBegin{fl, "",
new AstForeach{fl, nodep->arrayp()->unlinkFrBack(),
nodep->stmtsp()->unlinkFrBackWithNext()},
true});
iterateAndNextNull(nodep->bodyp());
nodep->replaceWith(new AstBegin{fl, "",
new AstForeach{fl, nodep->headerp()->unlinkFrBack(),
nodep->bodyp()->unlinkFrBackWithNext()},
true});
}
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
@@ -1962,8 +1961,8 @@ class ConstraintExprVisitor final : public VNVisitor {
AstVar* const newVarp
= new AstVar{fl, VVarType::BLOCKTEMP, "__Vinside", nodep->findSigned32DType()};
AstNodeExpr* const idxRefp = new AstVarRef{nodep->fileline(), newVarp, VAccess::READ};
AstSelLoopVars* const arrayp
= new AstSelLoopVars{fl, nodep->fromp()->cloneTreePure(false), newVarp};
AstForeachHeader* const headerp
= new AstForeachHeader{fl, nodep->fromp()->cloneTreePure(false), newVarp};
AstNodeExpr* const selp = newSel(nodep->fileline(), nodep->fromp(), idxRefp);
selp->user1(randArr);
AstNode* const itemp = new AstEq{fl, selp, nodep->pinsp()->unlinkFrBack()};
@@ -1977,7 +1976,7 @@ class ConstraintExprVisitor final : public VNVisitor {
AstCExpr* const cexprp = new AstCExpr{fl};
cexprp->dtypeSetString();
cexprp->add("([&]{\nstd::string ret;\n");
cexprp->add(new AstBegin{fl, "", new AstForeach{fl, arrayp, cstmtp}, true});
cexprp->add(new AstBegin{fl, "", new AstForeach{fl, headerp, cstmtp}, true});
cexprp->add("return ret.empty() ? \"#b0\" : \"(bvor\" + ret + \")\";\n})()");
nodep->replaceWith(new AstSFormatF{fl, "%@", false, cexprp});
VL_DO_DANGLING(nodep->deleteTree(), nodep);
@@ -2022,8 +2021,8 @@ class ConstraintExprVisitor final : public VNVisitor {
AstVar* const newVarp
= new AstVar{fl, VVarType::BLOCKTEMP, "__Vreduce", nodep->findSigned32DType()};
AstSelLoopVars* const arrayp
= new AstSelLoopVars{fl, nodep->fromp()->cloneTreePure(false), newVarp};
AstForeachHeader* const headerp
= new AstForeachHeader{fl, nodep->fromp()->cloneTreePure(false), newVarp};
// Foreach body: register element as scalar solver var + append name
AstCStmt* const cstmtp = new AstCStmt{fl};
@@ -2045,7 +2044,7 @@ class ConstraintExprVisitor final : public VNVisitor {
AstCExpr* const cexprp = new AstCExpr{fl};
cexprp->dtypeSetString();
cexprp->add("([&]{\nstd::string ret;\n");
cexprp->add(new AstBegin{fl, "", new AstForeach{fl, arrayp, cstmtp}, true});
cexprp->add(new AstBegin{fl, "", new AstForeach{fl, headerp, cstmtp}, true});
const char* smtOp = nullptr;
std::string identity;
@@ -2243,7 +2242,7 @@ class CaptureVisitor final : public VNVisitor {
const bool varIsFieldOfCaller = AstClass::isClassExtendedFrom(callerClassp, varClassp);
const bool varIsParam = varRefp->varp()->isParam();
const bool varIsConstraintIterator
= VN_IS(varRefp->varp()->firstAbovep(), SelLoopVars)
= VN_IS(varRefp->varp()->firstAbovep(), ForeachHeader)
&& VN_IS(varRefp->varp()->firstAbovep()->firstAbovep(), ConstraintForeach);
if (refIsXref) return CaptureMode::CAP_VALUE | CaptureMode::CAP_F_XREF;
if (varIsConstraintIterator) return CaptureMode::CAP_NO;
@@ -2939,12 +2938,12 @@ class RandomizeVisitor final : public VNVisitor {
tempDTypep = tempDTypep->virtRefDTypep();
}
AstSelLoopVars* const randLoopVarp
= new AstSelLoopVars{fl, exprp->cloneTree(false), randLoopIndxp};
AstForeachHeader* const headerp
= new AstForeachHeader{fl, exprp->cloneTree(false), randLoopIndxp};
AstNodeStmt* const randStmtsp = newRandStmtsp(fl, tempElementp, nullptr, outputVarp);
// TODO: we should just not clone in 'newRandStmtsp' if not necessary
if (!tempElementp->backp()) VL_DO_DANGLING(pushDeletep(tempElementp), tempElementp);
return new AstForeach{fl, randLoopVarp, randStmtsp};
return new AstForeach{fl, headerp, randStmtsp};
}
AstNodeStmt* newRandStmtsp(FileLine* fl, AstNodeExpr* exprp, AstVar* randcVarp,
AstVar* const outputVarp, int offset = 0,