From a83043d7355b97d92659ca10a1106dd26200c4c9 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Wed, 5 Oct 2022 10:36:28 +0100 Subject: [PATCH] DfgPeephole: Rework folding of associative operations Allow constant folding through adjacent nodes of all associative operations, for example '((a & 2) & 3)' or '(3 & (2 & a))' can now be folded into '(a & 2)' and '(2 & a)' respectively. Also improve speed of making associative expression trees right leaning by using rotation of the existing vertices whenever instead of allocation of new nodes. --- src/V3Dfg.h | 3 +- src/V3DfgPeephole.cpp | 319 +++++++++++++++++------------- src/V3DfgPeephole.h | 6 +- test_regress/t/t_dfg_peephole.cpp | 3 + test_regress/t/t_dfg_peephole.v | 26 ++- 5 files changed, 210 insertions(+), 147 deletions(-) diff --git a/src/V3Dfg.h b/src/V3Dfg.h index e0745dad2..e4a6d308f 100644 --- a/src/V3Dfg.h +++ b/src/V3Dfg.h @@ -226,7 +226,7 @@ class DfgVertex VL_NOT_FINAL { protected: DfgEdge* m_sinksp = nullptr; // List of sinks of this vertex FileLine* const m_filelinep; // Source location - AstNodeDType* m_dtypep = nullptr; // Data type of the result of this vertex + AstNodeDType* m_dtypep; // Data type of the result of this vertex - mutable for efficiency const VDfgType m_type; // CONSTRUCTOR @@ -297,6 +297,7 @@ public: FileLine* fileline() const { return m_filelinep; } // The data type of the result of the nodes AstNodeDType* dtypep() const { return m_dtypep; } + void dtypep(AstNodeDType* nodep) { m_dtypep = nodep; } // The type of this vertex VDfgType type() const { return m_type; } diff --git a/src/V3DfgPeephole.cpp b/src/V3DfgPeephole.cpp index 79c7cd0c6..6a6542a25 100644 --- a/src/V3DfgPeephole.cpp +++ b/src/V3DfgPeephole.cpp @@ -200,6 +200,122 @@ class V3DfgPeephole final : public DfgVisitor { return false; } + // Rotate the expression tree rooted at 'vtxp' to the right ('vtxp->lhsp()' becomes root, + // producing a right-leaning tree). Warning: only valid for associative operations. + template + void rotateRight(Vertex* vtxp) { + static_assert(std::is_base_of::value, "Must invoke on binary"); + static_assert(std::is_final::value, "Must invoke on final class"); + DfgVertexBinary* const ap = vtxp; + DfgVertexBinary* const bp = vtxp->lhsp()->template as(); + UASSERT_OBJ(!bp->hasMultipleSinks(), vtxp, "Can't rotate a non-tree"); + ap->replaceWith(bp); + ap->lhsp(bp->rhsp()); + bp->rhsp(ap); + // Concatenation dtypes need to be fixed up, other associative nodes preserve types + if VL_CONSTEXPR_CXX17 (std::is_same::value) { + ap->dtypep(dtypeForWidth(ap->lhsp()->width() + ap->rhsp()->width())); + bp->dtypep(dtypeForWidth(bp->lhsp()->width() + bp->rhsp()->width())); + } + } + + // Transformations that apply to all associative binary vertices. + // Returns true if vtxp was replaced. + template + bool associativeBinary(Vertex* vtxp) { + static_assert(std::is_base_of::value, "Must invoke on binary"); + static_assert(std::is_final::value, "Must invoke on final class"); + + DfgVertex* const lhsp = vtxp->lhsp(); + DfgVertex* const rhsp = vtxp->rhsp(); + FileLine* const flp = vtxp->fileline(); + + DfgConst* const lConstp = lhsp->cast(); + DfgConst* const rConstp = rhsp->cast(); + + if (lConstp && rConstp) { + APPLYING(FOLD_ASSOC_BINARY) { + DfgConst* const resultp = makeZero(flp, vtxp->width()); + foldOp(resultp->num(), lConstp->num(), rConstp->num()); + vtxp->replaceWith(resultp); + return true; + } + } + + if (lConstp) { + if (Vertex* const rVtxp = rhsp->cast()) { + if (DfgConst* const rlConstp = rVtxp->lhsp()->template cast()) { + APPLYING(FOLD_ASSOC_BINARY_LHS_OF_RHS) { + // Fold constants + const uint32_t width = std::is_same::value + ? lConstp->width() + rlConstp->width() + : vtxp->width(); + DfgConst* const constp = makeZero(flp, width); + foldOp(constp->num(), lConstp->num(), rlConstp->num()); + + // Replace vertex + if VL_CONSTEXPR_CXX17 (!std::is_same::value) { + rVtxp->lhsp(constp); + vtxp->replaceWith(rVtxp); + } else if (!rVtxp->hasMultipleSinks()) { + rVtxp->lhsp(constp); + rVtxp->dtypep(vtxp->dtypep()); + vtxp->replaceWith(rVtxp); + } else { + Vertex* const resp = new Vertex{m_dfg, flp, vtxp->dtypep()}; + resp->lhsp(constp); + resp->rhsp(rVtxp->rhsp()); + vtxp->replaceWith(resp); + } + return true; + } + } + } + } + + if (rConstp) { + if (Vertex* const lVtxp = lhsp->cast()) { + if (DfgConst* const lrConstp = lVtxp->rhsp()->template cast()) { + APPLYING(FOLD_ASSOC_BINARY_RHS_OF_LHS) { + // Fold constants + const uint32_t width = std::is_same::value + ? lrConstp->width() + rConstp->width() + : vtxp->width(); + DfgConst* const constp = makeZero(flp, width); + foldOp(constp->num(), lrConstp->num(), rConstp->num()); + + // Replace vertex + if VL_CONSTEXPR_CXX17 (!std::is_same::value) { + lVtxp->rhsp(constp); + vtxp->replaceWith(lVtxp); + } else if (!lVtxp->hasMultipleSinks()) { + lVtxp->rhsp(constp); + lVtxp->dtypep(vtxp->dtypep()); + vtxp->replaceWith(lVtxp); + } else { + Vertex* const resp = new Vertex{m_dfg, flp, vtxp->dtypep()}; + resp->lhsp(lVtxp->lhsp()); + resp->rhsp(constp); + vtxp->replaceWith(resp); + } + return true; + } + } + } + } + + // Make associative trees right leaning to reduce pattern variations, and for better CSE + while (vtxp->lhsp()->template is() && !vtxp->lhsp()->hasMultipleSinks()) { + APPLYING(RIGHT_LEANING_ASSOC) { + rotateRight(vtxp); + continue; + } + break; + } + + return false; + } + // Transformations that apply to all commutative binary vertices void commutativeBinary(DfgVertexBinary* vtxp) { DfgVertex* const lhsp = vtxp->source<0>(); @@ -237,22 +353,6 @@ class V3DfgPeephole final : public DfgVisitor { } } - // Transformations that apply to all associative binary vertices - void associativeBinary(DfgVertexBinary* vtxp) { - DfgVertex* const lhsp = vtxp->lhsp(); - - // Make associative trees right leaning (for better CSE opportunities) - if (lhsp->type() == vtxp->type() && !lhsp->hasMultipleSinks()) { - DfgVertexBinary* const lBinp = lhsp->as(); - APPLYING(RIGHT_LEANING_ASSOC) { - vtxp->replaceWith(lBinp); - vtxp->lhsp(lBinp->rhsp()); - lBinp->rhsp(vtxp); - return; - } - } - } - // Bitwise operation with one side Const, and the other side a Concat template bool tryPushBitwiseOpThroughConcat(Vertex* vtxp, DfgConst* constp, DfgConcat* concatp) { @@ -589,10 +689,9 @@ class V3DfgPeephole final : public DfgVisitor { UASSERT_OBJ(vtxp->width() == vtxp->lhsp()->width(), vtxp, "Mismatched LHS width"); UASSERT_OBJ(vtxp->width() == vtxp->rhsp()->width(), vtxp, "Mismatched RHS width"); - if (foldBinary(vtxp)) return; + if (associativeBinary(vtxp)) return; commutativeBinary(vtxp); - associativeBinary(vtxp); DfgVertex* const lhsp = vtxp->lhsp(); DfgVertex* const rhsp = vtxp->rhsp(); @@ -667,10 +766,9 @@ class V3DfgPeephole final : public DfgVisitor { UASSERT_OBJ(vtxp->width() == vtxp->lhsp()->width(), vtxp, "Mismatched LHS width"); UASSERT_OBJ(vtxp->width() == vtxp->rhsp()->width(), vtxp, "Mismatched RHS width"); - if (foldBinary(vtxp)) return; + if (associativeBinary(vtxp)) return; commutativeBinary(vtxp); - associativeBinary(vtxp); DfgVertex* const lhsp = vtxp->lhsp(); DfgVertex* const rhsp = vtxp->rhsp(); @@ -773,10 +871,9 @@ class V3DfgPeephole final : public DfgVisitor { UASSERT_OBJ(vtxp->width() == vtxp->lhsp()->width(), vtxp, "Mismatched LHS width"); UASSERT_OBJ(vtxp->width() == vtxp->rhsp()->width(), vtxp, "Mismatched RHS width"); - if (foldBinary(vtxp)) return; + if (associativeBinary(vtxp)) return; commutativeBinary(vtxp); - associativeBinary(vtxp); DfgVertex* const lhsp = vtxp->lhsp(); DfgVertex* const rhsp = vtxp->rhsp(); @@ -814,10 +911,9 @@ class V3DfgPeephole final : public DfgVisitor { UASSERT_OBJ(vtxp->width() == vtxp->lhsp()->width(), vtxp, "Mismatched LHS width"); UASSERT_OBJ(vtxp->width() == vtxp->rhsp()->width(), vtxp, "Mismatched RHS width"); - if (foldBinary(vtxp)) return; + if (associativeBinary(vtxp)) return; commutativeBinary(vtxp); - associativeBinary(vtxp); } void visit(DfgArraySel* vtxp) override { @@ -835,133 +931,70 @@ class V3DfgPeephole final : public DfgVisitor { } void visit(DfgConcat* vtxp) override { - UASSERT_OBJ(vtxp->width() == vtxp->lhsp()->width() + vtxp->rhsp()->width(), vtxp, - "Inconsisend Concat"); + if (associativeBinary(vtxp)) return; - if (foldBinary(vtxp)) return; + UASSERT_OBJ(vtxp->width() == vtxp->lhsp()->width() + vtxp->rhsp()->width(), vtxp, + "Inconsistent Concat"); DfgVertex* const lhsp = vtxp->lhsp(); DfgVertex* const rhsp = vtxp->rhsp(); FileLine* const flp = vtxp->fileline(); - // Make concat trees right leaning (for better CSE opportunities) - if (DfgConcat* const lConcatp = lhsp->cast()) { - if (!lConcatp->hasMultipleSinks()) { - APPLYING(RIGHT_LEANING_CONCAT) { - const uint32_t topWidth = lConcatp->rhsp()->width() + rhsp->width(); - DfgConcat* const topp = new DfgConcat{m_dfg, flp, dtypeForWidth(topWidth)}; - DfgConcat* const botp = new DfgConcat{m_dfg, flp, vtxp->dtypep()}; - topp->rhsp(rhsp); - topp->lhsp(lConcatp->rhsp()); - botp->rhsp(topp); - botp->lhsp(lConcatp->lhsp()); - vtxp->replaceWith(botp); - return; - } - } - } - - { - const auto joinConsts - = [this](DfgConst* lConstp, DfgConst* rConstp, FileLine* flp) -> DfgConst* { - DfgConst* const newConstp = makeZero(flp, lConstp->width() + rConstp->width()); - newConstp->num().opSelInto(rConstp->num(), 0, rConstp->width()); - newConstp->num().opSelInto(lConstp->num(), rConstp->width(), lConstp->width()); - return newConstp; - }; - - DfgConst* const lConstp = lhsp->cast(); - DfgConst* const rConstp = rhsp->cast(); - - if (lConstp) { - if (DfgConcat* const rConcatp = rhsp->cast()) { - if (DfgConst* const rlConstp = rConcatp->lhsp()->cast()) { - APPLYING(REPLACE_NESTED_CONCAT_OF_CONSTS_ON_LHS) { - DfgConst* const joinedConstp = joinConsts(lConstp, rlConstp, flp); - DfgConcat* const replacementp - = new DfgConcat{m_dfg, flp, vtxp->dtypep()}; - replacementp->lhsp(joinedConstp); - replacementp->rhsp(rConcatp->rhsp()); + if (lhsp->isZero()) { + DfgConst* const lConstp = lhsp->as(); + if (DfgSel* const rSelp = rhsp->cast()) { + if (DfgConst* const rSelLsbConstp = rSelp->lsbp()->cast()) { + if (vtxp->width() == rSelp->fromp()->width() + && rSelLsbConstp->toU32() == lConstp->width()) { + const uint32_t rSelWidth = rSelp->widthp()->as()->toU32(); + UASSERT_OBJ(lConstp->width() + rSelWidth == vtxp->width(), vtxp, + "Inconsistent"); + APPLYING(REPLACE_CONCAT_ZERO_AND_SEL_TOP_WITH_SHIFTR) { + DfgShiftR* const replacementp + = new DfgShiftR{m_dfg, flp, vtxp->dtypep()}; + replacementp->lhsp(rSelp->fromp()); + replacementp->rhsp(makeI32(flp, lConstp->width())); vtxp->replaceWith(replacementp); return; } } } - - if (lConstp->isZero()) { - if (DfgSel* const rSelp = rhsp->cast()) { - if (DfgConst* const rSelLsbConstp = rSelp->lsbp()->cast()) { - if (vtxp->width() == rSelp->fromp()->width() - && rSelLsbConstp->toU32() == lConstp->width()) { - const uint32_t rSelWidth - = rSelp->widthp()->as()->toU32(); - UASSERT_OBJ(lConstp->width() + rSelWidth == vtxp->width(), vtxp, - "Inconsistent"); - APPLYING(REPLACE_CONCAT_ZERO_AND_SEL_TOP_WITH_SHIFTR) { - DfgShiftR* const replacementp - = new DfgShiftR{m_dfg, flp, vtxp->dtypep()}; - replacementp->lhsp(rSelp->fromp()); - replacementp->rhsp(makeI32(flp, lConstp->width())); - vtxp->replaceWith(replacementp); - return; - } - } - } - } - } - } - - if (rConstp) { - if (DfgConcat* const lConcatp = lhsp->cast()) { - if (DfgConst* const lrConstp = lConcatp->rhsp()->cast()) { - APPLYING(REPLACE_NESTED_CONCAT_OF_CONSTS_ON_RHS) { - DfgConst* const joinedConstp = joinConsts(lrConstp, rConstp, flp); - DfgConcat* const replacementp - = new DfgConcat{m_dfg, flp, vtxp->dtypep()}; - replacementp->lhsp(lConcatp->lhsp()); - replacementp->rhsp(joinedConstp); - vtxp->replaceWith(replacementp); - return; - } - } - } - - if (rConstp->isZero()) { - if (DfgSel* const lSelp = lhsp->cast()) { - if (DfgConst* const lSelLsbConstp = lSelp->lsbp()->cast()) { - if (vtxp->width() == lSelp->fromp()->width() - && lSelLsbConstp->toU32() == 0) { - const uint32_t lSelWidth - = lSelp->widthp()->as()->toU32(); - UASSERT_OBJ(lSelWidth + rConstp->width() == vtxp->width(), vtxp, - "Inconsistent"); - APPLYING(REPLACE_CONCAT_SEL_BOTTOM_AND_ZERO_WITH_SHIFTL) { - DfgShiftL* const replacementp - = new DfgShiftL{m_dfg, flp, vtxp->dtypep()}; - replacementp->lhsp(lSelp->fromp()); - replacementp->rhsp(makeI32(flp, rConstp->width())); - vtxp->replaceWith(replacementp); - return; - } - } - } - } - } } } - { - DfgNot* const lNot = lhsp->cast(); - DfgNot* const rNot = rhsp->cast(); - if (lNot && rNot && !lNot->hasMultipleSinks() && !rNot->hasMultipleSinks()) { - APPLYING(PUSH_CONCAT_THROUGH_NOTS) { - vtxp->lhsp(lNot->srcp()); - vtxp->rhsp(rNot->srcp()); - DfgNot* const replacementp = new DfgNot{m_dfg, flp, vtxp->dtypep()}; - vtxp->replaceWith(replacementp); - replacementp->srcp(vtxp); - return; + if (rhsp->isZero()) { + DfgConst* const rConstp = rhsp->as(); + if (DfgSel* const lSelp = lhsp->cast()) { + if (DfgConst* const lSelLsbConstp = lSelp->lsbp()->cast()) { + if (vtxp->width() == lSelp->fromp()->width() && lSelLsbConstp->toU32() == 0) { + const uint32_t lSelWidth = lSelp->widthp()->as()->toU32(); + UASSERT_OBJ(lSelWidth + rConstp->width() == vtxp->width(), vtxp, + "Inconsistent"); + APPLYING(REPLACE_CONCAT_SEL_BOTTOM_AND_ZERO_WITH_SHIFTL) { + DfgShiftL* const replacementp + = new DfgShiftL{m_dfg, flp, vtxp->dtypep()}; + replacementp->lhsp(lSelp->fromp()); + replacementp->rhsp(makeI32(flp, rConstp->width())); + vtxp->replaceWith(replacementp); + return; + } + } + } + } + } + + if (DfgNot* const lNot = lhsp->cast()) { + if (DfgNot* const rNot = rhsp->cast()) { + if (!lNot->hasMultipleSinks() && !rNot->hasMultipleSinks()) { + APPLYING(PUSH_CONCAT_THROUGH_NOTS) { + vtxp->lhsp(lNot->srcp()); + vtxp->rhsp(rNot->srcp()); + DfgNot* const replacementp = new DfgNot{m_dfg, flp, vtxp->dtypep()}; + vtxp->replaceWith(replacementp); + replacementp->srcp(vtxp); + return; + } } } } @@ -1114,11 +1147,21 @@ class V3DfgPeephole final : public DfgVisitor { } void visit(DfgMul* vtxp) override { - if (foldBinary(vtxp)) return; + UASSERT_OBJ(vtxp->width() == vtxp->lhsp()->width(), vtxp, "Mismatched LHS width"); + UASSERT_OBJ(vtxp->width() == vtxp->rhsp()->width(), vtxp, "Mismatched RHS width"); + + if (associativeBinary(vtxp)) return; + + commutativeBinary(vtxp); } void visit(DfgMulS* vtxp) override { - if (foldBinary(vtxp)) return; + UASSERT_OBJ(vtxp->width() == vtxp->lhsp()->width(), vtxp, "Mismatched LHS width"); + UASSERT_OBJ(vtxp->width() == vtxp->rhsp()->width(), vtxp, "Mismatched RHS width"); + + if (associativeBinary(vtxp)) return; + + commutativeBinary(vtxp); } void visit(DfgNeq* vtxp) override { diff --git a/src/V3DfgPeephole.h b/src/V3DfgPeephole.h index bec8a5c8f..2f64da014 100644 --- a/src/V3DfgPeephole.h +++ b/src/V3DfgPeephole.h @@ -26,6 +26,9 @@ // Enumeration of each peephole optimization. Must be kept in sorted order (enforced by tests). // clang-format off #define FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION(macro) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, FOLD_ASSOC_BINARY) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, FOLD_ASSOC_BINARY_LHS_OF_RHS) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, FOLD_ASSOC_BINARY_RHS_OF_LHS) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, FOLD_BINARY) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, FOLD_SEL) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, FOLD_UNARY) \ @@ -73,8 +76,6 @@ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_EXTEND) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_NESTED_CONCAT_OF_ADJOINING_SELS_ON_LHS) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_NESTED_CONCAT_OF_ADJOINING_SELS_ON_RHS) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_NESTED_CONCAT_OF_CONSTS_ON_LHS) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_NESTED_CONCAT_OF_CONSTS_ON_RHS) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_NOT_EQ) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_NOT_NEQ) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_OR_OF_CONCAT_LHS_ZERO_AND_CONCAT_ZERO_RHS) \ @@ -87,7 +88,6 @@ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_TAUTOLOGICAL_OR) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_XOR_WITH_ONES) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, RIGHT_LEANING_ASSOC) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, RIGHT_LEANING_CONCAT) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, SWAP_COND_WITH_NEQ_CONDITION) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, SWAP_COND_WITH_NOT_CONDITION) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, SWAP_CONST_IN_COMMUTATIVE_BINARY) \ diff --git a/test_regress/t/t_dfg_peephole.cpp b/test_regress/t/t_dfg_peephole.cpp index 7a9d9cac4..6a6bf3440 100644 --- a/test_regress/t/t_dfg_peephole.cpp +++ b/test_regress/t/t_dfg_peephole.cpp @@ -29,15 +29,18 @@ int main(int, char**) { uint64_t rand_a = 0x5aef0c8dd70a4497; uint64_t rand_b = 0xf0c0a8dd75ae4497; + uint64_t srand_a = 0x00fa8dcc7ae4957; for (size_t n = 0; n < 200000; ++n) { // Update rngs rngUpdate(rand_a); rngUpdate(rand_b); + rngUpdate(srand_a); // Assign inputs ref.rand_a = opt.rand_a = rand_a; ref.rand_b = opt.rand_b = rand_b; + ref.srand_a = opt.srand_a = srand_a; // Evaluate both models ref.eval(); diff --git a/test_regress/t/t_dfg_peephole.v b/test_regress/t/t_dfg_peephole.v index 7f9acc62b..675fd9194 100644 --- a/test_regress/t/t_dfg_peephole.v +++ b/test_regress/t/t_dfg_peephole.v @@ -8,15 +8,17 @@ module t ( `include "portlist.vh" // Boilerplate generated by t_dfg_peephole.pl - rand_a, rand_b + rand_a, rand_b, srand_a ); `include "portdecl.vh" // Boilerplate generated by t_dfg_peephole.pl input rand_a; input rand_b; - wire [63:0] rand_a; - wire [63:0] rand_b; + input srand_a; + wire logic [63:0] rand_a; + wire logic [63:0] rand_b; + wire logic signed [63:0] srand_a; wire logic randbit_a = rand_a[0]; wire logic [127:0] rand_ba = {rand_b, rand_a}; @@ -85,6 +87,22 @@ module t ( `signal(FOLD_BINARY_Sub, const_a - const_b); `signal(FOLD_BINARY_Xor, const_a ^ const_b); + `signal(FOLD_ASSOC_BINARY_LHS_OF_RHS_And, (const_a & (const_b & rand_a))); + `signal(FOLD_ASSOC_BINARY_LHS_OF_RHS_Or, (const_a | (const_b | rand_a))); + `signal(FOLD_ASSOC_BINARY_LHS_OF_RHS_Xor, (const_a ^ (const_b ^ rand_a))); + `signal(FOLD_ASSOC_BINARY_LHS_OF_RHS_Add, (const_a + (const_b + rand_a))); + `signal(FOLD_ASSOC_BINARY_LHS_OF_RHS_Mul, (const_a * (const_b * rand_a))); + `signal(FOLD_ASSOC_BINARY_LHS_OF_RHS_MulS, (sconst_a * (sconst_b * srand_a))); + `signal(FOLD_ASSOC_BINARY_LHS_OF_RHS_Concat, {const_a, {const_b, rand_a}}); + + `signal(FOLD_ASSOC_BINARY_RHS_OF_LHS_And, ((rand_a & const_b) & const_a)); + `signal(FOLD_ASSOC_BINARY_RHS_OF_LHS_Or, ((rand_a | const_b) | const_a)); + `signal(FOLD_ASSOC_BINARY_RHS_OF_LHS_Xor, ((rand_a ^ const_b) ^ const_a)); + `signal(FOLD_ASSOC_BINARY_RHS_OF_LHS_Add, ((rand_a + const_b) + const_a)); + `signal(FOLD_ASSOC_BINARY_RHS_OF_LHS_Mul, ((rand_a * const_b) * const_a)); + `signal(FOLD_ASSOC_BINARY_RHS_OF_LHS_MulS, ((srand_a * sconst_b) * sconst_a)); + `signal(FOLD_ASSOC_BINARY_RHS_OF_LHS_Concat, {{rand_a, const_b}, const_a}); + `signal(FOLD_SEL, const_a[3:1]); `signal(SWAP_CONST_IN_COMMUTATIVE_BINARY, rand_a + const_a); @@ -128,8 +146,6 @@ module t ( `signal(PUSH_SEL_THROUGH_REPLICATE, rand_aa[0]); `signal(REPLACE_SEL_FROM_CONST, const_a[2]); `signal(REPLACE_CONCAT_OF_CONSTS, {const_a, const_b}); - `signal(REPLACE_NESTED_CONCAT_OF_CONSTS_ON_RHS, {`DFG({rand_a, const_a}), const_b}); - `signal(REPLACE_NESTED_CONCAT_OF_CONSTS_ON_LHS, {const_a, `DFG({const_b, rand_a})}); `signal(REPLACE_CONCAT_ZERO_AND_SEL_TOP_WITH_SHIFTR, {62'd0, rand_a[63:62]}); `signal(REPLACE_CONCAT_SEL_BOTTOM_AND_ZERO_WITH_SHIFTL, {rand_a[1:0], 62'd0}); `signal(PUSH_CONCAT_THROUGH_NOTS, {~(rand_a+64'd101), ~(rand_b+64'd101)} );