Internals: V3Unroll refactoring. No functional change intended

This commit is contained in:
Wilson Snyder 2025-07-27 03:36:41 -04:00
parent 470f99694e
commit d93abd002f
1 changed files with 27 additions and 36 deletions

View File

@ -38,23 +38,32 @@ VL_DEFINE_DEBUG_FUNCTIONS;
// Unroll state, as a visitor of each AstNode // Unroll state, as a visitor of each AstNode
class UnrollVisitor final : public VNVisitor { class UnrollVisitor final : public VNVisitor {
// STATE // STATE - across all visitors
AstVar* m_forVarp; // Iterator variable AstVar* m_forVarp; // Iterator variable
const AstVarScope* m_forVscp; // Iterator variable scope (nullptr for generate pass) const AstVarScope* m_forVscp; // Iterator variable scope (nullptr for generate pass)
AstConst* m_varValuep; // Current value of loop
const AstNode* m_ignoreIncp; // Increment node to ignore const AstNode* m_ignoreIncp; // Increment node to ignore
bool m_varModeCheck; // Just checking RHS assignments bool m_varModeCheck; // Just checking RHS assignments
bool m_varModeReplace; // Replacing varrefs
bool m_varAssignHit; // Assign var hit bool m_varAssignHit; // Assign var hit
bool m_forkHit; // Fork hit bool m_forkHit; // Fork hit
bool m_generate; // Expand single generate For loop bool m_generate; // Expand single generate For loop
string m_beginName; // What name to give begin iterations string m_beginName; // What name to give begin iterations
// STATE - Statistic tracking
VDouble0 m_statLoops; // Statistic tracking VDouble0 m_statLoops; // Statistic tracking
VDouble0 m_statIters; // Statistic tracking VDouble0 m_statIters; // Statistic tracking
// METHODS // METHODS
void replaceVarRef(AstNode* bodyp, AstNode* varValuep) {
// Replace all occurances of loop variable in bodyp and next
bodyp->foreachAndNext([this, varValuep](AstVarRef* refp) {
if (refp->varp() == m_forVarp && refp->varScopep() == m_forVscp
&& refp->access().isReadOnly()) {
AstNode* const newconstp = varValuep->cloneTree(false);
refp->replaceWith(newconstp);
VL_DO_DANGLING(pushDeletep(refp), refp);
}
});
}
// VISITORS
bool cantUnroll(AstNode* nodep, const char* reason) const { bool cantUnroll(AstNode* nodep, const char* reason) const {
if (m_generate) if (m_generate)
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Can't unroll generate for; " << reason); nodep->v3warn(E_UNSUPPORTED, "Unsupported: Can't unroll generate for; " << reason);
@ -198,15 +207,13 @@ class UnrollVisitor final : public VNVisitor {
AstNode* clonep = nodep->cloneTree(true); AstNode* clonep = nodep->cloneTree(true);
UASSERT_OBJ(clonep, nodep, "Failed to clone tree"); UASSERT_OBJ(clonep, nodep, "Failed to clone tree");
if (loopValue) { if (loopValue) {
m_varValuep = new AstConst{nodep->fileline(), *loopValue}; AstConst* varValuep = new AstConst{nodep->fileline(), *loopValue};
// Iteration requires a back, so put under temporary node // Iteration requires a back, so put under temporary node
AstBegin* tempp = new AstBegin{nodep->fileline(), "[EditWrapper]", clonep}; AstBegin* tempp = new AstBegin{nodep->fileline(), "[EditWrapper]", clonep};
m_varModeReplace = true; replaceVarRef(tempp->stmtsp(), varValuep);
iterateAndNextNull(tempp->stmtsp());
m_varModeReplace = false;
clonep = tempp->stmtsp()->unlinkFrBackWithNext(); clonep = tempp->stmtsp()->unlinkFrBackWithNext();
VL_DO_CLEAR(tempp->deleteTree(), tempp = nullptr); VL_DO_CLEAR(tempp->deleteTree(), tempp = nullptr);
VL_DO_CLEAR(pushDeletep(m_varValuep), m_varValuep = nullptr); VL_DO_DANGLING(pushDeletep(varValuep), varValuep);
} }
SimulateVisitor simvis; SimulateVisitor simvis;
simvis.mainParamEmulate(clonep); simvis.mainParamEmulate(clonep);
@ -288,8 +295,8 @@ class UnrollVisitor final : public VNVisitor {
// Mark variable to disable some later warnings // Mark variable to disable some later warnings
m_forVarp->usedLoopIdx(true); m_forVarp->usedLoopIdx(true);
AstNode* newbodysp = nullptr;
++m_statLoops; ++m_statLoops;
AstNode* newbodysp = nullptr;
if (stmtsp) { if (stmtsp) {
int times = 0; int times = 0;
while (true) { while (true) {
@ -302,27 +309,23 @@ class UnrollVisitor final : public VNVisitor {
if (!res.isEqOne()) { if (!res.isEqOne()) {
break; // Done with the loop break; // Done with the loop
} else { } else {
// Replace iterator values with constant. // Replace iterator values with constant
AstNode* oneloopp = stmtsp->cloneTree(true); AstNode* oneloopp = stmtsp->cloneTree(true);
AstConst* varValuep = new AstConst{nodep->fileline(), loopValue};
m_varValuep = new AstConst{nodep->fileline(), loopValue};
// Iteration requires a back, so put under temporary node
if (oneloopp) { if (oneloopp) {
// Iteration requires a back, so put under temporary node
AstBegin* const tempp AstBegin* const tempp
= new AstBegin{oneloopp->fileline(), "[EditWrapper]", oneloopp}; = new AstBegin{oneloopp->fileline(), "[EditWrapper]", oneloopp};
m_varModeReplace = true; replaceVarRef(tempp->stmtsp(), varValuep);
iterateAndNextNull(tempp->stmtsp());
m_varModeReplace = false;
oneloopp = tempp->stmtsp()->unlinkFrBackWithNext(); oneloopp = tempp->stmtsp()->unlinkFrBackWithNext();
VL_DO_DANGLING(tempp->deleteTree(), tempp); VL_DO_DANGLING(tempp->deleteTree(), tempp);
} }
if (m_generate) { if (m_generate) {
const string index = AstNode::encodeNumber(m_varValuep->toSInt()); const string index = AstNode::encodeNumber(varValuep->toSInt());
const string nname = m_beginName + "__BRA__" + index + "__KET__"; const string nname = m_beginName + "__BRA__" + index + "__KET__";
oneloopp = new AstBegin{oneloopp->fileline(), nname, oneloopp, true}; oneloopp = new AstBegin{oneloopp->fileline(), nname, oneloopp, true};
} }
VL_DO_CLEAR(pushDeletep(m_varValuep), m_varValuep = nullptr); VL_DO_DANGLING(pushDeletep(varValuep), varValuep);
if (newbodysp) { if (newbodysp) {
newbodysp->addNext(oneloopp); newbodysp->addNext(oneloopp);
} else { } else {
@ -373,10 +376,10 @@ class UnrollVisitor final : public VNVisitor {
return true; return true;
} }
// VISITORS
void visit(AstWhile* nodep) override { void visit(AstWhile* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
if (m_varModeCheck || m_varModeReplace) { if (!m_varModeCheck) {
} else {
// Constify before unroll call, as it may change what is underneath. // Constify before unroll call, as it may change what is underneath.
if (nodep->condp()) V3Const::constifyEdit(nodep->condp()); // condp may change if (nodep->condp()) V3Const::constifyEdit(nodep->condp()); // condp may change
// Grab initial value // Grab initial value
@ -406,11 +409,10 @@ class UnrollVisitor final : public VNVisitor {
} }
} }
void visit(AstGenFor* nodep) override { void visit(AstGenFor* nodep) override {
if (!m_generate || m_varModeReplace) { if (!m_generate) {
iterateChildren(nodep); iterateChildren(nodep);
} // else V3Param will recursively call each for loop to be unrolled for us } // else V3Param will recursively call each for loop to be unrolled for us
if (m_varModeCheck || m_varModeReplace) { if (!m_varModeCheck) {
} else {
// Constify before unroll call, as it may change what is underneath. // Constify before unroll call, as it may change what is underneath.
if (nodep->initsp()) V3Const::constifyEdit(nodep->initsp()); // initsp may change if (nodep->initsp()) V3Const::constifyEdit(nodep->initsp()); // initsp may change
if (nodep->condp()) V3Const::constifyEdit(nodep->condp()); // condp may change if (nodep->condp()) V3Const::constifyEdit(nodep->condp()); // condp may change
@ -446,13 +448,6 @@ class UnrollVisitor final : public VNVisitor {
UINFO(8, " Itervar assigned to: " << nodep); UINFO(8, " Itervar assigned to: " << nodep);
m_varAssignHit = true; m_varAssignHit = true;
} }
if (m_varModeReplace && nodep->varp() == m_forVarp && nodep->varScopep() == m_forVscp
&& nodep->access().isReadOnly()) {
AstNode* const newconstp = m_varValuep->cloneTree(false);
nodep->replaceWith(newconstp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
} }
void visit(AstFork* nodep) override { void visit(AstFork* nodep) override {
@ -466,8 +461,6 @@ class UnrollVisitor final : public VNVisitor {
} }
} }
//--------------------
// Default: Just iterate
void visit(AstNode* nodep) override { void visit(AstNode* nodep) override {
if (m_varModeCheck && nodep == m_ignoreIncp) { if (m_varModeCheck && nodep == m_ignoreIncp) {
// Ignore subtree that is the increment // Ignore subtree that is the increment
@ -487,10 +480,8 @@ public:
void init(bool generate, const string& beginName) { void init(bool generate, const string& beginName) {
m_forVarp = nullptr; m_forVarp = nullptr;
m_forVscp = nullptr; m_forVscp = nullptr;
m_varValuep = nullptr;
m_ignoreIncp = nullptr; m_ignoreIncp = nullptr;
m_varModeCheck = false; m_varModeCheck = false;
m_varModeReplace = false;
m_varAssignHit = false; m_varAssignHit = false;
m_forkHit = false; m_forkHit = false;
m_generate = generate; m_generate = generate;