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:
parent
e732f656a9
commit
92b490f2f7
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue