Fix cache of boundary vertices in Dfg cycle breaking (#8308)

This commit is contained in:
Shriyans Sahoo
2026-09-20 17:05:56 +01:00
committed by GitHub
parent c545552cc1
commit e71f6f3b7a
2 changed files with 37 additions and 24 deletions
+1
View File
@@ -300,6 +300,7 @@ Seth Pellegrino
Shashvat Prabhu
Shogo Yamazaki
Shou-Li Hsu
Shriyans Sahoo
spomatasmd
Srinivasan Venkataramanan
Stefan Wallentowitz
+36 -24
View File
@@ -199,6 +199,8 @@ class TraceDriver final : public DfgVisitor {
DfgVertex* m_splicep = nullptr; // The splice vertex being traced, just for assertions
// Result cache for reusing already traced vertices
std::unordered_map<CacheKey, DfgVertex*, CacheKey::Hash, CacheKey::Equal> m_cache;
// Cache for boundary vertices (where m_sccInfo.get(*vtxp) != m_component)
std::unordered_map<CacheKey, DfgVertex*, CacheKey::Hash, CacheKey::Equal> m_boundaryCache;
#ifdef VL_DEBUG
std::ofstream m_lineCoverageFile; // Line coverage file, just for testing
@@ -269,8 +271,40 @@ class TraceDriver final : public DfgVisitor {
UASSERT_OBJ(vtxp->size() > msb, vtxp, "Traced Vertex too narrow");
UASSERT_OBJ(!m_defaultp || vtxp == m_splicep, vtxp, "Tracing wrong vertex");
// Get the cache entry, which is the resulting driver that is not part of
// the same component as vtxp
// If the currently traced vertex is in a different component,
// then we found what we were looking for. But if it's a splice
// with a corresponding default, we need to keep going as the
// splice does not fully define the value we are seeking.
if (m_sccInfo.get(*vtxp) != m_component && !m_defaultp) {
DfgVertex*& respr
= m_boundaryCache
.emplace(std::piecewise_construct, std::forward_as_tuple(vtxp, msb, lsb),
std::forward_as_tuple(nullptr))
.first->second;
if (!respr) {
respr = vtxp;
// If the result is a splice, we need to insert a temporary for it
// as a splice cannot be fed into arbitray logic
if (DfgVertexSplice* const splicep = respr->cast<DfgVertexSplice>()) {
DfgVertexVar* const tmpp = createTmp("TraceDriver", splicep);
// Note: we can't do 'splicep->replaceWith(tmpp)', as other
// variable sinks of the splice might have a defaultp driver.
tmpp->srcp(splicep);
respr = tmpp;
}
// Apply a Sel to extract the relevant bits if only a part is needed
if (msb != respr->width() - 1 || lsb != 0) {
DfgSel* const selp = make<DfgSel>(respr, msb - lsb + 1);
selp->fromp(respr);
selp->lsb(lsb);
respr = selp;
}
}
resp = respr;
break;
}
// Normal cache for intra-component traces
DfgVertex*& respr = m_cache
.emplace(std::piecewise_construct, //
std::forward_as_tuple(vtxp, msb, lsb), //
@@ -282,28 +316,6 @@ class TraceDriver final : public DfgVisitor {
// If already traced this vtxp/msb/lsb, just use the result.
// This is important to avoid combinatorial explosion when the
// same sub-expression is needed multiple times.
} else if (m_sccInfo.get(*vtxp) != m_component && !m_defaultp) {
// If the currently traced vertex is in a different component,
// then we found what we were looking for. But if it's a splice
// with a corresponding default, we need to keep going as the
// splice does not fully define the value we are seeking.
respr = vtxp;
// If the result is a splice, we need to insert a temporary for it
// as a splice cannot be fed into arbitray logic
if (DfgVertexSplice* const splicep = respr->cast<DfgVertexSplice>()) {
DfgVertexVar* const tmpp = createTmp("TraceDriver", splicep);
// Note: we can't do 'splicep->replaceWith(tmpp)', as other
// variable sinks of the splice might have a defaultp driver.
tmpp->srcp(splicep);
respr = tmpp;
}
// Apply a Sel to extract the relevant bits if only a part is needed
if (msb != respr->width() - 1 || lsb != 0) {
DfgSel* const selp = make<DfgSel>(respr, msb - lsb + 1);
selp->fromp(respr);
selp->lsb(lsb);
respr = selp;
}
} else {
// Otherwise visit the vertex to trace it
VL_RESTORER(m_msb);