diff --git a/src/V3Dfg.h b/src/V3Dfg.h index dd3016398..95320daad 100644 --- a/src/V3Dfg.h +++ b/src/V3Dfg.h @@ -815,9 +815,11 @@ void DfgEdge::relinkSrcp(DfgVertex* srcp) { bool DfgVertex::isCheaperThanLoad() const { // Constants if (is()) return true; + // Variables + if (is()) return true; // Array sels are just address computation if (is()) return true; - // Small constant select from variable + // Small select from variable if (const DfgSel* const selp = cast()) { if (!selp->fromp()->is()) return false; if (selp->fromp()->width() <= VL_QUADSIZE) return true; @@ -828,20 +830,32 @@ bool DfgVertex::isCheaperThanLoad() const { // Zero extend of a cheap vertex - Extend(_) was converted to Concat(0, _) if (const DfgConcat* const catp = cast()) { if (catp->width() > VL_QUADSIZE) return false; - const DfgConst* const lCatp = catp->lhsp()->cast(); - if (!lCatp) return false; - if (!lCatp->isZero()) return false; + const DfgConst* const lConstp = catp->lhsp()->cast(); + if (!lConstp || !lConstp->isZero()) return false; return catp->rhsp()->isCheaperThanLoad(); } - // Reduction of a cheap vertex - if (const DfgRedOr* const redOrp = cast()) { - return redOrp->srcp()->isCheaperThanLoad(); + // Reduction of a narrow cheap vertex + if (is() // + || is() // + || is()) { + const DfgVertex* const srcp = as()->srcp(); + return srcp->width() <= VL_QUADSIZE && srcp->isCheaperThanLoad(); } - if (const DfgRedAnd* const redAndp = cast()) { - return redAndp->srcp()->isCheaperThanLoad(); - } - if (const DfgRedXor* const redXorp = cast()) { - return redXorp->srcp()->isCheaperThanLoad(); + // Comparisons of a narrow cheap vertex with constant + if (is() // + || is() // + || is() // + || is() // + || is() // + || is() // + || is() // + || is() // + || is() // + || is()) { + const DfgVertexBinary* const binp = as(); + const DfgVertex* const lhsp = binp->inputp(0); + const DfgVertex* const rhsp = binp->inputp(1); + return lhsp->width() <= VL_QUADSIZE && lhsp->is() && rhsp->isCheaperThanLoad(); } // Otherwise probably not return false; diff --git a/src/V3DfgRegularize.cpp b/src/V3DfgRegularize.cpp index 622bb4648..588dbd52c 100644 --- a/src/V3DfgRegularize.cpp +++ b/src/V3DfgRegularize.cpp @@ -195,24 +195,35 @@ class DfgRegularize final { // Scope cache for below DfgVertex::ScopeCache scopeCache; - // Ensure intermediate values used multiple times are written to variables + // Build map from fanout to list of vertices with that fanout + std::vector> fanout2Vtxps; for (DfgVertex& vtx : m_dfg.opVertices()) { // LValue vertices feed into variables eventually and need no temporaries if (vtx.is()) continue; if (vtx.is()) continue; + // Add to map + const uint32_t fanout = vtx.fanout(); + if (!fanout) continue; + if (fanout >= fanout2Vtxps.size()) fanout2Vtxps.resize(2 * fanout); + fanout2Vtxps[fanout].push_back(&vtx); + } + if (fanout2Vtxps.empty()) return; - if (!needsTemporary(vtx, vtx)) continue; - - // Need to create an intermediate variable - ++m_ctx.m_temporariesIntroduced; - const std::string name = m_dfg.makeUniqueName("Regularize", m_nTmps); - FileLine* const flp = vtx.fileline(); - AstScope* const scopep = vtx.scopep(scopeCache); - DfgVertexVar* const newp = m_dfg.makeNewVar(flp, name, vtx.dtype(), scopep); - ++m_nTmps; - // Replace vertex with the variable, make it drive the variable - vtx.replaceWith(newp); - newp->srcp(&vtx); + // Ensure intermediate values used multiple times are written to variables + for (size_t fanout = fanout2Vtxps.size() - 1; fanout > 0; --fanout) { + for (DfgVertex* const vtxp : fanout2Vtxps[fanout]) { + if (!needsTemporary(*vtxp, *vtxp)) continue; + // Need to create an intermediate variable + ++m_ctx.m_temporariesIntroduced; + const std::string name = m_dfg.makeUniqueName("Regularize", m_nTmps); + FileLine* const flp = vtxp->fileline(); + AstScope* const scopep = vtxp->scopep(scopeCache); + DfgVertexVar* const newp = m_dfg.makeNewVar(flp, name, vtxp->dtype(), scopep); + ++m_nTmps; + // Replace vertex with the variable, make it drive the variable + vtxp->replaceWith(newp); + newp->srcp(vtxp); + } } }