From 3149f4337265b40102a6a55b5bc236f6d93b8d45 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Thu, 23 Apr 2026 10:14:27 +0100 Subject: [PATCH] Internals: Add special Dfg vertex for replication (#7471) --- src/V3AstNodeExpr.h | 1 - src/V3Dfg.cpp | 11 +- src/V3DfgBreakCycles.cpp | 9 +- src/V3DfgCse.cpp | 4 +- src/V3DfgDfgToAst.cpp | 6 ++ src/V3DfgPeephole.cpp | 57 +++++----- src/V3DfgPeepholePatterns.h | 7 +- src/V3DfgSynthesize.cpp | 21 ++++ src/V3DfgVertices.h | 11 ++ test_regress/t/t_dfg_dump_patterns.out | 140 +++++++++++-------------- test_regress/t/t_dfg_peephole.v | 1 + 11 files changed, 149 insertions(+), 119 deletions(-) diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index fa6fa02d6..2d156f3fb 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -3695,7 +3695,6 @@ class AstReplicate final : public AstNodeBiop { // Verilog {rhs{lhs}} - Note rhsp() is the replicate value, not the lhsp() // @astgen alias op1 := srcp // @astgen alias op2 := countp - // @astgen makeDfgVertex public: AstReplicate(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp) : ASTGEN_SUPER_Replicate(fl, lhsp, rhsp) { diff --git a/src/V3Dfg.cpp b/src/V3Dfg.cpp index bdf7eb3a1..df68246aa 100644 --- a/src/V3Dfg.cpp +++ b/src/V3Dfg.cpp @@ -97,6 +97,11 @@ std::unique_ptr DfgGraph::clone() const { vtxp2clonep.emplace(&vtx, cp); break; } + case VDfgType::Rep: { + DfgRep* const cp = new DfgRep{*clonep, vtx.fileline(), vtx.dtype()}; + vtxp2clonep.emplace(&vtx, cp); + break; + } case VDfgType::UnitArray: { DfgUnitArray* const cp = new DfgUnitArray{*clonep, vtx.fileline(), vtx.dtype()}; vtxp2clonep.emplace(&vtx, cp); @@ -712,12 +717,10 @@ void DfgVertex::typeCheck(const DfgGraph& dfg) const { return; } - case VDfgType::Replicate: { - // TODO: model DfgReplicate without an explicit 'countp' which is always constant - const DfgReplicate& v = *as(); + case VDfgType::Rep: { + const DfgRep& v = *as(); CHECK(v.isPacked(), "Should be Packed type"); CHECK(v.srcp()->isPacked(), "'srcp' should be same type"); - CHECK(v.countp()->isPacked(), "'countp' should be Packed type"); CHECK(v.size() % v.srcp()->size() == 0, "Not a replicate"); return; } diff --git a/src/V3DfgBreakCycles.cpp b/src/V3DfgBreakCycles.cpp index 227aece17..73789cb9b 100644 --- a/src/V3DfgBreakCycles.cpp +++ b/src/V3DfgBreakCycles.cpp @@ -374,14 +374,13 @@ class TraceDriver final : public DfgVisitor { SET_RESULT(resp); } - void visit(DfgReplicate* vtxp) override { + void visit(DfgRep* vtxp) override { DfgVertex* const srcp = vtxp->srcp(); const uint32_t sWidth = srcp->width(); // If we need more bits than the source, then we need the whole source if (m_msb - m_lsb + 1 > sWidth) { - DfgReplicate* const repp = make(vtxp, vtxp->width()); + DfgRep* const repp = make(vtxp, vtxp->width()); repp->srcp(trace(srcp, sWidth - 1, 0)); - repp->countp(vtxp->countp()); // Always a DfgConst DfgSel* const resp = make(vtxp, m_msb - m_lsb + 1); resp->fromp(repp); resp->lsb(m_lsb); @@ -757,8 +756,8 @@ class IndependentBits final : public DfgVisitor { m.opSelInto(MASK(lhsp), rhsp->width(), lhsp->width()); } - void visit(DfgReplicate* vtxp) override { - const uint32_t count = vtxp->countp()->as()->toU32(); + void visit(DfgRep* vtxp) override { + const uint32_t count = vtxp->count(); const DfgVertex* const srcp = vtxp->srcp(); const uint32_t sWidth = srcp->width(); V3Number& vMask = MASK(vtxp); diff --git a/src/V3DfgCse.cpp b/src/V3DfgCse.cpp index 5e4d1b93b..abce554ba 100644 --- a/src/V3DfgCse.cpp +++ b/src/V3DfgCse.cpp @@ -118,7 +118,7 @@ class V3DfgCse final { case VDfgType::RedAnd: case VDfgType::RedOr: case VDfgType::RedXor: - case VDfgType::Replicate: + case VDfgType::Rep: case VDfgType::ShiftL: case VDfgType::ShiftR: case VDfgType::ShiftRS: @@ -240,7 +240,7 @@ class V3DfgCse final { case VDfgType::RedAnd: case VDfgType::RedOr: case VDfgType::RedXor: - case VDfgType::Replicate: + case VDfgType::Rep: case VDfgType::ShiftL: case VDfgType::ShiftR: case VDfgType::ShiftRS: diff --git a/src/V3DfgDfgToAst.cpp b/src/V3DfgDfgToAst.cpp index e88966201..6da7bfc8d 100644 --- a/src/V3DfgDfgToAst.cpp +++ b/src/V3DfgDfgToAst.cpp @@ -228,6 +228,12 @@ class DfgToAstVisitor final : DfgVisitor { m_resultp = new AstConst{vtxp->fileline(), vtxp->num()}; } + void visit(DfgRep* vtxp) override { + FileLine* const flp = vtxp->fileline(); + AstNodeExpr* const srcp = convertDfgVertexToAstNodeExpr(vtxp->srcp()); + m_resultp = new AstReplicate{flp, srcp, vtxp->count()}; + } + void visit(DfgSel* vtxp) override { FileLine* const flp = vtxp->fileline(); AstNodeExpr* const fromp = convertDfgVertexToAstNodeExpr(vtxp->fromp()); diff --git a/src/V3DfgPeephole.cpp b/src/V3DfgPeephole.cpp index f2e4b9ce0..c20c6ca32 100644 --- a/src/V3DfgPeephole.cpp +++ b/src/V3DfgPeephole.cpp @@ -130,7 +130,6 @@ template <> const DfgDataType& resultDType (const DfgVertex* lhsp template <> const DfgDataType& resultDType (const DfgVertex* lhsp, const DfgVertex* rhsp) { return lhsp->dtype(); } template <> const DfgDataType& resultDType (const DfgVertex* lhsp, const DfgVertex* rhsp) { return lhsp->dtype(); } template <> const DfgDataType& resultDType (const DfgVertex* lhsp, const DfgVertex* rhsp) { return lhsp->dtype(); } -// template <> const DfgDataType& resultDType (const DfgVertex* lhsp, const DfgVertex* rhsp) { return ; } template <> const DfgDataType& resultDType (const DfgVertex* lhsp, const DfgVertex* rhsp) { return lhsp->dtype(); } template <> const DfgDataType& resultDType (const DfgVertex* lhsp, const DfgVertex* rhsp) { return lhsp->dtype(); } template <> const DfgDataType& resultDType (const DfgVertex* lhsp, const DfgVertex* rhsp) { return lhsp->dtype(); } @@ -178,7 +177,6 @@ template <> void foldOp (V3Number& out, const V3Number& lhs, cons template <> void foldOp (V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opPowSS(lhs, rhs); } template <> void foldOp (V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opPowSU(lhs, rhs); } template <> void foldOp (V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opPowUS(lhs, rhs); } -template <> void foldOp (V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opRepl(lhs, rhs); } template <> void foldOp (V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opShiftL(lhs, rhs); } template <> void foldOp (V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opShiftR(lhs, rhs); } template <> void foldOp (V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opShiftRS(lhs, rhs, lhs.width()); } @@ -409,8 +407,9 @@ class V3DfgPeephole final : public DfgVisitor { // Replicate 'bitp' to 'vtxp->width()' bits DfgVertex* replicate(DfgVertex* vtxp, DfgVertex* bitp) { + UASSERT_OBJ(bitp->dtype() == m_bitDType, vtxp, "Expected 1-bit vertex"); if (vtxp->dtype() == m_bitDType) return bitp; - return make(vtxp, bitp, makeI32(vtxp->fileline(), vtxp->width())); + return make(vtxp, bitp); } // Check two vertex are the same, or the same constant value @@ -1127,7 +1126,7 @@ class V3DfgPeephole final : public DfgVisitor { } } - if (DfgReplicate* const repp = fromp->cast()) { + if (DfgRep* const repp = fromp->cast()) { // If the Sel is wholly into the source of the Replicate, push the Sel through // the Replicate and apply it directly to the source of the Replicate. const uint32_t srcWidth = repp->srcp()->width(); @@ -1135,7 +1134,7 @@ class V3DfgPeephole final : public DfgVisitor { const uint32_t newLsb = lsb % srcWidth; const uint32_t newMsb = newLsb + width - 1; if (newMsb < srcWidth) { - APPLYING(PUSH_SEL_THROUGH_REPLICATE) { + APPLYING(PUSH_SEL_THROUGH_REP) { fromp = repp->srcp(); lsb = newLsb; continue; @@ -1488,10 +1487,10 @@ class V3DfgPeephole final : public DfgVisitor { } { - DfgReplicate* repp = lhsp->cast(); + DfgRep* repp = lhsp->cast(); DfgCond* condp = rhsp->cast(); if (!repp && !condp) { - repp = rhsp->cast(); + repp = rhsp->cast(); condp = lhsp->cast(); } if (repp && condp && repp->srcp()->size() == 1 && !condp->hasMultipleSinks() @@ -1984,24 +1983,22 @@ class V3DfgPeephole final : public DfgVisitor { // Convert various forms to REPLICATE if (isSame(lhsp, rhsp)) { APPLYING(REPLACE_CONCAT_SAME) { - replace(make(vtxp, lhsp, makeI32(flp, 2))); + replace(make(vtxp, lhsp)); return; } } - if (DfgReplicate* const lRepp = lhsp->cast()) { + if (DfgRep* const lRepp = lhsp->cast()) { if (isSame(lRepp->srcp(), rhsp)) { APPLYING(REPLACE_CONCAT_SAME_REP_ON_LHS) { - const uint32_t count = lRepp->countp()->as()->toU32() + 1; - replace(make(vtxp, rhsp, makeI32(flp, count))); + replace(make(vtxp, rhsp)); return; } } } - if (DfgReplicate* const rRepp = rhsp->cast()) { + if (DfgRep* const rRepp = rhsp->cast()) { if (isSame(lhsp, rRepp->srcp())) { APPLYING(REPLACE_CONCAT_SAME_REP_ON_RHS) { - const uint32_t count = rRepp->countp()->as()->toU32() + 1; - replace(make(vtxp, lhsp, makeI32(flp, count))); + replace(make(vtxp, lhsp)); return; } } @@ -2278,23 +2275,34 @@ class V3DfgPeephole final : public DfgVisitor { if (binary(vtxp)) return; } - void visit(DfgReplicate* const vtxp) override { - if (DfgConst* const sConstp = vtxp->srcp()->cast()) { - DfgConst* const cConstp = vtxp->countp()->as(); - APPLYING(FOLD_REPLICATE) { - DfgConst* const resultp = makeZero(vtxp->fileline(), vtxp->width()); - foldOp(resultp->num(), sConstp->num(), cConstp->num()); + void visit(DfgRep* const vtxp) override { + DfgVertex* const srcp = vtxp->srcp(); + FileLine* const flp = vtxp->fileline(); + + if (DfgConst* const sConstp = srcp->cast()) { + APPLYING(FOLD_REP) { + DfgConst* const resultp = makeZero(flp, vtxp->width()); + resultp->num().opRepl(sConstp->num(), vtxp->count()); replace(resultp); return; } } - if (vtxp->dtype() == vtxp->srcp()->dtype()) { - APPLYING(REMOVE_REPLICATE_ONCE) { + if (vtxp->dtype() == srcp->dtype()) { + APPLYING(REMOVE_REP_ONCE) { replace(vtxp->srcp()); return; } } + + if (DfgRep* const sRepp = srcp->cast()) { + if (!sRepp->hasMultipleSinks() || vtxp->width() <= VL_QUADSIZE) { + APPLYING(REPLACE_REP_REP) { + replace(make(vtxp, sRepp->srcp())); + return; + } + } + } } void visit(DfgShiftL* const vtxp) override { @@ -2775,15 +2783,14 @@ class V3DfgPeephole final : public DfgVisitor { if (isOnes(thenp) && isZero(elsep)) { APPLYING(REPLACE_COND_CONST_ONES_ZERO) { - replace(make(vtxp, condp, makeI32(flp, vtxp->width()))); + replace(replicate(vtxp, condp)); return; } } if (isZero(thenp) && isOnes(elsep)) { APPLYING(REPLACE_COND_CONST_ZERO_ONES) { - replace(make(vtxp, make(condp, condp), - makeI32(flp, vtxp->width()))); + replace(replicate(vtxp, make(condp, condp))); return; } } diff --git a/src/V3DfgPeepholePatterns.h b/src/V3DfgPeepholePatterns.h index 05df94530..249130cc2 100644 --- a/src/V3DfgPeepholePatterns.h +++ b/src/V3DfgPeepholePatterns.h @@ -32,7 +32,7 @@ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, FOLD_BINARY) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, FOLD_MUX_FROM_ONES) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, FOLD_MUX_FROM_ZERO) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, FOLD_REPLICATE) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, FOLD_REP) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, FOLD_SEL) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, FOLD_SELF_EQ) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, FOLD_SELF_GT) \ @@ -64,7 +64,7 @@ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, PUSH_REDUCTION_THROUGH_COND_WITH_CONST_BRANCH) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, PUSH_SEL_THROUGH_COND) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, PUSH_SEL_THROUGH_NOT) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, PUSH_SEL_THROUGH_REPLICATE) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, PUSH_SEL_THROUGH_REP) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, PUSH_SEL_THROUGH_SHIFTL) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, PUSH_SEL_THROUGH_SPLICE) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, PUSH_SHIFTL_THROUGH_COND) \ @@ -84,7 +84,7 @@ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REMOVE_NOT_NOT) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REMOVE_OR_WITH_ZERO) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REMOVE_REDUNDANT_ZEXT_ON_RHS_OF_SHIFT) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REMOVE_REPLICATE_ONCE) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REMOVE_REP_ONCE) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REMOVE_SEL_FROM_LHS_OF_CONCAT) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REMOVE_SEL_FROM_RHS_OF_CONCAT) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REMOVE_SHIFTL_ZERO) \ @@ -144,6 +144,7 @@ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_OR_OF_NOT_AND_NEQ) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_OR_OF_NOT_AND_NOT) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_OR_WITH_ONES) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_REP_REP) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_SEL_FROM_SEL) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_SHIFTL_CAT) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_SHIFTL_OVER) \ diff --git a/src/V3DfgSynthesize.cpp b/src/V3DfgSynthesize.cpp index 745b41461..882aff0b8 100644 --- a/src/V3DfgSynthesize.cpp +++ b/src/V3DfgSynthesize.cpp @@ -384,6 +384,26 @@ class AstToDfgConverter final : public VNVisitor { 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"); + if (unhandled(nodep)) return; + + const DfgDataType* const dtypep = DfgDataType::fromAst(nodep->dtypep()); + if (!dtypep) { + m_foundUnhandled = true; + ++m_ctx.m_conv.nonRepDType; + return; + } + + iterate(nodep->srcp()); + if (m_foundUnhandled) return; + + FileLine* const flp = nodep->fileline(); + DfgRep* const vtxp = make(flp, *dtypep); + vtxp->srcp(nodep->srcp()->user2u().to()); + nodep->user2p(vtxp); + } void visit(AstSel* nodep) override { UASSERT_OBJ(m_converting, nodep, "AstToDfg visit called without m_converting"); UASSERT_OBJ(!nodep->user2p(), nodep, "Already has Dfg vertex"); @@ -426,6 +446,7 @@ class AstToDfgConverter final : public VNVisitor { } nodep->user2p(vtxp); } + // The rest of the visit methods for expressions are generated by 'astgen' #include "V3Dfg__gen_ast_to_dfg.h" diff --git a/src/V3DfgVertices.h b/src/V3DfgVertices.h index 7a8fe1040..8ab12c214 100644 --- a/src/V3DfgVertices.h +++ b/src/V3DfgVertices.h @@ -265,6 +265,17 @@ public: std::string srcName(size_t) const override final { return ""; } }; +class DfgRep final : public DfgVertexUnary { + // AstReplicate is binary, but 'countp' is always constant. Represented in + // Dfg as a unary vertex, with the count determined by the data type, + // similar to Extend/ExtendS. +public: + DfgRep(DfgGraph& dfg, FileLine* flp, const DfgDataType& dtype) + : DfgVertexUnary{dfg, dfgType(), flp, dtype} {} + ASTGEN_MEMBERS_DfgRep; + uint32_t count() const { return width() / srcp()->width(); } +}; + class DfgSel final : public DfgVertexUnary { // AstSel is binary, but 'lsbp' is very often constant. As AstSel is fairly // common, we special case as a DfgSel for the constant 'lsbp', and as diff --git a/test_regress/t/t_dfg_dump_patterns.out b/test_regress/t/t_dfg_dump_patterns.out index 0d686ee07..c55e4e620 100644 --- a/test_regress/t/t_dfg_dump_patterns.out +++ b/test_regress/t/t_dfg_dump_patterns.out @@ -1,10 +1,10 @@ DFG patterns with depth 1 8 (CONCAT _:1 _:a):b - 5 (CONST #A):a - 5 (REDXOR _:a*):1 - 5 (VARPACKED _:a*):a + 5 (REDXOR _:a):1 3 (NOT (VARPACKED):a):a* - 3 (REDXOR _:a):1 + 3 (REDXOR _:a*):1 + 3 (REP _:1*):a + 3 (VARPACKED _:a*):a 3 (VARPACKED):a 2 (AND _:a* _:a*):a 1 (AND _:a* _:a*):a* @@ -12,112 +12,94 @@ DFG patterns with depth 1 1 (CONCAT _:1* _:a):b 1 (NOT _:a*):a 1 (REDXOR _:a):1* - 1 (REPLICATE _:1 (CONST #A):a):b* - 1 (REPLICATE _:a (CONST #A):a):b* - 1 (REPLICATE _:a* (CONST #A):a):b - 1 (REPLICATE _:a* (CONST #A):b):b* - 1 (REPLICATE _:a* (CONST #A):b):c* + 1 (REP _:1*):a* + 1 (REP _:a):b* 1 (SEL@0 _:a*):1 1 (SEL@0 _:a*):b - 1 (SEL@A _:a*):1 + 1 (SEL@A _:a*):1* 1 (VARPACKED _:a):a DFG patterns with depth 2 - 3 (CONCAT (REDXOR _:a*):1 (CONCAT _:1 _:b):c):d + 4 (CONCAT (REDXOR _:a):1 (CONCAT _:1 _:b):c):d + 3 (REP (SEL@A _:a*):1*):b 2 (AND (NOT (VARPACKED):a):a* (NOT (VARPACKED):a):a*):a - 2 (CONCAT (REDXOR _:a):1 (CONCAT _:1 _:b):c):d 2 (REDXOR (AND _:a* _:a*):a):1 + 2 (REDXOR (REP _:1*):a):1 1 (AND (NOT (VARPACKED):a):a* (NOT (VARPACKED):a):a*):a* 1 (CONCAT (REDXOR _:a):1 (REDXOR _:b):1*):c 1 (CONCAT (REDXOR _:a):1* (CONCAT _:1 _:b):c):d 1 (CONCAT (REDXOR _:a*):1 (CONCAT _:1 _:1*):b):c + 1 (CONCAT (REDXOR _:a*):1 (CONCAT _:1 _:b):c):d 1 (CONCAT (REDXOR _:a*):1 (CONCAT _:1* _:b):c):d 1 (CONCAT (SEL@0 _:a*):1 (CONCAT _:1 _:b):c):d - 1 (NOT (REPLICATE _:a* (CONST #A):b):b*):b + 1 (NOT (REP _:1*):a*):a 1 (REDXOR (AND _:a* _:a*):a*):1 - 1 (REDXOR (REPLICATE _:1 (CONST #A):a):b*):1 - 1 (REDXOR (REPLICATE _:a (CONST #A):a):b*):1 - 1 (REDXOR (REPLICATE _:a* (CONST #A):a):b):1* - 1 (REDXOR (REPLICATE _:a* (CONST #A):b):b*):1 - 1 (REDXOR (REPLICATE _:a* (CONST #A):b):c*):1 + 1 (REDXOR (REP _:1*):a):1* + 1 (REDXOR (REP _:1*):a*):1 + 1 (REDXOR (REP _:a):b*):1 1 (REDXOR (SEL@0 _:a*):b):1 - 1 (REPLICATE (NOT _:a*):a (CONST #A):a):b* - 1 (REPLICATE (REPLICATE _:1 (CONST #A):a):b* (CONST #B):a):c* - 1 (REPLICATE (REPLICATE _:a* (CONST #A):b):b* (CONST #A):b):c - 1 (REPLICATE (REPLICATE _:a* (CONST #A):b):c* (CONST #A):b):b* - 1 (REPLICATE (SEL@A _:a*):1 (CONST #A):b):c* + 1 (REP (NOT _:a*):a):b* + 1 (REP (SEL@A _:a*):1*):b* 1 (SEL@0 (AND _:a* _:a*):a*):1 - 1 (SEL@0 (REPLICATE _:a (CONST #A):a):b*):c - 1 (SEL@A (AND _:a* _:a*):a*):1 + 1 (SEL@0 (REP _:a):b*):c + 1 (SEL@A (AND _:a* _:a*):a*):1* 1 (VARPACKED (AND _:a* _:a*):a*):a 1 (VARPACKED (CONCAT _:1 _:a):b):b - 1 (VARPACKED (REPLICATE _:1 (CONST #A):a):b*):b - 1 (VARPACKED (REPLICATE _:a (CONST #A):a):b*):b - 1 (VARPACKED (REPLICATE _:a* (CONST #A):b):b*):b - 1 (VARPACKED (REPLICATE _:a* (CONST #A):b):c*):c + 1 (VARPACKED (REP _:1*):a*):a + 1 (VARPACKED (REP _:a):b*):b DFG patterns with depth 3 + 3 (REP (SEL@A (AND _:a* _:a*):a*):1*):b 2 (REDXOR (AND (NOT (VARPACKED):a):a* (NOT (VARPACKED):a):a*):a):1 + 2 (REDXOR (REP (SEL@A _:a*):1*):b):1 1 (CONCAT (REDXOR (AND _:a* _:a*):a):1 (CONCAT (REDXOR _:a):1 (CONCAT _:1 _:b):c):d):e 1 (CONCAT (REDXOR (AND _:a* _:a*):a):1 (CONCAT (SEL@0 _:a*):1 (CONCAT _:1 _:b):c):d):e 1 (CONCAT (REDXOR (AND _:a* _:a*):a*):1 (CONCAT (REDXOR _:a):1 (CONCAT _:1 _:b):c):d):e - 1 (CONCAT (REDXOR (REPLICATE _:1 (CONST #A):a):b*):1 (CONCAT (REDXOR _:c*):1 (CONCAT _:1 _:d):e):f):g - 1 (CONCAT (REDXOR (REPLICATE _:a (CONST #A):a):b*):1 (CONCAT (REDXOR _:c):1 (REDXOR _:b):1*):d):e - 1 (CONCAT (REDXOR (REPLICATE _:a* (CONST #A):b):b*):1 (CONCAT (REDXOR _:c):1* (CONCAT _:1 _:d):e):f):g - 1 (CONCAT (REDXOR (REPLICATE _:a* (CONST #A):b):c*):1 (CONCAT (REDXOR _:b*):1 (CONCAT _:1* _:d):e):f):g - 1 (CONCAT (REDXOR (SEL@0 _:a*):b):1 (REDXOR (REPLICATE _:c* (CONST #A):c):a):1*):d - 1 (CONCAT (SEL@0 (AND _:a* _:a*):a*):1 (CONCAT (REDXOR _:b*):1 (CONCAT _:1 _:c):d):e):b - 1 (CONCAT A:1* (CONCAT (REDXOR _:a*):1 (CONCAT _:1 A:1*):b):c):d | A is (REDXOR (REPLICATE _:e* (CONST #A):e):a):1* - 1 (NOT (REPLICATE (REPLICATE _:a* (CONST #A):b):c* (CONST #A):b):b*):b + 1 (CONCAT (REDXOR (REP _:1*):a):1 (CONCAT (REDXOR _:b):1 (CONCAT _:1 _:c):d):e):f + 1 (CONCAT (REDXOR (REP _:1*):a):1 (CONCAT (REDXOR _:b*):1 (CONCAT _:1* _:c):d):e):f + 1 (CONCAT (REDXOR (REP _:1*):a*):1 (CONCAT (REDXOR _:b):1* (CONCAT _:1 _:c):d):e):f + 1 (CONCAT (REDXOR (REP _:a):b*):1 (CONCAT (REDXOR _:c):1 (REDXOR _:b):1*):d):e + 1 (CONCAT (REDXOR (SEL@0 _:a*):b):1 (REDXOR (REP _:1*):a):1*):c + 1 (CONCAT (SEL@0 (AND _:a* _:a*):a*):1 (CONCAT (REDXOR _:b):1 (CONCAT _:1 _:c):d):e):b + 1 (CONCAT A:1* (CONCAT (REDXOR _:a*):1 (CONCAT _:1 A:1*):b):c):d | A is (REDXOR (REP _:1*):a):1* + 1 (NOT (REP (SEL@A _:a*):1*):b*):b 1 (REDXOR (AND (NOT (VARPACKED):a):a* (NOT (VARPACKED):a):a*):a*):1 - 1 (REDXOR (REPLICATE (NOT _:a*):a (CONST #A):a):b*):1 - 1 (REDXOR (REPLICATE (REPLICATE _:1 (CONST #A):a):b* (CONST #B):a):c*):1 - 1 (REDXOR (REPLICATE (REPLICATE _:a* (CONST #A):b):b* (CONST #A):b):c):1* - 1 (REDXOR (REPLICATE (REPLICATE _:a* (CONST #A):b):c* (CONST #A):b):b*):1 - 1 (REDXOR (REPLICATE (SEL@A _:a*):1 (CONST #A):b):c*):1 - 1 (REDXOR (SEL@0 (REPLICATE _:a (CONST #A):a):b*):c):1 - 1 (REPLICATE (NOT (REPLICATE _:a* (CONST #A):b):b*):b (CONST #A):b):c* - 1 (REPLICATE (REPLICATE (REPLICATE _:1 (CONST #A):a):b* (CONST #B):a):c* (CONST #B):a):a* - 1 (REPLICATE (REPLICATE (REPLICATE _:a* (CONST #A):b):c* (CONST #A):b):b* (CONST #A):b):d - 1 (REPLICATE (REPLICATE (SEL@A _:a*):1 (CONST #A):b):c* (CONST #B):b):d* - 1 (REPLICATE (SEL@A (AND _:a* _:a*):a*):1 (CONST #A):b):c* + 1 (REDXOR (REP (NOT _:a*):a):b*):1 + 1 (REDXOR (REP (SEL@A _:a*):1*):b):1* + 1 (REDXOR (REP (SEL@A _:a*):1*):b*):1 + 1 (REDXOR (SEL@0 (REP _:a):b*):c):1 + 1 (REP (NOT (REP _:1*):a*):a):b* + 1 (REP (SEL@A (AND _:a* _:a*):a*):1*):b* 1 (SEL@0 (AND (NOT (VARPACKED):a):a* (NOT (VARPACKED):a):a*):a*):1 - 1 (SEL@0 (REPLICATE (NOT _:a*):a (CONST #A):a):b*):c - 1 (SEL@A (AND (NOT (VARPACKED):a):a* (NOT (VARPACKED):a):a*):a*):1 + 1 (SEL@0 (REP (NOT _:a*):a):b*):c + 1 (SEL@A (AND (NOT (VARPACKED):a):a* (NOT (VARPACKED):a):a*):a*):1* 1 (VARPACKED (AND (NOT (VARPACKED):a):a* (NOT (VARPACKED):a):a*):a*):a 1 (VARPACKED (CONCAT (REDXOR _:a*):1 (CONCAT _:1 _:b):c):d):d - 1 (VARPACKED (REPLICATE (NOT _:a*):a (CONST #A):a):b*):b - 1 (VARPACKED (REPLICATE (REPLICATE _:1 (CONST #A):a):b* (CONST #B):a):c*):c - 1 (VARPACKED (REPLICATE (REPLICATE _:a* (CONST #A):b):c* (CONST #A):b):b*):b - 1 (VARPACKED (REPLICATE (SEL@A _:a*):1 (CONST #A):b):c*):c + 1 (VARPACKED (REP (NOT _:a*):a):b*):b + 1 (VARPACKED (REP (SEL@A _:a*):1*):b*):b DFG patterns with depth 4 + 3 (REP (SEL@A (AND (NOT (VARPACKED):a):a* (NOT (VARPACKED):a):a*):a*):1*):b + 2 (REDXOR (REP (SEL@A (AND _:a* _:a*):a*):1*):b):1 1 (CONCAT (REDXOR (AND (NOT (VARPACKED):a):a* A:a*):a):1 (CONCAT (REDXOR (AND A:a* _:a*):a):1 (CONCAT (SEL@0 _:a*):1 (CONCAT _:1 _:b):c):d):e):f | A is (NOT (VARPACKED):a):a* - 1 (CONCAT (REDXOR (AND (NOT (VARPACKED):a):a* A:a*):a):1 (CONCAT (SEL@0 (AND A:a* _:a*):a*):1 (CONCAT (REDXOR _:b*):1 (CONCAT _:1 _:c):d):e):b):f | A is (NOT (VARPACKED):a):a* + 1 (CONCAT (REDXOR (AND (NOT (VARPACKED):a):a* A:a*):a):1 (CONCAT (SEL@0 (AND A:a* _:a*):a*):1 (CONCAT (REDXOR _:b):1 (CONCAT _:1 _:c):d):e):b):f | A is (NOT (VARPACKED):a):a* 1 (CONCAT (REDXOR (AND (NOT (VARPACKED):a):a* A:a*):a*):1 (CONCAT (REDXOR (AND A:a* _:a*):a):1 (CONCAT (REDXOR _:a):1 (CONCAT _:1 _:b):c):d):e):f | A is (NOT (VARPACKED):a):a* - 1 (CONCAT (REDXOR (SEL@0 (REPLICATE _:a (CONST #A):a):b*):c):1 (REDXOR (REPLICATE (REPLICATE _:d* (CONST #A):a):a* (CONST #A):a):b):1*):e - 1 (CONCAT (REDXOR A:a*):1 (CONCAT (REDXOR (REPLICATE A:a* (CONST #A):b):b*):1 (CONCAT (REDXOR _:c):1* (CONCAT _:1 _:d):e):f):g):h | A is (REPLICATE (REPLICATE _:1 (CONST #B):b):i* (CONST #A):b):a* - 1 (CONCAT (REDXOR A:a*):1 (CONCAT (REDXOR (REPLICATE A:a* (CONST #A):b):c*):1 (CONCAT (REDXOR _:b*):1 (CONCAT _:1* _:d):e):f):g):h | A is (REPLICATE (SEL@A _:e*):1 (CONST #B):b):a* - 1 (CONCAT (REDXOR A:a*):1 (CONCAT (REDXOR (SEL@0 A:a*):b):1 (REDXOR (REPLICATE B:c* (CONST #A):c):a):1*):d):e | A is (REPLICATE (NOT B:c*):c (CONST #A):c):a* | B is _:c* - 1 (CONCAT (REDXOR A:a*):1 (CONCAT B:1* (CONCAT (REDXOR _:b*):1 (CONCAT _:1 B:1*):c):d):e):f | A is (REPLICATE (REPLICATE _:g* (CONST #A):a):h* (CONST #A):a):a* | B is (REDXOR (REPLICATE A:a* (CONST #A):a):b):1* - 1 (CONCAT (SEL@0 (AND (NOT (VARPACKED):a):a* (NOT (VARPACKED):a):a*):a*):1 (CONCAT (REDXOR (REPLICATE _:1 (CONST #A):b):c*):1 (CONCAT (REDXOR _:d*):1 (CONCAT _:1 _:a):e):f):g):c - 1 (CONCAT A:1* (CONCAT (REDXOR (REPLICATE _:a (CONST #A):a):b*):1 (CONCAT (REDXOR _:c):1 A:1*):d):e):f | A is (REDXOR B:b):1* | B is (REPLICATE (REPLICATE _:g* (CONST #A):a):a* (CONST #A):a):b - 1 (NOT (REPLICATE (REPLICATE (REPLICATE _:1 (CONST #A):a):b* (CONST #B):a):c* (CONST #B):a):a*):a - 1 (REDXOR (REPLICATE (NOT (REPLICATE _:a* (CONST #A):b):b*):b (CONST #A):b):c*):1 - 1 (REDXOR (REPLICATE (REPLICATE (REPLICATE _:1 (CONST #A):a):b* (CONST #B):a):c* (CONST #B):a):a*):1 - 1 (REDXOR (REPLICATE (REPLICATE (REPLICATE _:a* (CONST #A):b):c* (CONST #A):b):b* (CONST #A):b):d):1* - 1 (REDXOR (REPLICATE (REPLICATE (SEL@A _:a*):1 (CONST #A):b):c* (CONST #B):b):d*):1 - 1 (REDXOR (REPLICATE (SEL@A (AND _:a* _:a*):a*):1 (CONST #A):b):c*):1 - 1 (REDXOR (SEL@0 (REPLICATE (NOT _:a*):a (CONST #A):a):b*):c):1 - 1 (REPLICATE (NOT (REPLICATE (REPLICATE _:a* (CONST #A):b):c* (CONST #A):b):b*):b (CONST #A):b):d* - 1 (REPLICATE (REPLICATE (REPLICATE (REPLICATE _:1 (CONST #A):a):b* (CONST #B):a):c* (CONST #B):a):a* (CONST #B):a):d - 1 (REPLICATE (REPLICATE (REPLICATE (SEL@A _:a*):1 (CONST #A):b):c* (CONST #B):b):d* (CONST #B):b):b* - 1 (REPLICATE (REPLICATE (SEL@A (AND _:a* _:a*):a*):1 (CONST #A):b):c* (CONST #B):b):d* - 1 (REPLICATE (SEL@A (AND (NOT (VARPACKED):a):a* (NOT (VARPACKED):a):a*):a*):1 (CONST #A):b):c* - 1 (SEL@0 (REPLICATE (NOT (REPLICATE _:a* (CONST #A):b):b*):b (CONST #A):b):c*):d + 1 (CONCAT (REDXOR (REP A:1*):a):1 (CONCAT (REDXOR (REP A:1*):b):1 (CONCAT (REDXOR _:c*):1 (CONCAT _:1* _:d):e):f):g):h | A is (SEL@A _:e*):1* + 1 (CONCAT (REDXOR (REP A:1*):a):1 (CONCAT (REDXOR (REP A:1*):b*):1 (CONCAT (REDXOR _:c):1* (CONCAT _:1 _:d):e):f):g):h | A is (SEL@A _:f*):1* + 1 (CONCAT (REDXOR (REP A:1*):a*):1 (CONCAT B:1* (CONCAT (REDXOR _:b*):1 (CONCAT _:1 B:1*):c):d):e):f | A is (SEL@A _:e*):1* | B is (REDXOR (REP A:1*):b):1* + 1 (CONCAT (REDXOR (SEL@0 (REP _:a):b*):c):1 (REDXOR (REP (SEL@A _:d*):1*):b):1*):e + 1 (CONCAT (REDXOR A:a*):1 (CONCAT (REDXOR (SEL@0 A:a*):b):1 (REDXOR (REP _:1*):a):1*):c):d | A is (REP (NOT _:e*):e):a* + 1 (CONCAT (SEL@0 (AND (NOT (VARPACKED):a):a* (NOT (VARPACKED):a):a*):a*):1 (CONCAT (REDXOR (REP _:1*):b):1 (CONCAT (REDXOR _:c):1 (CONCAT _:1 _:a):d):e):f):b + 1 (CONCAT A:1* (CONCAT (REDXOR (REP _:a):b*):1 (CONCAT (REDXOR _:c):1 A:1*):d):e):f | A is (REDXOR B:b):1* | B is (REP (SEL@A _:f*):1*):b + 1 (NOT (REP (SEL@A (AND _:a* _:a*):a*):1*):b*):b + 1 (REDXOR (REP (NOT (REP _:1*):a*):a):b*):1 + 1 (REDXOR (REP (SEL@A (AND _:a* _:a*):a*):1*):b):1* + 1 (REDXOR (REP (SEL@A (AND _:a* _:a*):a*):1*):b*):1 + 1 (REDXOR (SEL@0 (REP (NOT _:a*):a):b*):c):1 + 1 (REP (NOT (REP (SEL@A _:a*):1*):b*):b):c* + 1 (REP (SEL@A (AND (NOT (VARPACKED):a):a* (NOT (VARPACKED):a):a*):a*):1*):b* + 1 (SEL@0 (REP (NOT (REP _:1*):a*):a):b*):c 1 (VARPACKED (CONCAT (REDXOR (AND _:a* _:a*):a*):1 (CONCAT (REDXOR _:a):1 (CONCAT _:1 _:b):c):d):e):e - 1 (VARPACKED (REPLICATE (NOT (REPLICATE _:a* (CONST #A):b):b*):b (CONST #A):b):c*):c - 1 (VARPACKED (REPLICATE (REPLICATE (REPLICATE _:1 (CONST #A):a):b* (CONST #B):a):c* (CONST #B):a):a*):a - 1 (VARPACKED (REPLICATE (REPLICATE (SEL@A _:a*):1 (CONST #A):b):c* (CONST #B):b):d*):d - 1 (VARPACKED (REPLICATE (SEL@A (AND _:a* _:a*):a*):1 (CONST #A):b):c*):c + 1 (VARPACKED (REP (NOT (REP _:1*):a*):a):b*):b + 1 (VARPACKED (REP (SEL@A (AND _:a* _:a*):a*):1*):b*):b diff --git a/test_regress/t/t_dfg_peephole.v b/test_regress/t/t_dfg_peephole.v index 0d88de5d9..8ec285978 100644 --- a/test_regress/t/t_dfg_peephole.v +++ b/test_regress/t/t_dfg_peephole.v @@ -326,6 +326,7 @@ module t ( `signal(REMOVE_NEQ_BIT_0, 1'b0 != rand_a[0]); `signal(REPLACE_NEQ_BIT_1, 1'b1 != rand_a[0]); `signal(REPLACE_COND_INSERT, rand_a[0] ? {rand_b[63:40], {1'd0, rand_b[38:0]}} : rand_b); + `signal(REPLACE_REP_REP, {2{({3{rand_a[0]}})}}); // Operators that should work wiht mismatched widths `signal(MISMATCHED_ShiftL,const_a << 4'd2);