Optimize $sformat in V3Life (#7703)

Treat AstSFormat as a special form of assignment in V3Life. This allows
eliminating earlier redundant assignments to strings when an $sformat
later sets the string. UVM has lot of these.
This commit is contained in:
Geza Lore 2026-06-03 08:41:58 +01:00 committed by GitHub
parent 0026a73ca0
commit 970e7983d3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 33 additions and 22 deletions

View File

@ -78,12 +78,14 @@ public:
m_setBeforeUse = setBeforeUse;
}
void simpleAssign(AstNodeAssign* nodep) { // New simple A=.... assignment
void simpleAssign(AstNodeStmt* nodep) { // New simple A=.... assignment
UASSERT_OBJ(!m_isNew, nodep, "Uninitialized new entry");
m_assignp = nodep;
m_constp = nullptr;
m_everSet = true;
if (VN_IS(nodep->rhsp(), Const)) m_constp = VN_AS(nodep->rhsp(), Const);
if (AstNodeAssign* const assp = VN_CAST(nodep, Assign)) {
if (VN_IS(assp->rhsp(), Const)) m_constp = VN_AS(assp->rhsp(), Const);
}
}
void complexAssign() { // A[x]=... or some complicated assignment
UASSERT(!m_isNew, "Uninitialized new entry");
@ -144,7 +146,7 @@ public:
++m_statep->m_statAssnDel;
VL_DO_DANGLING(m_deleter.pushDeletep(oldassp), oldassp);
}
void simpleAssign(AstVarScope* nodep, AstNodeAssign* assp) {
void simpleAssign(AstVarScope* nodep, AstNodeStmt* assp) {
// Do we have a old assignment we can nuke?
UINFO(4, " ASSIGNof: " << nodep);
UINFO(7, " new: " << assp);
@ -267,6 +269,29 @@ class LifeVisitor final : public VNVisitor {
m_lifep->clear();
}
void processAssignment(AstNodeStmt* nodep, AstNodeExpr* lhsp, AstNodeExpr* rhsp) {
// Collect any used variables first, as lhs may also be on rhs
// Similar code in V3Dead
VL_RESTORER(m_sideEffect);
m_sideEffect = false;
m_lifep->clearReplaced();
rhsp = VN_AS(iterateSubtreeReturnEdits(rhsp), NodeExpr);
if (m_lifep->replaced()) {
// We changed something, try to constant propagate, but don't delete the
// assignment as we still need nodep to remain.
V3Const::constifyEdit(rhsp);
VL_DANGLING(rhsp); // rhsp may change
}
// Has to be direct assignment without any EXTRACTing.
if (VN_IS(lhsp, VarRef) && !m_sideEffect && !m_noopt) {
AstVarScope* const vscp = VN_AS(lhsp, VarRef)->varScopep();
UASSERT_OBJ(vscp, nodep, "Scope lost on variable");
m_lifep->simpleAssign(vscp, nodep);
} else {
iterateAndNextNull(lhsp);
}
}
// VISITORS
void visit(AstVarRef* nodep) override {
// Consumption/generation of a variable,
@ -290,25 +315,11 @@ class LifeVisitor final : public VNVisitor {
iterateChildren(nodep);
return;
}
// Collect any used variables first, as lhs may also be on rhs
// Similar code in V3Dead
VL_RESTORER(m_sideEffect);
m_sideEffect = false;
m_lifep->clearReplaced();
iterateAndNextNull(nodep->rhsp());
if (m_lifep->replaced()) {
// We changed something, try to constant propagate, but don't delete the
// assignment as we still need nodep to remain.
V3Const::constifyEdit(nodep->rhsp()); // rhsp may change
}
// Has to be direct assignment without any EXTRACTing.
if (VN_IS(nodep->lhsp(), VarRef) && !m_sideEffect && !m_noopt) {
AstVarScope* const vscp = VN_AS(nodep->lhsp(), VarRef)->varScopep();
UASSERT_OBJ(vscp, nodep, "Scope lost on variable");
m_lifep->simpleAssign(vscp, nodep);
} else {
iterateAndNextNull(nodep->lhsp());
}
processAssignment(nodep, nodep->lhsp(), nodep->rhsp());
}
void visit(AstSFormat* nodep) override {
// AstSFormat is just a special form of assignment
processAssignment(nodep, nodep->lhsp(), nodep->fmtp());
}
void visit(AstAssignDly* nodep) override {
// V3Life doesn't understand time sense