Optimize CReset in Dfg

This commit is contained in:
Geza Lore 2026-06-05 13:36:24 +01:00
parent e6a070b93b
commit 0278b1e475
11 changed files with 76 additions and 4 deletions

View File

@ -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");

View File

@ -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;
}

View File

@ -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

View File

@ -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();

View File

@ -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);
}

View File

@ -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;

View File

@ -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();

View File

@ -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(); }

View File

@ -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");

View File

@ -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

View File

@ -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