Internals: Cleanup some V3Simulate branches. No functional change intended.

This commit is contained in:
Wilson Snyder 2026-04-03 20:16:10 -04:00
parent ed0506ea8d
commit 00bf59ac92
1 changed files with 97 additions and 106 deletions

View File

@ -521,24 +521,23 @@ private:
} }
} }
} }
if (!m_checkOnly && optimizable()) { // simulating if (m_checkOnly || !optimizable()) return; // Not simulating
UASSERT_OBJ(nodep->access().isReadOnly(), nodep, UASSERT_OBJ(nodep->access().isReadOnly(), nodep,
"LHS varref should be handled in AstAssign visitor."); "LHS varref should be handled in AstAssign visitor.");
{ {
// Return simulation value - copy by reference instead of value for speed // Return simulation value - copy by reference instead of value for speed
AstNodeExpr* valuep = fetchValueNull(vscp); AstNodeExpr* valuep = fetchValueNull(vscp);
if (!valuep) { if (!valuep) {
if (m_params) { if (m_params) {
clearOptimizable( clearOptimizable(
nodep, "Language violation: reference to non-function-local variable"); nodep, "Language violation: reference to non-function-local variable");
} else { } else {
nodep->v3fatalSrc( nodep->v3fatalSrc(
"Variable value should have been set before any visitor called."); "Variable value should have been set before any visitor called.");
}
valuep = allocConst(nodep); // Any value; just so recover from error
} }
setValue(nodep, valuep); valuep = allocConst(nodep); // Any value; just so recover from error
} }
setValue(nodep, valuep);
} }
} }
void visit(AstVarXRef* nodep) override { void visit(AstVarXRef* nodep) override {
@ -606,12 +605,14 @@ private:
} }
void visit(AstConst* nodep) override { void visit(AstConst* nodep) override {
checkNodeInfo(nodep); checkNodeInfo(nodep);
if (!m_checkOnly && optimizable()) newValue(nodep, nodep); if (m_checkOnly || !optimizable()) return;
newValue(nodep, nodep);
} }
void visit(AstInitArray* nodep) override { void visit(AstInitArray* nodep) override {
checkNodeInfo(nodep); checkNodeInfo(nodep);
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
if (!m_checkOnly && optimizable()) newValue(nodep, nodep); if (m_checkOnly || !optimizable()) return;
newValue(nodep, nodep);
} }
void visit(AstInitItem* nodep) override { void visit(AstInitItem* nodep) override {
checkNodeInfo(nodep); checkNodeInfo(nodep);
@ -620,62 +621,55 @@ private:
void visit(AstEnumItemRef* nodep) override { void visit(AstEnumItemRef* nodep) override {
checkNodeInfo(nodep); checkNodeInfo(nodep);
UASSERT_OBJ(nodep->itemp(), nodep, "Not linked"); UASSERT_OBJ(nodep->itemp(), nodep, "Not linked");
if (!m_checkOnly && optimizable()) { if (m_checkOnly || !optimizable()) return;
AstNode* const valuep = nodep->itemp()->valuep(); AstNode* const valuep = nodep->itemp()->valuep();
if (valuep) { if (valuep) {
iterateAndNextConstNull(valuep); iterateAndNextConstNull(valuep);
if (!optimizable()) return; if (!optimizable()) return;
newValue(nodep, fetchValue(valuep)); newValue(nodep, fetchValue(valuep));
} else { } else {
clearOptimizable(nodep, "No value found for enum item"); // LCOV_EXCL_LINE clearOptimizable(nodep, "No value found for enum item"); // LCOV_EXCL_LINE
}
} }
} }
void visit(AstNodeUniop* nodep) override { void visit(AstNodeUniop* nodep) override {
if (!optimizable()) return; // Accelerate if (!optimizable()) return; // Accelerate
checkNodeInfo(nodep); checkNodeInfo(nodep);
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
if (!m_checkOnly && optimizable()) { if (m_checkOnly || !optimizable()) return;
nodep->numberOperate(newConst(nodep)->num(), fetchConst(nodep->lhsp())->num()); nodep->numberOperate(newConst(nodep)->num(), fetchConst(nodep->lhsp())->num());
}
} }
void visit(AstNodeBiop* nodep) override { void visit(AstNodeBiop* nodep) override {
if (!optimizable()) return; // Accelerate if (!optimizable()) return; // Accelerate
checkNodeInfo(nodep); checkNodeInfo(nodep);
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
if (!m_checkOnly && optimizable()) { if (m_checkOnly || !optimizable()) return;
AstConst* const valuep = newConst(nodep); AstConst* const valuep = newConst(nodep);
nodep->numberOperate(newConst(nodep)->num(), fetchConst(nodep->lhsp())->num(), nodep->numberOperate(newConst(nodep)->num(), fetchConst(nodep->lhsp())->num(),
fetchConst(nodep->rhsp())->num()); fetchConst(nodep->rhsp())->num());
// See #5490. 'numberOperate' on partially out of range select yields 'x' bits, // See #5490. 'numberOperate' on partially out of range select yields 'x' bits,
// but in reality it would yield '0's without V3Table, so force 'x' bits to '0', // but in reality it would yield '0's without V3Table, so force 'x' bits to '0',
// to ensure the result is the same with and without V3Table. // to ensure the result is the same with and without V3Table.
if (!m_params && VN_IS(nodep, Sel) && valuep->num().isAnyX()) { if (!m_params && VN_IS(nodep, Sel) && valuep->num().isAnyX()) {
const V3Number num{valuep, valuep->width(), valuep->num()}; const V3Number num{valuep, valuep->width(), valuep->num()};
valuep->num().opBitsOne(num); valuep->num().opBitsOne(num);
}
} }
} }
void visit(AstNodeTriop* nodep) override { void visit(AstNodeTriop* nodep) override {
if (!optimizable()) return; // Accelerate if (!optimizable()) return; // Accelerate
checkNodeInfo(nodep); checkNodeInfo(nodep);
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
if (!m_checkOnly && optimizable()) { if (m_checkOnly || !optimizable()) return;
nodep->numberOperate(newConst(nodep)->num(), fetchConst(nodep->lhsp())->num(), nodep->numberOperate(newConst(nodep)->num(), fetchConst(nodep->lhsp())->num(),
fetchConst(nodep->rhsp())->num(), fetchConst(nodep->rhsp())->num(), fetchConst(nodep->thsp())->num());
fetchConst(nodep->thsp())->num());
}
} }
void visit(AstNodeQuadop* nodep) override { void visit(AstNodeQuadop* nodep) override {
if (!optimizable()) return; // Accelerate if (!optimizable()) return; // Accelerate
checkNodeInfo(nodep); checkNodeInfo(nodep);
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
if (!m_checkOnly && optimizable()) { if (m_checkOnly || !optimizable()) return;
nodep->numberOperate(newConst(nodep)->num(), fetchConst(nodep->lhsp())->num(), nodep->numberOperate(newConst(nodep)->num(), fetchConst(nodep->lhsp())->num(),
fetchConst(nodep->rhsp())->num(), fetchConst(nodep->rhsp())->num(), fetchConst(nodep->thsp())->num(),
fetchConst(nodep->thsp())->num(), fetchConst(nodep->fhsp())->num());
fetchConst(nodep->fhsp())->num());
}
} }
void visit(AstLogAnd* nodep) override { void visit(AstLogAnd* nodep) override {
// Need to short circuit // Need to short circuit
@ -773,62 +767,60 @@ private:
clearOptimizable(nodep, "Array of non-basic dtype (e.g. array-of-array)"); clearOptimizable(nodep, "Array of non-basic dtype (e.g. array-of-array)");
return; return;
} }
if (!m_checkOnly && optimizable()) { if (m_checkOnly || !optimizable()) return;
AstNode* const vscp = varOrScope(varrefp); AstNode* const vscp = varOrScope(varrefp);
AstInitArray* initp = nullptr; AstInitArray* initp = nullptr;
if (AstInitArray* const vscpnump = VN_CAST(fetchOutValueNull(vscp), InitArray)) { if (AstInitArray* const vscpnump = VN_CAST(fetchOutValueNull(vscp), InitArray)) {
initp = vscpnump; initp = vscpnump;
} else if (AstInitArray* const vscpnump = VN_CAST(fetchValueNull(vscp), InitArray)) { } else if (AstInitArray* const vscpnump = VN_CAST(fetchValueNull(vscp), InitArray)) {
initp = vscpnump; initp = vscpnump;
} else { // Assignment to unassigned variable, all bits are X } else { // Assignment to unassigned variable, all bits are X
// TODO generic initialization which builds X/arrays by recursion // TODO generic initialization which builds X/arrays by recursion
AstConst* const outconstp = new AstConst{ AstConst* const outconstp
nodep->fileline(), AstConst::WidthedValue{}, basicp->widthMin(), 0}; = new AstConst{nodep->fileline(), AstConst::WidthedValue{}, basicp->widthMin(), 0};
if (basicp->isZeroInit()) { if (basicp->isZeroInit()) {
outconstp->num().setAllBits0(); outconstp->num().setAllBits0();
} else { } else {
outconstp->num().setAllBitsX(); outconstp->num().setAllBitsX();
}
initp = new AstInitArray{nodep->fileline(), arrayp, outconstp};
m_reclaimValuesp.push_back(initp);
} }
const uint32_t index = fetchConst(selp->bitp())->toUInt();
AstNodeExpr* const valuep = newTrackedClone(fetchValue(valueFromp)); initp = new AstInitArray{nodep->fileline(), arrayp, outconstp};
UINFO(9, " set val[" << index << "] = " << valuep); m_reclaimValuesp.push_back(initp);
// Values are in the "real" tree under the InitArray so can eventually extract it,
// Not in the usual setValue (via m_varAux)
initp->addIndexValuep(index, valuep);
UINFOTREE(9, initp, "", "array");
assignOutValue(nodep, vscp, initp);
} }
const uint32_t index = fetchConst(selp->bitp())->toUInt();
AstNodeExpr* const valuep = newTrackedClone(fetchValue(valueFromp));
UINFO(9, " set val[" << index << "] = " << valuep);
// Values are in the "real" tree under the InitArray so can eventually extract it,
// Not in the usual setValue (via m_varAux)
initp->addIndexValuep(index, valuep);
UINFOTREE(9, initp, "", "array");
assignOutValue(nodep, vscp, initp);
} }
void handleAssignSel(AstNodeAssign* nodep, AstSel* selp, AstNodeExpr* valueFromp) { void handleAssignSel(AstNodeAssign* nodep, AstSel* selp, AstNodeExpr* valueFromp) {
AstVarRef* varrefp = nullptr; AstVarRef* varrefp = nullptr;
V3Number lsb{nodep}; V3Number lsb{nodep};
handleAssignSelRecurse(nodep, selp, varrefp /*ref*/, lsb /*ref*/, 0); handleAssignSelRecurse(nodep, selp, varrefp /*ref*/, lsb /*ref*/, 0);
if (!m_checkOnly && optimizable()) { if (m_checkOnly || !optimizable()) return;
UASSERT_OBJ(varrefp, nodep, UASSERT_OBJ(varrefp, nodep,
"Indicated optimizable, but no variable found on RHS of select"); "Indicated optimizable, but no variable found on RHS of select");
AstNode* const vscp = varOrScope(varrefp); AstNode* const vscp = varOrScope(varrefp);
AstConst* outconstp = nullptr; AstConst* outconstp = nullptr;
if (AstConst* const vscpnump = fetchOutConstNull(vscp)) { if (AstConst* const vscpnump = fetchOutConstNull(vscp)) {
outconstp = vscpnump; outconstp = vscpnump;
} else if (AstConst* const vscpnump = fetchConstNull(vscp)) { } else if (AstConst* const vscpnump = fetchConstNull(vscp)) {
outconstp = vscpnump; outconstp = vscpnump;
} else { // Assignment to unassigned variable, all bits are X or 0 } else { // Assignment to unassigned variable, all bits are X or 0
outconstp = new AstConst{nodep->fileline(), AstConst::WidthedValue{}, outconstp = new AstConst{nodep->fileline(), AstConst::WidthedValue{},
varrefp->varp()->widthMin(), 0}; varrefp->varp()->widthMin(), 0};
if (varrefp->varp()->basicp() && varrefp->varp()->basicp()->isZeroInit()) { if (varrefp->varp()->basicp() && varrefp->varp()->basicp()->isZeroInit()) {
outconstp->num().setAllBits0(); outconstp->num().setAllBits0();
} else { } else {
outconstp->num().setAllBitsX(); outconstp->num().setAllBitsX();
}
m_reclaimValuesp.emplace_back(outconstp);
} }
outconstp->num().opSelInto(fetchConst(valueFromp)->num(), lsb, selp->widthConst()); m_reclaimValuesp.emplace_back(outconstp);
assignOutValue(nodep, vscp, outconstp);
} }
outconstp->num().opSelInto(fetchConst(valueFromp)->num(), lsb, selp->widthConst());
assignOutValue(nodep, vscp, outconstp);
} }
void handleAssignSelRecurse(AstNodeAssign* nodep, AstSel* selp, AstVarRef*& outVarrefpRef, void handleAssignSelRecurse(AstNodeAssign* nodep, AstSel* selp, AstVarRef*& outVarrefpRef,
V3Number& lsbRef, int depth) { V3Number& lsbRef, int depth) {
@ -1059,8 +1051,8 @@ private:
iterateAndNextConstNull(nodep->stmtsp()); iterateAndNextConstNull(nodep->stmtsp());
if (!optimizable()) return; if (!optimizable()) return;
iterateAndNextConstNull(nodep->resultp()); iterateAndNextConstNull(nodep->resultp());
if (!optimizable()) return; if (m_checkOnly || !optimizable()) return;
if (!m_checkOnly) newValue(nodep, fetchValue(nodep->resultp())); newValue(nodep, fetchValue(nodep->resultp()));
} }
void visit(AstJumpBlock* nodep) override { void visit(AstJumpBlock* nodep) override {
@ -1121,7 +1113,8 @@ private:
if (jumpingOver()) return; if (jumpingOver()) return;
checkNodeInfo(nodep); checkNodeInfo(nodep);
iterateConst(nodep->condp()); iterateConst(nodep->condp());
if (!m_checkOnly && optimizable() && fetchConst(nodep->condp())->num().isEqZero()) { if (m_checkOnly || !optimizable()) return;
if (fetchConst(nodep->condp())->num().isEqZero()) {
UINFO(5, " LOOP TEST GO " << nodep); UINFO(5, " LOOP TEST GO " << nodep);
UASSERT_OBJ(!m_jumptargetp, nodep, "Jump inside jump"); UASSERT_OBJ(!m_jumptargetp, nodep, "Jump inside jump");
m_jumptargetp = nodep->loopp(); m_jumptargetp = nodep->loopp();
@ -1274,8 +1267,7 @@ private:
if (!optimizable()) return; // Accelerate if (!optimizable()) return; // Accelerate
checkNodeInfo(nodep); checkNodeInfo(nodep);
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
if (m_checkOnly) return; if (m_checkOnly || !optimizable()) return;
if (!optimizable()) return; // Accelerate
AstNode* nextArgp = nodep->exprsp(); AstNode* nextArgp = nodep->exprsp();
string result; string result;
@ -1357,8 +1349,7 @@ private:
if (!optimizable()) return; // Accelerate if (!optimizable()) return; // Accelerate
checkNodeInfo(nodep); checkNodeInfo(nodep);
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
if (!optimizable()) return; if (m_checkOnly || !optimizable()) return;
if (m_checkOnly) return;
const std::string result = toStringRecurse(nodep->lhsp()); const std::string result = toStringRecurse(nodep->lhsp());
if (!optimizable()) return; if (!optimizable()) return;
AstConst* const resultConstp = new AstConst{nodep->fileline(), AstConst::String{}, result}; AstConst* const resultConstp = new AstConst{nodep->fileline(), AstConst::String{}, result};