Internals: Some tristate and param cleanups. No functional change.

This commit is contained in:
Wilson Snyder 2026-01-25 14:19:27 -05:00
parent 2ddfcbed16
commit 41b131389e
3 changed files with 85 additions and 96 deletions

View File

@ -662,6 +662,7 @@ public:
if (pinVarp->isInout()) {
pinVarp->v3fatalSrc("Unsupported: Inout connections to pins must be"
" direct one-to-one connection (without any expression)");
// V3Tristate should have cleared up before this point
} else if (pinVarp->isWritable()) {
// See also V3Inst
AstNodeExpr* rhsp = new AstVarRef{pinp->fileline(), newvarp, VAccess::READ};

View File

@ -1318,13 +1318,13 @@ public:
srcModp->someInstanceName(instanceName);
AstNodeModule* newModp = nullptr;
if (AstCell* cellp = VN_CAST(nodep, Cell)) {
if (AstCell* const cellp = VN_CAST(nodep, Cell)) {
newModp = cellDeparam(cellp, srcModp);
} else if (AstIfaceRefDType* ifaceRefDTypep = VN_CAST(nodep, IfaceRefDType)) {
} else if (AstIfaceRefDType* const ifaceRefDTypep = VN_CAST(nodep, IfaceRefDType)) {
newModp = ifaceRefDeparam(ifaceRefDTypep, srcModp);
} else if (AstClassRefDType* classRefp = VN_CAST(nodep, ClassRefDType)) {
} else if (AstClassRefDType* const classRefp = VN_CAST(nodep, ClassRefDType)) {
newModp = classRefDeparam(classRefp, srcModp);
} else if (AstClassOrPackageRef* classRefp = VN_CAST(nodep, ClassOrPackageRef)) {
} else if (AstClassOrPackageRef* const classRefp = VN_CAST(nodep, ClassOrPackageRef)) {
newModp = classRefDeparam(classRefp, srcModp);
} else {
nodep->v3fatalSrc("Expected module parameterization");
@ -2025,7 +2025,7 @@ public:
netlistp->foreach([](AstNodeFTaskRef* ftaskrefp) {
AstNodeFTask* ftaskp = ftaskrefp->taskp();
if (!ftaskp || !ftaskp->classMethod()) return;
string funcName = ftaskp->name();
const string funcName = ftaskp->name();
for (AstNode* backp = ftaskrefp->backp(); backp; backp = backp->backp()) {
if (VN_IS(backp, Class)) {
if (backp == ftaskrefp->classOrPackagep())
@ -2042,7 +2042,7 @@ public:
}
UASSERT_OBJ(classp, ftaskrefp, "Class method has no class above it");
if (classp->user3p()) return; // will not get removed, no need to relink
AstClass* parametrizedClassp = VN_CAST(classp->user4p(), Class);
AstClass* const parametrizedClassp = VN_CAST(classp->user4p(), Class);
if (!parametrizedClassp) return;
AstNodeFTask* newFuncp = nullptr;
parametrizedClassp->exists([&newFuncp, funcName](AstNodeFTask* ftaskp) {

View File

@ -192,8 +192,8 @@ private:
public:
// CONSTRUCTORS
TristateGraph() { clear(); }
virtual ~TristateGraph() { clear(); }
TristateGraph() { clearAndCheck(); }
virtual ~TristateGraph() { clearAndCheck(); }
VL_UNCOPYABLE(TristateGraph);
private:
@ -271,7 +271,7 @@ private:
public:
// METHODS
bool empty() const { return m_graph.empty(); }
void clear() {
void clearAndCheck() {
for (V3GraphVertex& vtx : m_graph.vertices()) {
const TristateVertex& vvertex = static_cast<TristateVertex&>(vtx);
if (vvertex.isTristate() && !vvertex.processed()) {
@ -617,23 +617,20 @@ class TristateVisitor final : public TristateBaseVisitor {
// them to the lhs map so they get expanded correctly.
const TristateGraph::VarVec vars = m_tgraph.tristateVars();
for (auto varp : vars) {
if (m_tgraph.isTristate(varp)) {
const auto it = m_lhsmap.find(varp);
if (it == m_lhsmap.end()) {
// This variable is floating, set output enable to
// always be off on this assign
UINFO(8, " Adding driver to var " << varp);
AstConst* const constp = newAllZerosOrOnes(varp, false);
AstVarRef* const varrefp
= new AstVarRef{varp->fileline(), varp, VAccess::WRITE};
AstAssignW* const newp = new AstAssignW{varp->fileline(), varrefp, constp};
UINFO(9, " newoev " << newp);
varrefp->user1p(newAllZerosOrOnes(varp, false));
nodep->addStmtsp(new AstAlways{newp});
mapInsertLhsVarRef(varrefp); // insertTristates will convert
// // to a varref to the __out# variable
}
}
if (!m_tgraph.isTristate(varp)) continue;
const auto it = m_lhsmap.find(varp);
if (it != m_lhsmap.end()) continue;
// This variable is floating, set output enable to
// always be off on this assign
UINFO(8, " Adding driver to var " << varp);
AstConst* const constp = newAllZerosOrOnes(varp, false);
AstVarRef* const varrefp = new AstVarRef{varp->fileline(), varp, VAccess::WRITE};
AstAssignW* const newp = new AstAssignW{varp->fileline(), varrefp, constp};
UINFO(9, " newoev " << newp);
varrefp->user1p(newAllZerosOrOnes(varp, false));
nodep->addStmtsp(new AstAlways{newp});
mapInsertLhsVarRef(varrefp); // insertTristates will convert
// // to a varref to the __out# variable
}
// Now go through the lhs driver map and generate the output
@ -929,33 +926,31 @@ class TristateVisitor final : public TristateBaseVisitor {
// same Net (merge by or for WOR/TIOR and merge by and for WAND/TRIAND).
for (auto& varpAssigns : m_assigns) {
Assigns& assigns = varpAssigns.second;
if (assigns.size() > 1) {
AstVar* const varp = varpAssigns.first;
if (varp->isWiredNet()) {
auto it = assigns.begin();
AstAssignW* const assignWp0 = *it;
FileLine* const fl = assignWp0->fileline();
AstNodeExpr* wExp = nullptr;
while (++it != assigns.end()) {
AstAssignW* assignWpi = *it;
if (!wExp) {
wExp = newMergeExpr(assignWp0->rhsp()->cloneTreePure(false),
assignWpi->rhsp()->cloneTreePure(false), fl,
varp->isWor());
} else {
wExp = newMergeExpr(wExp, assignWpi->rhsp()->cloneTreePure(false), fl,
varp->isWor());
}
VL_DO_DANGLING((assignWpi->unlinkFrBack()->deleteTree()), assignWpi);
}
AstVarRef* const wVarRef = new AstVarRef{fl, varp, VAccess::WRITE};
AstAssignW* const wAssignp = new AstAssignW{fl, wVarRef, wExp};
assignWp0->replaceWith(wAssignp);
VL_DO_DANGLING(pushDeletep(assignWp0), assignWp0);
assigns.clear();
assigns.push_back(wAssignp);
if (assigns.size() <= 1) continue;
AstVar* const varp = varpAssigns.first;
if (!varp->isWiredNet()) continue;
auto it = assigns.begin();
AstAssignW* const assignWp0 = *it;
FileLine* const fl = assignWp0->fileline();
AstNodeExpr* wExp = nullptr;
while (++it != assigns.end()) {
AstAssignW* assignWpi = *it;
if (!wExp) {
wExp
= newMergeExpr(assignWp0->rhsp()->cloneTreePure(false),
assignWpi->rhsp()->cloneTreePure(false), fl, varp->isWor());
} else {
wExp = newMergeExpr(wExp, assignWpi->rhsp()->cloneTreePure(false), fl,
varp->isWor());
}
VL_DO_DANGLING((assignWpi->unlinkFrBack()->deleteTree()), assignWpi);
}
AstVarRef* const wVarRef = new AstVarRef{fl, varp, VAccess::WRITE};
AstAssignW* const wAssignp = new AstAssignW{fl, wVarRef, wExp};
assignWp0->replaceWith(wAssignp);
VL_DO_DANGLING(pushDeletep(assignWp0), assignWp0);
assigns.clear();
assigns.push_back(wAssignp);
}
}
@ -985,26 +980,25 @@ class TristateVisitor final : public TristateBaseVisitor {
// value (0 or 1), is found, all weaker assignments can be safely removed.
for (auto& varpAssigns : m_assigns) {
Assigns& assigns = varpAssigns.second;
if (assigns.size() > 1) {
const AstAssignW* const strongest0p = getStrongestAssignmentOfValue(assigns, 0);
const AstAssignW* const strongest1p = getStrongestAssignmentOfValue(assigns, 1);
const AstAssignW* strongestp = nullptr;
uint8_t greatestKnownStrength = 0;
const auto getIfStrongest
= [&](const AstAssignW* const strongestCandidatep, bool value) {
if (!strongestCandidatep) return;
uint8_t strength = getStrength(strongestCandidatep, value);
if (strength >= greatestKnownStrength) {
greatestKnownStrength = strength;
strongestp = strongestCandidatep;
}
};
getIfStrongest(strongest0p, 0);
getIfStrongest(strongest1p, 1);
if (assigns.size() <= 1) continue;
const AstAssignW* const strongest0p = getStrongestAssignmentOfValue(assigns, 0);
const AstAssignW* const strongest1p = getStrongestAssignmentOfValue(assigns, 1);
const AstAssignW* strongestp = nullptr;
uint8_t greatestKnownStrength = 0;
const auto getIfStrongest
= [&](const AstAssignW* const strongestCandidatep, bool value) {
if (!strongestCandidatep) return;
uint8_t strength = getStrength(strongestCandidatep, value);
if (strength >= greatestKnownStrength) {
greatestKnownStrength = strength;
strongestp = strongestCandidatep;
}
};
getIfStrongest(strongest0p, 0);
getIfStrongest(strongest1p, 1);
if (strongestp) {
removeNotStrongerAssignments(assigns, strongestp, greatestKnownStrength);
}
if (strongestp) {
removeNotStrongerAssignments(assigns, strongestp, greatestKnownStrength);
}
}
}
@ -1017,28 +1011,22 @@ class TristateVisitor final : public TristateBaseVisitor {
// constant are already removed.)
for (auto& varpAssigns : m_assigns) {
Assigns& assigns = varpAssigns.second;
if (assigns.size() > 1) {
auto maxIt
= std::max_element(assigns.begin(), assigns.end(),
[&](const AstAssignW* ap, const AstAssignW* bp) {
if (m_tgraph.isTristate(ap))
return !m_tgraph.isTristate(bp);
if (m_tgraph.isTristate(bp)) return false;
const uint8_t minStrengthA
= std::min(getStrength(ap, 0), getStrength(ap, 1));
const uint8_t minStrengthB
= std::min(getStrength(bp, 0), getStrength(bp, 1));
return minStrengthA < minStrengthB;
});
// If RHSs of all assignments are tristate, 1st element is returned, so it is
// needed to check if it is non-tristate.
const AstAssignW* const strongestp
= m_tgraph.isTristate(*maxIt) ? nullptr : *maxIt;
if (strongestp) {
uint8_t greatestKnownStrength
= std::min(getStrength(strongestp, 0), getStrength(strongestp, 1));
removeNotStrongerAssignments(assigns, strongestp, greatestKnownStrength);
}
if (assigns.size() <= 1) continue;
auto maxIt = std::max_element(
assigns.begin(), assigns.end(), [&](const AstAssignW* ap, const AstAssignW* bp) {
if (m_tgraph.isTristate(ap)) return !m_tgraph.isTristate(bp);
if (m_tgraph.isTristate(bp)) return false;
const uint8_t minStrengthA = std::min(getStrength(ap, 0), getStrength(ap, 1));
const uint8_t minStrengthB = std::min(getStrength(bp, 0), getStrength(bp, 1));
return minStrengthA < minStrengthB;
});
// If RHSs of all assignments are tristate, 1st element is returned, so it is
// needed to check if it is non-tristate.
const AstAssignW* const strongestp = m_tgraph.isTristate(*maxIt) ? nullptr : *maxIt;
if (strongestp) {
uint8_t greatestKnownStrength
= std::min(getStrength(strongestp, 0), getStrength(strongestp, 1));
removeNotStrongerAssignments(assigns, strongestp, greatestKnownStrength);
}
}
}
@ -1839,7 +1827,7 @@ class TristateVisitor final : public TristateBaseVisitor {
}
void visit(AstNodeModule* nodep) override {
UINFO(8, nodep);
UINFO(8, dbgState() << nodep);
VL_RESTORER(m_modp);
VL_RESTORER(m_graphing);
VL_RESTORER(m_unique);
@ -1850,7 +1838,7 @@ class TristateVisitor final : public TristateBaseVisitor {
// Clear state
m_graphing = false;
m_tgraph.clear();
m_tgraph.clearAndCheck();
m_unique = 0;
m_logicp = nullptr;
m_lhsmap.clear();
@ -1878,7 +1866,7 @@ class TristateVisitor final : public TristateBaseVisitor {
// Insert new logic for all tristates
insertTristates(nodep);
m_tgraph.clear(); // Recursion not supported
m_tgraph.clearAndCheck(); // Recursion not supported
}
void visit(AstClass* nodep) override {
@ -1910,7 +1898,7 @@ class TristateVisitor final : public TristateBaseVisitor {
public:
// CONSTRUCTORS
explicit TristateVisitor(AstNetlist* netlistp) {
m_tgraph.clear();
m_tgraph.clearAndCheck();
iterateChildrenBackwardsConst(netlistp);
#ifdef VL_LEAK_CHECKS