Optimize CReset in Dfg (#7737)
Teach DFG about CReset. This is not so much to optimize CReset itself, but to enable synthesizing logic involving CReset, which does appear with automatic variables used only in certain branches
This commit is contained in:
parent
e6a070b93b
commit
ece4d71e5b
|
|
@ -91,6 +91,11 @@ std::unique_ptr<DfgGraph> DfgGraph::clone() const {
|
|||
for (const DfgVertex& vtx : m_opVertices) {
|
||||
switch (vtx.type()) {
|
||||
#include "V3Dfg__gen_clone_cases.h" // From ./astgen
|
||||
case VDfgType::CReset: { // LCOV_EXCL_START - No algorithm actually hits this today
|
||||
DfgCReset* const cp = new DfgCReset{*clonep, vtx.fileline(), vtx.dtype()};
|
||||
vtxp2clonep.emplace(&vtx, cp);
|
||||
break;
|
||||
} // LCOV_EXCL_STOP
|
||||
case VDfgType::Sel: {
|
||||
DfgSel* const cp = new DfgSel{*clonep, vtx.fileline(), vtx.dtype()};
|
||||
cp->lsb(vtx.as<DfgSel>()->lsb());
|
||||
|
|
@ -132,11 +137,14 @@ std::unique_ptr<DfgGraph> DfgGraph::clone() const {
|
|||
VL_UNREACHABLE;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
vtx.v3fatalSrc("Unhandled operation vertex type: " + vtx.typeName());
|
||||
case VDfgType::AstRd: // LCOV_EXCL_START
|
||||
case VDfgType::Const:
|
||||
case VDfgType::VarArray:
|
||||
case VDfgType::VarPacked: {
|
||||
vtx.v3fatalSrc("Vertex should have been handled above: " + vtx.typeName());
|
||||
VL_UNREACHABLE;
|
||||
break;
|
||||
}
|
||||
} // LCOV_EXCL_STOP
|
||||
}
|
||||
}
|
||||
UASSERT(size() == clonep->size(), "Size of clone should be the same");
|
||||
|
|
@ -618,6 +626,10 @@ void DfgVertex::typeCheck(const DfgGraph& dfg) const {
|
|||
CHECK(isPacked(), "Should be Packed type");
|
||||
return;
|
||||
}
|
||||
case VDfgType::CReset: {
|
||||
CHECK(isPacked() || isArray(), "Should be Packed or Array type");
|
||||
return;
|
||||
}
|
||||
case VDfgType::AstRd: {
|
||||
const DfgAstRd& v = *as<DfgAstRd>();
|
||||
CHECK(v.isPacked() || v.isArray(), "Should be Packed or Array type");
|
||||
|
|
|
|||
|
|
@ -125,6 +125,12 @@ class ColorStronglyConnectedComponents final {
|
|||
|
||||
// Initialize state of operation vertices
|
||||
for (const DfgVertex& vtx : m_dfg.opVertices()) {
|
||||
// If it has no inputs or no outputs, it cannot be part of a non-trivial SCC.
|
||||
if (!vtx.nInputs() || !vtx.hasSinks()) {
|
||||
index(vtx) = 0;
|
||||
component(vtx) = 0;
|
||||
continue;
|
||||
}
|
||||
index(vtx) = UNASSIGNED;
|
||||
component(vtx) = UNASSIGNED;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ class V3DfgCse final {
|
|||
|
||||
// Special vertices
|
||||
case VDfgType::Const: // LCOV_EXCL_START
|
||||
case VDfgType::CReset:
|
||||
case VDfgType::VarArray:
|
||||
case VDfgType::VarPacked:
|
||||
case VDfgType::AstRd: // LCOV_EXCL_STOP
|
||||
|
|
@ -170,6 +171,7 @@ class V3DfgCse final {
|
|||
|
||||
// Special vertices
|
||||
case VDfgType::Const: return a.as<DfgConst>()->num().isCaseEq(b.as<DfgConst>()->num());
|
||||
case VDfgType::CReset: return false;
|
||||
|
||||
case VDfgType::VarArray:
|
||||
case VDfgType::VarPacked: // CSE does not combine variables
|
||||
|
|
@ -303,6 +305,10 @@ class V3DfgCse final {
|
|||
for (const DfgVertexVar& vtx : dfg.varVertices()) m_hashCache[vtx] = V3Hash{++varHash};
|
||||
// Pre-hash Ast references, these are all unique like variables
|
||||
for (const DfgVertexAst& vtx : dfg.astVertices()) m_hashCache[vtx] = V3Hash{++varHash};
|
||||
// Pre-hash CReset vertices, these are all unique
|
||||
for (const DfgVertex& vtx : dfg.opVertices()) {
|
||||
if (vtx.is<DfgCReset>()) m_hashCache[vtx] = V3Hash{++varHash};
|
||||
}
|
||||
|
||||
// Similarly pre-hash constants for speed. While we don't combine constants, we do want
|
||||
// expressions using the same constants to be combined, so we do need to hash equal
|
||||
|
|
|
|||
|
|
@ -227,6 +227,13 @@ class DfgToAstVisitor final : DfgVisitor {
|
|||
void visit(DfgConst* vtxp) override { //
|
||||
m_resultp = new AstConst{vtxp->fileline(), vtxp->num()};
|
||||
}
|
||||
void visit(DfgCReset* vtxp) override {
|
||||
DfgVertex* const sinkp = vtxp->singleSink();
|
||||
UASSERT_OBJ(sinkp, vtxp, "CReset should only have one sink");
|
||||
UASSERT_OBJ(sinkp->is<DfgVertexVar>(), sinkp, "CReset should drive a variable");
|
||||
AstVar* const varp = sinkp->as<DfgVertexVar>()->vscp()->varp();
|
||||
m_resultp = new AstCReset{vtxp->fileline(), varp, false};
|
||||
}
|
||||
|
||||
void visit(DfgRep* vtxp) override {
|
||||
FileLine* const flp = vtxp->fileline();
|
||||
|
|
|
|||
|
|
@ -120,6 +120,8 @@ void V3DfgPasses::inlineVars(DfgGraph& dfg) {
|
|||
// Partial driver cannot be inlined
|
||||
if (srcp->is<DfgVertexSplice>()) continue;
|
||||
if (srcp->is<DfgUnitArray>()) continue;
|
||||
// Don't inline CReset
|
||||
if (srcp->is<DfgCReset>()) continue;
|
||||
// Okie dokie, here we go ...
|
||||
vtx.replaceWith(srcp);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1158,7 +1158,7 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
|
||||
// Sel from a partial variable (including narrowed vertex)
|
||||
if (DfgVarPacked* const varp = fromp->cast<DfgVarPacked>()) {
|
||||
if (varp->srcp() && !varp->isVolatile()) {
|
||||
if (varp->srcp() && !varp->isVolatile() && !varp->srcp()->is<DfgCReset>()) {
|
||||
// Must be a splice, otherwise it would have been inlined
|
||||
DfgSplicePacked* splicep = varp->srcp()->as<DfgSplicePacked>();
|
||||
DfgVertex* driverp = nullptr;
|
||||
|
|
|
|||
|
|
@ -89,6 +89,9 @@ class V3DfgPushDownSels final {
|
|||
m_stack.push_back(&vtx);
|
||||
}
|
||||
for (DfgConst& vtx : m_dfg.constVertices()) m_stack.push_back(&vtx);
|
||||
for (DfgVertex& vtx : m_dfg.opVertices()) {
|
||||
if (!vtx.nInputs()) m_stack.push_back(&vtx);
|
||||
}
|
||||
|
||||
// Reverse post order number to assign to next vertex
|
||||
uint32_t rpoNext = m_dfg.size();
|
||||
|
|
|
|||
|
|
@ -100,6 +100,9 @@ class DfgRegularize final {
|
|||
// No need to add a temporary if the single sink is a variable already
|
||||
if (sink.is<DfgVertexVar>()) return false;
|
||||
|
||||
// CReset always needs to be driving a variable
|
||||
if (aVtx.is<DfgCReset>()) return true;
|
||||
|
||||
// Do not inline expressions into a loop body
|
||||
if (const DfgAstRd* const astRdp = sink.cast<DfgAstRd>()) { return astRdp->inLoop(); }
|
||||
|
||||
|
|
|
|||
|
|
@ -384,6 +384,24 @@ class AstToDfgConverter final : public VNVisitor {
|
|||
nodep->user2p(vtxp);
|
||||
}
|
||||
}
|
||||
void visit(AstCReset* nodep) override {
|
||||
UASSERT_OBJ(m_converting, nodep, "AstToDfg visit called without m_converting");
|
||||
UASSERT_OBJ(!nodep->user2p(), nodep, "Already has Dfg vertex");
|
||||
if (unhandled(nodep)) return;
|
||||
|
||||
const DfgDataType* const dtypep = DfgDataType::fromAst(nodep->dtypep());
|
||||
if (!dtypep) {
|
||||
m_foundUnhandled = true;
|
||||
++m_ctx.m_conv.nonRepDType;
|
||||
return;
|
||||
}
|
||||
|
||||
UASSERT_OBJ(!nodep->constructing(), nodep,
|
||||
"CReset should be non-constructing at this stage");
|
||||
|
||||
DfgVertex* const vtxp = make<DfgCReset>(nodep->fileline(), *dtypep);
|
||||
nodep->user2p(vtxp);
|
||||
}
|
||||
void visit(AstReplicate* nodep) override {
|
||||
UASSERT_OBJ(m_converting, nodep, "AstToDfg visit called without m_converting");
|
||||
UASSERT_OBJ(!nodep->user2p(), nodep, "Already has Dfg vertex");
|
||||
|
|
|
|||
|
|
@ -248,6 +248,14 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class DfgCReset final : public DfgVertexNullary {
|
||||
public:
|
||||
DfgCReset(DfgGraph& dfg, FileLine* flp, const DfgDataType& dtype)
|
||||
: DfgVertexNullary{dfg, dfgType(), flp, dtype} {}
|
||||
|
||||
ASTGEN_MEMBERS_DfgCReset;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Unary vertices - 1 inputs
|
||||
|
||||
|
|
|
|||
|
|
@ -570,4 +570,11 @@ module t (
|
|||
wire logic [7:0] func_3 = pkg::branchy(rand_a[7:0], rand_b[7:0]);
|
||||
`signal(FUNC_3, func_3);
|
||||
|
||||
logic [1:0] via_creset;
|
||||
always_comb begin
|
||||
automatic logic [1:0] a /* = AstCReset */;
|
||||
via_creset = a + 2'd1;
|
||||
end
|
||||
`signal(VIA_CRESET, via_creset);
|
||||
|
||||
endmodule
|
||||
|
|
|
|||
Loading…
Reference in New Issue