Optimize temporary insertion in Dfg (#7459)
Insert temporaries for highest fanout vertices first. Omit them for cheap comparisons.
This commit is contained in:
parent
a1a8b9624c
commit
686594b4ab
38
src/V3Dfg.h
38
src/V3Dfg.h
|
|
@ -815,9 +815,11 @@ void DfgEdge::relinkSrcp(DfgVertex* srcp) {
|
|||
bool DfgVertex::isCheaperThanLoad() const {
|
||||
// Constants
|
||||
if (is<DfgConst>()) return true;
|
||||
// Variables
|
||||
if (is<DfgVertexVar>()) return true;
|
||||
// Array sels are just address computation
|
||||
if (is<DfgArraySel>()) return true;
|
||||
// Small constant select from variable
|
||||
// Small select from variable
|
||||
if (const DfgSel* const selp = cast<DfgSel>()) {
|
||||
if (!selp->fromp()->is<DfgVarPacked>()) 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<DfgConcat>()) {
|
||||
if (catp->width() > VL_QUADSIZE) return false;
|
||||
const DfgConst* const lCatp = catp->lhsp()->cast<DfgConst>();
|
||||
if (!lCatp) return false;
|
||||
if (!lCatp->isZero()) return false;
|
||||
const DfgConst* const lConstp = catp->lhsp()->cast<DfgConst>();
|
||||
if (!lConstp || !lConstp->isZero()) return false;
|
||||
return catp->rhsp()->isCheaperThanLoad();
|
||||
}
|
||||
// Reduction of a cheap vertex
|
||||
if (const DfgRedOr* const redOrp = cast<DfgRedOr>()) {
|
||||
return redOrp->srcp()->isCheaperThanLoad();
|
||||
// Reduction of a narrow cheap vertex
|
||||
if (is<DfgRedOr>() //
|
||||
|| is<DfgRedAnd>() //
|
||||
|| is<DfgRedXor>()) {
|
||||
const DfgVertex* const srcp = as<DfgVertexUnary>()->srcp();
|
||||
return srcp->width() <= VL_QUADSIZE && srcp->isCheaperThanLoad();
|
||||
}
|
||||
if (const DfgRedAnd* const redAndp = cast<DfgRedAnd>()) {
|
||||
return redAndp->srcp()->isCheaperThanLoad();
|
||||
}
|
||||
if (const DfgRedXor* const redXorp = cast<DfgRedXor>()) {
|
||||
return redXorp->srcp()->isCheaperThanLoad();
|
||||
// Comparisons of a narrow cheap vertex with constant
|
||||
if (is<DfgEq>() //
|
||||
|| is<DfgNeq>() //
|
||||
|| is<DfgLt>() //
|
||||
|| is<DfgLte>() //
|
||||
|| is<DfgGt>() //
|
||||
|| is<DfgGte>() //
|
||||
|| is<DfgLtS>() //
|
||||
|| is<DfgLteS>() //
|
||||
|| is<DfgGtS>() //
|
||||
|| is<DfgGteS>()) {
|
||||
const DfgVertexBinary* const binp = as<DfgVertexBinary>();
|
||||
const DfgVertex* const lhsp = binp->inputp(0);
|
||||
const DfgVertex* const rhsp = binp->inputp(1);
|
||||
return lhsp->width() <= VL_QUADSIZE && lhsp->is<DfgConst>() && rhsp->isCheaperThanLoad();
|
||||
}
|
||||
// Otherwise probably not
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -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<std::vector<DfgVertex*>> fanout2Vtxps;
|
||||
for (DfgVertex& vtx : m_dfg.opVertices()) {
|
||||
// LValue vertices feed into variables eventually and need no temporaries
|
||||
if (vtx.is<DfgVertexSplice>()) continue;
|
||||
if (vtx.is<DfgUnitArray>()) 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue