Fix excessive logic replication in Dfg circular driver tracing (#6561) (#6594)

Cache already traced vertices and reuse them on subsequent traces. This
avoids a potential combinatorial explosion in the size of the resulting
circuit.
This commit is contained in:
Geza Lore 2025-10-25 16:07:22 +02:00 committed by GitHub
parent e732f656a9
commit 92b490f2f7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 29 additions and 21 deletions

View File

@ -73,6 +73,8 @@ class TraceDriver final : public DfgVisitor {
uint32_t m_lsb = 0; // LSB to extract from the currently visited Vertex uint32_t m_lsb = 0; // LSB to extract from the currently visited Vertex
uint32_t m_msb = 0; // MSB to extract from the currently visited Vertex uint32_t m_msb = 0; // MSB to extract from the currently visited Vertex
DfgVertex* m_defaultp = nullptr; // When tracing a variable, this is its 'defaultp', if any DfgVertex* m_defaultp = nullptr; // When tracing a variable, this is its 'defaultp', if any
// Result cache for reusing already traced vertices
std::unordered_map<Visited, DfgVertex*, Visited::Hash, Visited::Equal> m_cache;
// Result of tracing the currently visited Vertex. Use SET_RESULT below! // Result of tracing the currently visited Vertex. Use SET_RESULT below!
DfgVertex* m_resp = nullptr; DfgVertex* m_resp = nullptr;
std::vector<DfgVertex*> m_newVtxps; // New vertices created during the traversal std::vector<DfgVertex*> m_newVtxps; // New vertices created during the traversal
@ -155,12 +157,22 @@ class TraceDriver final : public DfgVisitor {
// Push to stack // Push to stack
m_stack.emplace_back(vtxp, msb, lsb); m_stack.emplace_back(vtxp, msb, lsb);
bool& onStackr = m_visited[m_stack.back()]; bool& onStackr = m_visited[m_stack.back()];
// Save onStack before updating
const bool wasOnStack = onStackr;
// We are tracing the vertex now
onStackr = true;
// Check for true combinational cycles // The resulting driver that is not part of m_component
if (onStackr) { DfgVertex* resp = nullptr;
// Pop from stack
m_stack.pop_back();
// Retrieve cache entry
const auto& cachePair = m_cache.emplace(m_stack.back(), nullptr);
DfgVertex*& cachedRespr = cachePair.first->second;
// Trace the vertex
if (wasOnStack) {
// If it was already on the stack, then this is a true
// combinational cycles, terminate the trace.
// Note: could issue a "proper combinational cycle" error here, // Note: could issue a "proper combinational cycle" error here,
// but constructing a legible error message is hard as the Vertex // but constructing a legible error message is hard as the Vertex
// Filelines can be very rough after optimizations (could consider // Filelines can be very rough after optimizations (could consider
@ -168,20 +180,15 @@ class TraceDriver final : public DfgVisitor {
// run mulitple times and report the same error again. There will // run mulitple times and report the same error again. There will
// be an UNOPTFLAT issued during scheduling anyway, and the true // be an UNOPTFLAT issued during scheduling anyway, and the true
// cycle might still settle at run-time. // cycle might still settle at run-time.
resp = nullptr;
// Stop trace } else if (!cachePair.second) {
return nullptr; // 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.
// Trace the vertex resp = cachedRespr;
onStackr = true; } else if (m_vtx2Scc[vtxp] != m_component) {
// If the currently traced vertex is in a different component,
// The resulting driver that is not part of m_component // then we found what we were looking for.
DfgVertex* resp = nullptr;
// If the currently traced vertex is in a different component,
// then we found what we were looking for.
if (m_vtx2Scc[vtxp] != m_component) {
resp = vtxp; resp = vtxp;
// If the result is a splice, we need to insert a temporary for it // If the result is a splice, we need to insert a temporary for it
// as a splice cannot be fed into arbitray logic // as a splice cannot be fed into arbitray logic
@ -212,14 +219,15 @@ class TraceDriver final : public DfgVisitor {
} }
UASSERT_OBJ(!resp || resp->width() == (msb - lsb + 1), vtxp, "Wrong result width"); UASSERT_OBJ(!resp || resp->width() == (msb - lsb + 1), vtxp, "Wrong result width");
// Save to cache
cachedRespr = resp;
// Pop from stack // Pop from stack
onStackr = false; onStackr = false;
m_stack.pop_back(); m_stack.pop_back();
// Done // Done
if (!resp) { if (!resp) UINFO(9, "TraceDriver - Failed to trace vertex of type: " << vtxp->typeName());
UINFO(9, "TraceDriver - Failed to trace vertex of type: " << vtxp->typeName());
}
return resp; return resp;
} }