From 84b9502af48ca255fbfdb1ef9ee4b3bc988147d6 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Fri, 30 Sep 2022 16:19:53 +0100 Subject: [PATCH] DFG: Add more peephole patterns --- src/V3Dfg.h | 18 +- src/V3DfgPeephole.cpp | 281 +++++++++++++++++++++++++---- src/V3DfgPeephole.h | 118 ++++++------ test_regress/t/t_dfg_peephole.cpp | 29 ++- test_regress/t/t_dfg_peephole.pl | 128 +++++-------- test_regress/t/t_dfg_peephole.v | 286 ++++++++++-------------------- 6 files changed, 493 insertions(+), 367 deletions(-) diff --git a/src/V3Dfg.h b/src/V3Dfg.h index 7f30ea94d..1cfe8768e 100644 --- a/src/V3Dfg.h +++ b/src/V3Dfg.h @@ -39,6 +39,7 @@ #include "V3Hasher.h" #include "V3List.h" +#include #include #include #include @@ -275,6 +276,8 @@ public: FileLine* fileline() const { return m_filelinep; } // The data type of the result of the nodes AstNodeDType* dtypep() const { return m_dtypep; } + // The type of this vertex + DfgType type() const { return m_type; } // Width of result uint32_t width() const { @@ -365,7 +368,7 @@ public: // Returns first source edge which satisfies the given predicate 'p', or nullptr if no such // sink vertex exists - inline DfgEdge* findSourceEdge(std::function p); + inline const DfgEdge* findSourceEdge(std::function p) const; // Returns first sink vertex of type 'Vertex' which satisfies the given predicate 'p', // or nullptr if no such sink vertex exists @@ -747,6 +750,13 @@ public: FileLine* driverFileLine(size_t idx) const { return m_driverData[idx].first; } uint32_t driverIndex(size_t idx) const { return m_driverData[idx].second; } + DfgVertex* driverAt(size_t idx) const { + const DfgEdge* const edgep = findSourceEdge([=](const DfgEdge&, size_t i) { // + return driverIndex(i) == idx; + }); + return edgep ? edgep->sourcep() : nullptr; + } + const string srcName(size_t idx) const override { return cvtToStr(driverIndex(idx)); } }; @@ -897,12 +907,12 @@ void DfgVertex::forEachSinkEdge(std::function f) const { } } -DfgEdge* DfgVertex::findSourceEdge(std::function p) { +const DfgEdge* DfgVertex::findSourceEdge(std::function p) const { const auto pair = sourceEdges(); - DfgEdge* const edgesp = pair.first; + const DfgEdge* const edgesp = pair.first; const size_t arity = pair.second; for (size_t i = 0; i < arity; ++i) { - DfgEdge& edge = edgesp[i]; + const DfgEdge& edge = edgesp[i]; if (p(edge, i)) return &edge; } return nullptr; diff --git a/src/V3DfgPeephole.cpp b/src/V3DfgPeephole.cpp index 19f98314c..8ba02b5e2 100644 --- a/src/V3DfgPeephole.cpp +++ b/src/V3DfgPeephole.cpp @@ -62,6 +62,24 @@ V3DfgPeepholeContext::~V3DfgPeepholeContext() { #undef OPTIMIZATION_EMIT_STATS } +// clang-format off +template +struct ReductionToBitwiseImpl {}; +template <> struct ReductionToBitwiseImpl { using type = DfgAnd; }; +template <> struct ReductionToBitwiseImpl { using type = DfgOr; }; +template <> struct ReductionToBitwiseImpl { using type = DfgXor; }; +template +using ReductionToBitwise = typename ReductionToBitwiseImpl::type; + +template +struct BitwiseToReductionImpl {}; +template <> struct BitwiseToReductionImpl { using type = DfgRedAnd; }; +template <> struct BitwiseToReductionImpl { using type = DfgRedOr; }; +template <> struct BitwiseToReductionImpl { using type = DfgRedXor; }; +template +using BitwiseToReduction = typename BitwiseToReductionImpl::type; +// clang-format on + class V3DfgPeephole final : public DfgVisitor { // STATE @@ -133,6 +151,22 @@ class V3DfgPeephole final : public DfgVisitor { } } + // Transformations that apply to all associative binary vertices + void associativeBinary(DfgVertexWithArity<2>* vtxp) { + DfgVertex* const lhsp = vtxp->lhsp(); + + // Make associative trees right leaning (for better CSE opportunities) + if (lhsp->type() == vtxp->type() && !lhsp->hasMultipleSinks()) { + DfgVertexWithArity<2>* const lBinp = static_cast*>(lhsp); + 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) { @@ -226,33 +260,56 @@ class V3DfgPeephole final : public DfgVisitor { return false; } - template - void optimizeReduction(Vertex* vtxp) { - static_assert(std::is_same::value - || std::is_same::value - || std::is_same::value, - "Invalid 'Vertex' type for this method"); + template + bool tryPushBitwiseOpThroughReductions(Bitwise* vtxp) { + using Reduction = BitwiseToReduction; + + if (Reduction* const lRedp = vtxp->lhsp()->template cast()) { + if (Reduction* const rRedp = vtxp->rhsp()->template cast()) { + DfgVertex* const lSrcp = lRedp->srcp(); + DfgVertex* const rSrcp = rRedp->srcp(); + if (lSrcp->dtypep() == rSrcp->dtypep()) { + APPLYING(PUSH_BITWISE_THROUGH_REDUCTION) { + FileLine* const flp = vtxp->fileline(); + Bitwise* const bwp = new Bitwise{m_dfg, flp, lSrcp->dtypep()}; + bwp->lhsp(lSrcp); + bwp->rhsp(rSrcp); + Reduction* const redp = new Reduction{m_dfg, flp, m_bitDType}; + redp->srcp(bwp); + vtxp->replaceWith(redp); + return true; + } + } + } + } + + return false; + } + + template + void optimizeReduction(Reduction* vtxp) { + using Bitwise = ReductionToBitwise; DfgVertex* const srcp = vtxp->srcp(); + FileLine* const flp = vtxp->fileline(); - // Reduction of 1-bit value -- Currently unreachable as V3Const can remove these, but - // in the future they will be created during this optimization. - if (srcp->width() == 1) { // LCOV_EXCL_START + // Reduction of 1-bit value + if (srcp->width() == 1) { APPLYING(REMOVE_WIDTH_ONE_REDUCTION) { vtxp->replaceWith(srcp); return; } - } // LCOV_EXCL_STOP + } if (DfgCond* const condp = srcp->cast()) { if (condp->thenp()->is() || condp->elsep()->is()) { APPLYING(PUSH_REDUCTION_THROUGH_COND_WITH_CONST_BRANCH) { // The new 'then' vertex - Vertex* const newThenp = new Vertex{m_dfg, vtxp->fileline(), m_bitDType}; + Reduction* const newThenp = new Reduction{m_dfg, flp, m_bitDType}; newThenp->srcp(condp->thenp()); // The new 'else' vertex - Vertex* const newElsep = new Vertex{m_dfg, vtxp->fileline(), m_bitDType}; + Reduction* const newElsep = new Reduction{m_dfg, flp, m_bitDType}; newElsep->srcp(condp->elsep()); // The replacement Cond vertex @@ -268,12 +325,33 @@ class V3DfgPeephole final : public DfgVisitor { } } + if (DfgConcat* const concatp = srcp->cast()) { + APPLYING(PUSH_REDUCTION_THROUGH_CONCAT) { + // Reduce the parts of the concatenation + Reduction* const lReducep = new Reduction{m_dfg, concatp->fileline(), m_bitDType}; + lReducep->srcp(concatp->lhsp()); + Reduction* const rReducep = new Reduction{m_dfg, concatp->fileline(), m_bitDType}; + rReducep->srcp(concatp->rhsp()); + + // Bitwise reduce the results + DfgVertexWithArity<2>* const replacementp = new Bitwise{m_dfg, flp, m_bitDType}; + replacementp->lhsp(lReducep); + replacementp->rhsp(rReducep); + vtxp->replaceWith(replacementp); + + // Optimize the new reductions + optimizeReduction(lReducep); + optimizeReduction(rReducep); + return; + } + } + if (DfgConst* const constp = srcp->cast()) { APPLYING(REPLACE_REDUCTION_OF_CONST) { - DfgConst* const replacementp = makeZero(vtxp->fileline(), 1); - if (std::is_same::value) { + DfgConst* const replacementp = makeZero(flp, 1); + if VL_CONSTEXPR_CXX17 (std::is_same::value) { replacementp->num().opRedAnd(constp->num()); - } else if (std::is_same::value) { + } else if VL_CONSTEXPR_CXX17 (std::is_same::value) { replacementp->num().opRedOr(constp->num()); } else { replacementp->num().opRedXor(constp->num()); @@ -304,8 +382,9 @@ class V3DfgPeephole final : public DfgVisitor { FileLine* const flp = vtxp->fileline(); - // Convert Extend into Concat with zeros. This simplifies other patterns as they only need - // to handle Concat, which is more generic, and don't need special cases for Extend. + // Convert Extend into Concat with zeros. This simplifies other patterns as they only + // need to handle Concat, which is more generic, and don't need special cases for + // Extend. APPLYING(REPLACE_EXTEND) { DfgConcat* const replacementp = new DfgConcat{m_dfg, flp, vtxp->dtypep()}; replacementp->lhsp(makeZero(flp, extension)); @@ -354,6 +433,17 @@ class V3DfgPeephole final : public DfgVisitor { } } + // Not of Eq + if (DfgEq* const eqp = vtxp->srcp()->cast()) { + APPLYING(REPLACE_NOT_EQ) { + DfgNeq* const replacementp = new DfgNeq{m_dfg, eqp->fileline(), vtxp->dtypep()}; + replacementp->lhsp(eqp->lhsp()); + replacementp->rhsp(eqp->rhsp()); + vtxp->replaceWith(replacementp); + return; + } + } + // Not of Neq if (DfgNeq* const neqp = vtxp->srcp()->cast()) { APPLYING(REPLACE_NOT_NEQ) { @@ -381,22 +471,38 @@ class V3DfgPeephole final : public DfgVisitor { UASSERT_OBJ(vtxp->width() == vtxp->rhsp()->width(), vtxp, "Mismatched RHS width"); commutativeBinary(vtxp); + associativeBinary(vtxp); DfgVertex* const lhsp = vtxp->lhsp(); DfgVertex* const rhsp = vtxp->rhsp(); - FileLine* const flp = vtxp->fileline(); // Bubble pushing - if (lhsp->is() && rhsp->is()) { - APPLYING(REPLACE_AND_OF_NOT_AND_NOT) { - DfgOr* const orp = new DfgOr{m_dfg, flp, vtxp->dtypep()}; - orp->lhsp(lhsp->as()->srcp()); - orp->rhsp(rhsp->as()->srcp()); - DfgNot* const notp = new DfgNot{m_dfg, flp, vtxp->dtypep()}; - notp->srcp(orp); - vtxp->replaceWith(notp); - return; + if (DfgNot* const lhsNotp = lhsp->cast()) { + if (DfgNot* const rhsNotp = rhsp->cast()) { + APPLYING(REPLACE_AND_OF_NOT_AND_NOT) { + DfgOr* const orp = new DfgOr{m_dfg, flp, vtxp->dtypep()}; + orp->lhsp(lhsNotp->srcp()); + orp->rhsp(rhsNotp->srcp()); + DfgNot* const notp = new DfgNot{m_dfg, flp, vtxp->dtypep()}; + notp->srcp(orp); + vtxp->replaceWith(notp); + return; + } + } + if (DfgNeq* const rhsNeqp = rhsp->cast()) { + APPLYING(REPLACE_AND_OF_NOT_AND_NEQ) { + DfgOr* const orp = new DfgOr{m_dfg, flp, vtxp->dtypep()}; + orp->lhsp(lhsNotp->srcp()); + DfgEq* const newRhsp = new DfgEq{m_dfg, rhsp->fileline(), rhsp->dtypep()}; + newRhsp->lhsp(rhsNeqp->lhsp()); + newRhsp->rhsp(rhsNeqp->rhsp()); + orp->rhsp(newRhsp); + DfgNot* const notp = new DfgNot{m_dfg, flp, vtxp->dtypep()}; + notp->srcp(orp); + vtxp->replaceWith(notp); + return; + } } } @@ -429,6 +535,8 @@ class V3DfgPeephole final : public DfgVisitor { } } + if (tryPushBitwiseOpThroughReductions(vtxp)) return; + if (DfgNot* const lhsNotp = lhsp->cast()) { // ~A & A is all zeroes if (lhsNotp->srcp() == rhsp) { @@ -446,10 +554,10 @@ class V3DfgPeephole final : public DfgVisitor { UASSERT_OBJ(vtxp->width() == vtxp->rhsp()->width(), vtxp, "Mismatched RHS width"); commutativeBinary(vtxp); + associativeBinary(vtxp); DfgVertex* const lhsp = vtxp->lhsp(); DfgVertex* const rhsp = vtxp->rhsp(); - FileLine* const flp = vtxp->fileline(); // Bubble pushing @@ -537,6 +645,8 @@ class V3DfgPeephole final : public DfgVisitor { } } + if (tryPushBitwiseOpThroughReductions(vtxp)) return; + if (DfgNot* const lhsNotp = lhsp->cast()) { // ~A | A is all ones if (lhsNotp->srcp() == rhsp) { @@ -555,15 +665,42 @@ class V3DfgPeephole final : public DfgVisitor { UASSERT_OBJ(vtxp->width() == vtxp->rhsp()->width(), vtxp, "Mismatched RHS width"); commutativeBinary(vtxp); + associativeBinary(vtxp); DfgVertex* const lhsp = vtxp->lhsp(); DfgVertex* const rhsp = vtxp->rhsp(); + FileLine* const flp = vtxp->fileline(); - if (DfgConst* const lhsConstp = lhsp->cast()) { - if (DfgConcat* const rhsConcatp = rhsp->cast()) { - if (tryPushBitwiseOpThroughConcat(vtxp, lhsConstp, rhsConcatp)) return; + if (DfgConst* const lConstp = lhsp->cast()) { + if (lConstp->isZero()) { + APPLYING(REMOVE_XOR_WITH_ZERO) { + vtxp->replaceWith(rhsp); + return; + } + } + if (lConstp->isOnes()) { + APPLYING(REPLACE_XOR_WITH_ONES) { + DfgNot* const replacementp = new DfgNot{m_dfg, flp, vtxp->dtypep()}; + replacementp->srcp(rhsp); + vtxp->replaceWith(replacementp); + return; + } + } + if (DfgConcat* const rConcatp = rhsp->cast()) { + tryPushBitwiseOpThroughConcat(vtxp, lConstp, rConcatp); + return; + } + if (DfgConst* const rConstp = rhsp->cast()) { + APPLYING(REPLACE_XOR_OF_CONST_AND_CONST) { + DfgConst* const replacementp = makeZero(flp, vtxp->width()); + replacementp->num().opXor(lConstp->num(), rConstp->num()); + vtxp->replaceWith(replacementp); + return; + } } } + + if (tryPushBitwiseOpThroughReductions(vtxp)) return; } void visit(DfgAdd* vtxp) override { @@ -571,6 +708,7 @@ class V3DfgPeephole final : public DfgVisitor { UASSERT_OBJ(vtxp->width() == vtxp->rhsp()->width(), vtxp, "Mismatched RHS width"); commutativeBinary(vtxp); + associativeBinary(vtxp); } void visit(DfgSub* vtxp) override { @@ -808,14 +946,32 @@ class V3DfgPeephole final : public DfgVisitor { void visit(DfgRedXor* vtxp) override { optimizeReduction(vtxp); } void visit(DfgConcat* vtxp) override { + UASSERT_OBJ(vtxp->width() == vtxp->lhsp()->width() + vtxp->rhsp()->width(), vtxp, + "Incorrect Concat width: " << vtxp->width() << " != " << vtxp->lhsp()->width() + << " + " << vtxp->rhsp()->width()); + DfgVertex* const lhsp = vtxp->lhsp(); DfgVertex* const rhsp = vtxp->rhsp(); - UASSERT_OBJ(vtxp->width() == lhsp->width() + rhsp->width(), vtxp, - "Incorrect Concat width: " << vtxp->width() << " != " << lhsp->width() << " + " - << rhsp->width()); 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* { @@ -1057,6 +1213,49 @@ class V3DfgPeephole final : public DfgVisitor { } } + if (vtxp->width() > 1) { + // 'cond ? a + 1 : a' -> 'a + cond' + if (DfgAdd* const thenAddp = thenp->cast()) { + if (DfgConst* const constp = thenAddp->lhsp()->cast()) { + if (constp->toI32() == 1) { + if (thenAddp->rhsp() == elsep) { + APPLYING(REPLACE_COND_INC) { + DfgConcat* const extp = new DfgConcat{m_dfg, flp, vtxp->dtypep()}; + extp->rhsp(condp); + extp->lhsp(makeZero(flp, vtxp->width() - 1)); + FileLine* const thenFlp = thenAddp->fileline(); + DfgAdd* const addp = new DfgAdd{m_dfg, thenFlp, vtxp->dtypep()}; + addp->lhsp(thenAddp->rhsp()); + addp->rhsp(extp); + vtxp->replaceWith(addp); + return; + } + } + } + } + } + // 'cond ? a - 1 : a' -> 'a - cond' + if (DfgSub* const thenSubp = thenp->cast()) { + if (DfgConst* const constp = thenSubp->rhsp()->cast()) { + if (constp->toI32() == 1) { + if (thenSubp->lhsp() == elsep) { + APPLYING(REPLACE_COND_DEC) { + DfgConcat* const extp = new DfgConcat{m_dfg, flp, vtxp->dtypep()}; + extp->rhsp(condp); + extp->lhsp(makeZero(flp, vtxp->width() - 1)); + FileLine* const thenFlp = thenSubp->fileline(); + DfgSub* const subp = new DfgSub{m_dfg, thenFlp, vtxp->dtypep()}; + subp->lhsp(thenSubp->lhsp()); + subp->rhsp(extp); + vtxp->replaceWith(subp); + return; + } + } + } + } + } + } + if (vtxp->width() == 1) { AstNodeDType* const dtypep = vtxp->dtypep(); if (thenp->isZero()) { // a ? 0 : b becomes ~a & b @@ -1102,6 +1301,20 @@ class V3DfgPeephole final : public DfgVisitor { } } + void visit(DfgArraySel* vtxp) override { + if (DfgConst* const idxp = vtxp->bitp()->cast()) { + if (DfgVarArray* const varp = vtxp->fromp()->cast()) { + const uint32_t idx = idxp->toU32(); + if (DfgVertex* const driverp = varp->driverAt(idx)) { + APPLYING(INLINE_ARRAYSEL) { + vtxp->replaceWith(driverp); + return; + } + } + } + } + } + void visit(DfgVarPacked* vtxp) override { // Inline variables fully driven by the logic represented by the DFG if (vtxp->hasSinks() && vtxp->isDrivenFullyByDfg()) { diff --git a/src/V3DfgPeephole.h b/src/V3DfgPeephole.h index f89a6d1ee..10fe177f6 100644 --- a/src/V3DfgPeephole.h +++ b/src/V3DfgPeephole.h @@ -23,68 +23,80 @@ #define _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, arg) macro(arg, #arg) +// 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, SWAP_CONST_IN_COMMUTATIVE_BINARY) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, SWAP_NOT_IN_COMMUTATIVE_BINARY) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, SWAP_VAR_IN_COMMUTATIVE_BINARY) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, INLINE_ARRAYSEL) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, INLINE_VAR) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, PULL_NOTS_THROUGH_COND) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, PUSH_BITWISE_OP_THROUGH_CONCAT) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, PUSH_BITWISE_THROUGH_REDUCTION) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, PUSH_COMPARE_OP_THROUGH_CONCAT) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REMOVE_WIDTH_ONE_REDUCTION) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, PUSH_REDUCTION_THROUGH_COND_WITH_CONST_BRANCH) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_REDUCTION_OF_CONST) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_EXTEND) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, PUSH_NOT_THROUGH_COND) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REMOVE_NOT_NOT) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_NOT_NEQ) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_NOT_OF_CONST) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_AND_OF_NOT_AND_NOT) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_AND_OF_CONST_AND_CONST) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_AND_WITH_ZERO) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REMOVE_AND_WITH_ONES) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_CONTRADICTORY_AND) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_OR_OF_NOT_AND_NOT) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_OR_OF_NOT_AND_NEQ) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_OR_OF_CONCAT_ZERO_LHS_AND_CONCAT_RHS_ZERO) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_OR_OF_CONCAT_LHS_ZERO_AND_CONCAT_ZERO_RHS) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_OR_OF_CONST_AND_CONST) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REMOVE_OR_WITH_ZERO) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_OR_WITH_ONES) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_TAUTOLOGICAL_OR) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REMOVE_SUB_ZERO) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_SUB_WITH_NOT) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REMOVE_REDUNDANT_ZEXT_ON_RHS_OF_SHIFT) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_EQ_OF_CONST_AND_CONST) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REMOVE_FULL_WIDTH_SEL) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REMOVE_SEL_FROM_RHS_OF_CONCAT) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REMOVE_SEL_FROM_LHS_OF_CONCAT) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, PUSH_SEL_THROUGH_CONCAT) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, PUSH_SEL_THROUGH_REPLICATE) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, PUSH_SEL_THROUGH_NOT) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_SEL_FROM_SEL) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, PUSH_SEL_THROUGH_COND) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, PUSH_SEL_THROUGH_SHIFTL) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_SEL_FROM_CONST) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_CONCAT_OF_CONSTS) \ - _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_CONCAT_ZERO_AND_SEL_TOP_WITH_SHIFTR) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_CONCAT_SEL_BOTTOM_AND_ZERO_WITH_SHIFTL) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, PUSH_CONCAT_THROUGH_NOTS) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, PUSH_NOT_THROUGH_COND) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, PUSH_REDUCTION_THROUGH_CONCAT) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, PUSH_REDUCTION_THROUGH_COND_WITH_CONST_BRANCH) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, PUSH_SEL_THROUGH_CONCAT) \ + _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_SHIFTL) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REMOVE_AND_WITH_ONES) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REMOVE_CONCAT_OF_ADJOINING_SELS) \ - _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, REMOVE_COND_WITH_FALSE_CONDITION) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REMOVE_COND_WITH_TRUE_CONDITION) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, SWAP_COND_WITH_NOT_CONDITION) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, SWAP_COND_WITH_NEQ_CONDITION) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, PULL_NOTS_THROUGH_COND) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_COND_WITH_THEN_BRANCH_ZERO) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_COND_WITH_THEN_BRANCH_ONES) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_COND_WITH_ELSE_BRANCH_ZERO) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REMOVE_FULL_WIDTH_SEL) \ + _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_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_SUB_ZERO) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REMOVE_WIDTH_ONE_REDUCTION) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REMOVE_XOR_WITH_ZERO) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_AND_OF_CONST_AND_CONST) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_AND_OF_NOT_AND_NEQ) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_AND_OF_NOT_AND_NOT) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_AND_WITH_ZERO) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_CONCAT_OF_CONSTS) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_CONCAT_SEL_BOTTOM_AND_ZERO_WITH_SHIFTL) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_CONCAT_ZERO_AND_SEL_TOP_WITH_SHIFTR) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_COND_DEC) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_COND_INC) \ _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_COND_WITH_ELSE_BRANCH_ONES) \ - _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, INLINE_VAR) - + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_COND_WITH_ELSE_BRANCH_ZERO) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_COND_WITH_THEN_BRANCH_ONES) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_COND_WITH_THEN_BRANCH_ZERO) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_CONTRADICTORY_AND) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_EQ_OF_CONST_AND_CONST) \ + _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_NOT_OF_CONST) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_OR_OF_CONCAT_LHS_ZERO_AND_CONCAT_ZERO_RHS) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_OR_OF_CONCAT_ZERO_LHS_AND_CONCAT_RHS_ZERO) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_OR_OF_CONST_AND_CONST) \ + _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_REDUCTION_OF_CONST) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_SEL_FROM_CONST) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_SEL_FROM_SEL) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_SUB_WITH_NOT) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_TAUTOLOGICAL_OR) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_XOR_OF_CONST_AND_CONST) \ + _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) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, SWAP_NOT_IN_COMMUTATIVE_BINARY) \ + _FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, SWAP_VAR_IN_COMMUTATIVE_BINARY) // clang-format on class VDfgPeepholePattern final { diff --git a/test_regress/t/t_dfg_peephole.cpp b/test_regress/t/t_dfg_peephole.cpp index cd2c25318..7a9d9cac4 100644 --- a/test_regress/t/t_dfg_peephole.cpp +++ b/test_regress/t/t_dfg_peephole.cpp @@ -13,6 +13,12 @@ #include #include +void rngUpdate(uint64_t& x) { + x ^= x << 13; + x ^= x >> 7; + x ^= x << 17; +} + int main(int, char**) { // Create contexts VerilatedContext ctx; @@ -21,17 +27,28 @@ int main(int, char**) { Vref ref{&ctx}; Vopt opt{&ctx}; - ref.clk = 0; - opt.clk = 0; + uint64_t rand_a = 0x5aef0c8dd70a4497; + uint64_t rand_b = 0xf0c0a8dd75ae4497; - while (!ctx.gotFinish()) { + for (size_t n = 0; n < 200000; ++n) { + // Update rngs + rngUpdate(rand_a); + rngUpdate(rand_b); + + // Assign inputs + ref.rand_a = opt.rand_a = rand_a; + ref.rand_b = opt.rand_b = rand_b; + + // Evaluate both models ref.eval(); opt.eval(); + + // Check equivalence #include "checks.h" + // increment time ctx.timeInc(1); - - ref.clk = !ref.clk; - opt.clk = !opt.clk; } + + std::cout << "*-* All Finished *-*\n"; } diff --git a/test_regress/t/t_dfg_peephole.pl b/test_regress/t/t_dfg_peephole.pl index 2cd2887f2..c09227ce8 100755 --- a/test_regress/t/t_dfg_peephole.pl +++ b/test_regress/t/t_dfg_peephole.pl @@ -12,35 +12,60 @@ scenarios(vlt_all => 1); $Self->{sim_time} = 2000000; +# Read optimizations +my @optimizations = (); +{ + my $hdrFile = "../src/V3DfgPeephole.h"; + my $hdrFh = IO::File->new("<$hdrFile") or error("$! $hdrFile"); + my $prevOpt = ""; + my $lineno = 0; + while (defined(my $line = $hdrFh->getline)) { + $lineno = $lineno + 1; + next if $line !~ /^\s*_FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY\(macro, (\w+)\)/; + my $opt = $1; + error("$hdrFile:$linenno: '$opt; is not in sorted order") if $prevOpt gt $opt; + $prevOpt = $opt; + push @optimizations, $opt; + } + error("no optimizations defined in $hdrFile") if scalar @optimizations == 0; +} + +# Generate the equivalence checks and declaration boilerplate +my $rdFile = "$Self->{top_filename}"; +my $plistFile = "$Self->{obj_dir}/portlist.vh"; +my $pdeclFile = "$Self->{obj_dir}/portdecl.vh"; +my $checkFile = "$Self->{obj_dir}/checks.h"; +my $rdFh = IO::File->new("<$rdFile") or error("$! $rdFile"); +my $plistFh = IO::File->new(">$plistFile") or error("$! $plistFile"); +my $pdeclFh = IO::File->new(">$pdeclFile") or error("$! $pdeclFile"); +my $checkFh = IO::File->new(">$checkFile") or error("$! $checkFile"); +while (defined(my $line = $rdFh->getline)) { + next if $line !~ /^\s*.*`signal\((\w+),/; + my $signal = $1; + print $plistFh "$signal,\n"; + print $pdeclFh "output $signal;\n"; + print $checkFh "if (ref.$signal != opt.$signal) {\n"; + print $checkFh " std::cout << \"Mismatched $signal\" << std::endl;\n"; + print $checkFh " std::cout << \"Ref: 0x\" << std::hex << (ref.$signal + 0) << std::endl;\n"; + print $checkFh " std::cout << \"Opt: 0x\" << std::hex << (opt.$signal + 0) << std::endl;\n"; + print $checkFh " std::exit(1);\n"; + print $checkFh "}\n"; +} +close $rdFile; +close $wrFile; + + # Compile un-optimized compile( - verilator_flags2 => ["--stats", "--build", "-fno-dfg", "+define+REF", + verilator_flags2 => ["--stats", "--build", "-fno-dfg", "+incdir+$Self->{obj_dir}", "-Mdir", "$Self->{obj_dir}/obj_ref", "--prefix", "Vref"], verilator_make_gmake => 0, verilator_make_cmake => 0 ); -# Generate the equivalence checks -my $rdFile = "$Self->{obj_dir}/obj_ref/Vref.h"; -my $wrFile = "$Self->{obj_dir}/checks.h"; -my $rfh = IO::File->new("<$rdFile") or error("$! $rdFile"); -my $wfh = IO::File->new(">$wrFile") or error("$! $wrFile"); -while (defined(my $line = $rfh->getline)) { - next if $line !~ /.*\b(dfg_[A-Z_]*)\b/; - my $signal = $1; - print $wfh "if (ref.$signal != opt.$signal) {\n"; - print $wfh " std::cout << \"Mismatched $signal\" << std::endl;\n"; - print $wfh " std::cout << \"Ref: 0x\" << std::hex << (ref.$signal + 0) << std::endl;\n"; - print $wfh " std::cout << \"Opt: 0x\" << std::hex << (opt.$signal + 0) << std::endl;\n"; - print $wfh " std::exit(1);\n"; - print $wfh "}\n"; -} -close $rdFile; -close $wrFile; - # Compile optimized - also builds executable compile( - verilator_flags2 => ["--stats", "--build", "--exe", + verilator_flags2 => ["--stats", "--build", "--exe", "+incdir+$Self->{obj_dir}", "-Mdir", "$Self->{obj_dir}/obj_opt", "--prefix", "Vopt", "--dump-dfg", # To fill code coverage "-CFLAGS \"-I .. -I ../obj_ref\"", @@ -63,65 +88,10 @@ sub check { file_grep("$Self->{obj_dir}/obj_opt/Vopt__stats.txt", qr/DFG\s+(pre|post) inline Peephole, ${name}\s+([1-9]\d*)/i); } -# Check optimizations -check("SWAP_CONST_IN_COMMUTATIVE_BINARY"); -check("SWAP_NOT_IN_COMMUTATIVE_BINARY"); -check("SWAP_VAR_IN_COMMUTATIVE_BINARY"); -check("PUSH_BITWISE_OP_THROUGH_CONCAT"); -check("PUSH_COMPARE_OP_THROUGH_CONCAT"); -#check("REMOVE_WIDTH_ONE_REDUCTION"); V3Const eats this -check("PUSH_REDUCTION_THROUGH_COND_WITH_CONST_BRANCH"); -check("REPLACE_REDUCTION_OF_CONST"); -check("REPLACE_EXTEND"); -check("PUSH_NOT_THROUGH_COND"); -check("REMOVE_NOT_NOT"); -check("REPLACE_NOT_NEQ"); -check("REPLACE_NOT_OF_CONST"); -check("REPLACE_AND_OF_NOT_AND_NOT"); -check("REPLACE_AND_OF_CONST_AND_CONST"); -check("REPLACE_AND_WITH_ZERO"); -check("REMOVE_AND_WITH_ONES"); -check("REPLACE_CONTRADICTORY_AND"); -check("REPLACE_OR_OF_NOT_AND_NOT"); -check("REPLACE_OR_OF_NOT_AND_NEQ"); -check("REPLACE_OR_OF_CONCAT_ZERO_LHS_AND_CONCAT_RHS_ZERO"); -check("REPLACE_OR_OF_CONCAT_LHS_ZERO_AND_CONCAT_ZERO_RHS"); -check("REPLACE_OR_OF_CONST_AND_CONST"); -check("REMOVE_OR_WITH_ZERO"); -check("REPLACE_OR_WITH_ONES"); -check("REPLACE_TAUTOLOGICAL_OR"); -check("REMOVE_SUB_ZERO"); -check("REPLACE_SUB_WITH_NOT"); -check("REMOVE_REDUNDANT_ZEXT_ON_RHS_OF_SHIFT"); -check("REPLACE_EQ_OF_CONST_AND_CONST"); -check("REMOVE_FULL_WIDTH_SEL"); -check("REMOVE_SEL_FROM_RHS_OF_CONCAT"); -check("REMOVE_SEL_FROM_LHS_OF_CONCAT"); -check("PUSH_SEL_THROUGH_CONCAT"); -check("PUSH_SEL_THROUGH_REPLICATE"); -check("PUSH_SEL_THROUGH_NOT"); -check("REPLACE_SEL_FROM_SEL"); -check("PUSH_SEL_THROUGH_COND"); -check("PUSH_SEL_THROUGH_SHIFTL"); -check("REPLACE_SEL_FROM_CONST"); -check("REPLACE_CONCAT_OF_CONSTS"); -check("REPLACE_NESTED_CONCAT_OF_CONSTS_ON_LHS"); -check("REPLACE_NESTED_CONCAT_OF_CONSTS_ON_RHS"); -check("REPLACE_CONCAT_ZERO_AND_SEL_TOP_WITH_SHIFTR"); -check("REPLACE_CONCAT_SEL_BOTTOM_AND_ZERO_WITH_SHIFTL"); -check("PUSH_CONCAT_THROUGH_NOTS"); -check("REMOVE_CONCAT_OF_ADJOINING_SELS"); -check("REPLACE_NESTED_CONCAT_OF_ADJOINING_SELS_ON_LHS"); -check("REPLACE_NESTED_CONCAT_OF_ADJOINING_SELS_ON_RHS"); -check("REMOVE_COND_WITH_FALSE_CONDITION"); -check("REMOVE_COND_WITH_TRUE_CONDITION"); -check("SWAP_COND_WITH_NOT_CONDITION"); -check("SWAP_COND_WITH_NEQ_CONDITION"); -check("PULL_NOTS_THROUGH_COND"); -check("REPLACE_COND_WITH_THEN_BRANCH_ZERO"); -check("REPLACE_COND_WITH_THEN_BRANCH_ONES"); -check("REPLACE_COND_WITH_ELSE_BRANCH_ZERO"); -check("REPLACE_COND_WITH_ELSE_BRANCH_ONES"); +# Check all optimizations defined in +foreach my $opt (@optimizations) { + check($opt); +} ok(1); 1; diff --git a/test_regress/t/t_dfg_peephole.v b/test_regress/t/t_dfg_peephole.v index e5609c9c4..f7defa9b4 100644 --- a/test_regress/t/t_dfg_peephole.v +++ b/test_regress/t/t_dfg_peephole.v @@ -4,216 +4,116 @@ // any use, without warranty, 2022 by Geza Lore. // SPDX-License-Identifier: CC0-1.0 -`define STRINGIFY(x) `"x`" +`define signal(name, expr) wire [$bits(expr)-1:0] ``name = expr; -`define signal(name, expr) wire [$bits(expr)-1:0] dfg_``name = expr; +module t ( +`include "portlist.vh" // Boilerplate generated by t_dfg_peephole.pl + rand_a, rand_b + ); +`include "portdecl.vh" // Boilerplate generated by t_dfg_peephole.pl -module t (/*AUTOARG*/ - // Outputs - dfg_SWAP_CONST_IN_COMMUTATIVE_BINARY, - dfg_SWAP_NOT_IN_COMMUTATIVE_BINARY, - dfg_SWAP_VAR_IN_COMMUTATIVE_BINARY, - dfg_PUSH_BITWISE_OP_THROUGH_CONCAT, - dfg_PUSH_BITWISE_OP_THROUGH_CONCAT_2, - dfg_PUSH_COMPARE_OP_THROUGH_CONCAT, dfg_REMOVE_WIDTH_ONE_REDUCTION, - dfg_PUSH_REDUCTION_THROUGH_COND_WITH_CONST_BRANCH, - dfg_REPLACE_REDUCTION_OF_CONST_AND, - dfg_REPLACE_REDUCTION_OF_CONST_OR, - dfg_REPLACE_REDUCTION_OF_CONST_XOR, dfg_REPLACE_EXTEND, - dfg_PUSH_NOT_THROUGH_COND, dfg_REMOVE_NOT_NOT, dfg_REPLACE_NOT_NEQ, - dfg_REPLACE_NOT_OF_CONST, dfg_REPLACE_AND_OF_NOT_AND_NOT, - dfg_REPLACE_AND_OF_CONST_AND_CONST, dfg_REPLACE_AND_WITH_ZERO, - dfg_REMOVE_AND_WITH_ONES, dfg_REPLACE_CONTRADICTORY_AND, - dfg_REPLACE_OR_OF_NOT_AND_NOT, dfg_REPLACE_OR_OF_NOT_AND_NEQ, - dfg_REPLACE_OR_OF_CONCAT_ZERO_LHS_AND_CONCAT_RHS_ZERO, - dfg_REPLACE_OR_OF_CONCAT_LHS_ZERO_AND_CONCAT_ZERO_RHS, - dfg_REPLACE_OR_OF_CONST_AND_CONST, dfg_REMOVE_OR_WITH_ZERO, - dfg_REPLACE_OR_WITH_ONES, dfg_REPLACE_TAUTOLOGICAL_OR, - dfg_REMOVE_SUB_ZERO, dfg_REPLACE_SUB_WITH_NOT, - dfg_REMOVE_REDUNDANT_ZEXT_ON_RHS_OF_SHIFT, - dfg_REPLACE_EQ_OF_CONST_AND_CONST, dfg_REMOVE_FULL_WIDTH_SEL, - dfg_REMOVE_SEL_FROM_RHS_OF_CONCAT, - dfg_REMOVE_SEL_FROM_LHS_OF_CONCAT, dfg_PUSH_SEL_THROUGH_CONCAT, - dfg_PUSH_SEL_THROUGH_REPLICATE, dfg_REPLACE_SEL_FROM_CONST, - dfg_REPLACE_CONCAT_OF_CONSTS, - dfg_REPLACE_NESTED_CONCAT_OF_CONSTS_ON_RHS, - dfg_REPLACE_NESTED_CONCAT_OF_CONSTS_ON_LHS, - dfg_REPLACE_CONCAT_ZERO_AND_SEL_TOP_WITH_SHIFTR, - dfg_REPLACE_CONCAT_SEL_BOTTOM_AND_ZERO_WITH_SHIFTL, - dfg_PUSH_CONCAT_THROUGH_NOTS, dfg_REMOVE_CONCAT_OF_ADJOINING_SELS, - dfg_REPLACE_NESTED_CONCAT_OF_ADJOINING_SELS_ON_LHS, - dfg_REPLACE_NESTED_CONCAT_OF_ADJOINING_SELS_ON_RHS, - dfg_REMOVE_COND_WITH_FALSE_CONDITION, - dfg_REMOVE_COND_WITH_TRUE_CONDITION, - dfg_SWAP_COND_WITH_NOT_CONDITION, dfg_SWAP_COND_WITH_NEQ_CONDITION, - dfg_PULL_NOTS_THROUGH_COND, dfg_REPLACE_COND_WITH_THEN_BRANCH_ZERO, - dfg_REPLACE_COND_WITH_THEN_BRANCH_ONES, - dfg_REPLACE_COND_WITH_ELSE_BRANCH_ZERO, - dfg_REPLACE_COND_WITH_ELSE_BRANCH_ONES, dfg_PUSH_SEL_THROUGH_COND, - dfg_PUSH_SEL_THROUGH_SHIFTL, dfg_REPLACE_SEL_FROM_SEL, - // Inputs - clk - ); - input clk; + input rand_a; + input rand_b; + wire [63:0] rand_a; + wire [63:0] rand_b; - // Sadly verilog-mode cannot look in macros so need to define these - // separately - output dfg_SWAP_CONST_IN_COMMUTATIVE_BINARY; - output dfg_SWAP_NOT_IN_COMMUTATIVE_BINARY; - output dfg_SWAP_VAR_IN_COMMUTATIVE_BINARY; - output dfg_PUSH_BITWISE_OP_THROUGH_CONCAT; - output dfg_PUSH_BITWISE_OP_THROUGH_CONCAT_2; - output dfg_PUSH_COMPARE_OP_THROUGH_CONCAT; - output dfg_REMOVE_WIDTH_ONE_REDUCTION; - output dfg_PUSH_REDUCTION_THROUGH_COND_WITH_CONST_BRANCH; - output dfg_REPLACE_REDUCTION_OF_CONST_AND; - output dfg_REPLACE_REDUCTION_OF_CONST_OR; - output dfg_REPLACE_REDUCTION_OF_CONST_XOR; - output dfg_REPLACE_EXTEND; - output dfg_PUSH_NOT_THROUGH_COND; - output dfg_REMOVE_NOT_NOT; - output dfg_REPLACE_NOT_NEQ; - output dfg_REPLACE_NOT_OF_CONST; - output dfg_REPLACE_AND_OF_NOT_AND_NOT; - output dfg_REPLACE_AND_OF_CONST_AND_CONST; - output dfg_REPLACE_AND_WITH_ZERO; - output dfg_REMOVE_AND_WITH_ONES; - output dfg_REPLACE_CONTRADICTORY_AND; - output dfg_REPLACE_OR_OF_NOT_AND_NOT; - output dfg_REPLACE_OR_OF_NOT_AND_NEQ; - output dfg_REPLACE_OR_OF_CONCAT_ZERO_LHS_AND_CONCAT_RHS_ZERO; - output dfg_REPLACE_OR_OF_CONCAT_LHS_ZERO_AND_CONCAT_ZERO_RHS; - output dfg_REPLACE_OR_OF_CONST_AND_CONST; - output dfg_REMOVE_OR_WITH_ZERO; - output dfg_REPLACE_OR_WITH_ONES; - output dfg_REPLACE_TAUTOLOGICAL_OR; - output dfg_REMOVE_SUB_ZERO; - output dfg_REPLACE_SUB_WITH_NOT; - output dfg_REMOVE_REDUNDANT_ZEXT_ON_RHS_OF_SHIFT; - output dfg_REPLACE_EQ_OF_CONST_AND_CONST; - output dfg_REMOVE_FULL_WIDTH_SEL; - output dfg_REMOVE_SEL_FROM_RHS_OF_CONCAT; - output dfg_REMOVE_SEL_FROM_LHS_OF_CONCAT; - output dfg_PUSH_SEL_THROUGH_CONCAT; - output dfg_PUSH_SEL_THROUGH_REPLICATE; - output dfg_REPLACE_SEL_FROM_CONST; - output dfg_REPLACE_CONCAT_OF_CONSTS; - output dfg_REPLACE_NESTED_CONCAT_OF_CONSTS_ON_RHS; - output dfg_REPLACE_NESTED_CONCAT_OF_CONSTS_ON_LHS; - output dfg_REPLACE_CONCAT_ZERO_AND_SEL_TOP_WITH_SHIFTR; - output dfg_REPLACE_CONCAT_SEL_BOTTOM_AND_ZERO_WITH_SHIFTL; - output dfg_PUSH_CONCAT_THROUGH_NOTS; - output dfg_REMOVE_CONCAT_OF_ADJOINING_SELS; - output dfg_REPLACE_NESTED_CONCAT_OF_ADJOINING_SELS_ON_LHS; - output dfg_REPLACE_NESTED_CONCAT_OF_ADJOINING_SELS_ON_RHS; - output dfg_REMOVE_COND_WITH_FALSE_CONDITION; - output dfg_REMOVE_COND_WITH_TRUE_CONDITION; - output dfg_SWAP_COND_WITH_NOT_CONDITION; - output dfg_SWAP_COND_WITH_NEQ_CONDITION; - output dfg_PULL_NOTS_THROUGH_COND; - output dfg_REPLACE_COND_WITH_THEN_BRANCH_ZERO; - output dfg_REPLACE_COND_WITH_THEN_BRANCH_ONES; - output dfg_REPLACE_COND_WITH_ELSE_BRANCH_ZERO; - output dfg_REPLACE_COND_WITH_ELSE_BRANCH_ONES; - output dfg_PUSH_SEL_THROUGH_COND; - output dfg_PUSH_SEL_THROUGH_SHIFTL; - output dfg_REPLACE_SEL_FROM_SEL; + wire logic randbit_a = rand_a[0]; + wire logic [127:0] rand_ba = {rand_b, rand_a}; + wire logic [127:0] rand_aa = {2{rand_a}}; + wire logic [63:0] const_a; + wire logic [63:0] const_b; + wire logic [63:0] array [3:0]; + assign array[0] = (rand_a << 32) | (rand_a >> 32); + assign array[1] = (rand_a << 16) | (rand_a >> 48); - integer cyc = 0; - - reg [63:0] crc = 64'h5aef0c8d_d70a4497; - reg [63:0] rcr; - wire logic [127:0] rcr_crc = {rcr, crc}; - wire logic [127:0] crc_rep = {2{crc}}; - wire logic [63:0] const_a; - wire logic [63:0] const_b; - - always @ (posedge clk) begin - cyc <= cyc + 1; - crc <= {crc[62:0], crc[63] ^ crc[2] ^ crc[0]}; - rcr <= ~crc; - -`ifdef REF - if (cyc >= 100_000) begin - $write("*-* All Finished *-*\n"); - $finish; - end -`endif - end - - // 64'0 but don't tell V3Const + // 64 bit all 0 but don't tell V3Const `define ZERO (const_a & ~const_a) - // 64'1 but don't tell V3Const + // 64 bit all 1 but don't tell V3Const `define ONES (const_a | ~const_a) // x, but in a way only DFG understands `define DFG(x) ((|`ONES) ? (x) : (~x)) - `signal(SWAP_CONST_IN_COMMUTATIVE_BINARY, crc + const_a); - `signal(SWAP_NOT_IN_COMMUTATIVE_BINARY, crc + ~crc); - `signal(SWAP_VAR_IN_COMMUTATIVE_BINARY, rcr + crc); - `signal(PUSH_BITWISE_OP_THROUGH_CONCAT, 32'h12345678 ^ {8'h0, crc[23:0]}); - `signal(PUSH_BITWISE_OP_THROUGH_CONCAT_2, 32'h12345678 ^ {rcr[7:0], crc[23:0]}); - `signal(PUSH_COMPARE_OP_THROUGH_CONCAT, 4'b1011 == {2'b10, crc[1:0]}); - `signal(REMOVE_WIDTH_ONE_REDUCTION, &`DFG(crc[0])); - `signal(PUSH_REDUCTION_THROUGH_COND_WITH_CONST_BRANCH, |(crc[32] ? crc[3:0] : 4'h0)); + `signal(SWAP_CONST_IN_COMMUTATIVE_BINARY, rand_a + const_a); + `signal(SWAP_NOT_IN_COMMUTATIVE_BINARY, rand_a + ~rand_a); + `signal(SWAP_VAR_IN_COMMUTATIVE_BINARY, rand_b + rand_a); + `signal(PUSH_BITWISE_OP_THROUGH_CONCAT, 32'h12345678 ^ {8'h0, rand_a[23:0]}); + `signal(PUSH_BITWISE_OP_THROUGH_CONCAT_2, 32'h12345678 ^ {rand_b[7:0], rand_a[23:0]}); + `signal(PUSH_COMPARE_OP_THROUGH_CONCAT, 4'b1011 == {2'b10, rand_a[1:0]}); + `signal(REMOVE_WIDTH_ONE_REDUCTION, &`DFG(rand_a[0])); + `signal(PUSH_REDUCTION_THROUGH_COND_WITH_CONST_BRANCH, |(rand_a[32] ? rand_a[3:0] : 4'h0)); `signal(REPLACE_REDUCTION_OF_CONST_AND, &const_a); `signal(REPLACE_REDUCTION_OF_CONST_OR, |const_a); `signal(REPLACE_REDUCTION_OF_CONST_XOR, ^const_a); - `signal(REPLACE_EXTEND, 4'(crc[0])); - `signal(PUSH_NOT_THROUGH_COND, ~(crc[0] ? crc[4:0] : 5'hb)); - `signal(REMOVE_NOT_NOT, ~`DFG(~`DFG(crc))); - `signal(REPLACE_NOT_NEQ, ~`DFG(crc != rcr)); + `signal(REPLACE_EXTEND, 4'(rand_a[0])); + `signal(PUSH_NOT_THROUGH_COND, ~(rand_a[0] ? rand_a[4:0] : 5'hb)); + `signal(REMOVE_NOT_NOT, ~`DFG(~`DFG(rand_a))); + `signal(REPLACE_NOT_NEQ, ~`DFG(rand_a != rand_b)); + `signal(REPLACE_NOT_EQ, ~`DFG(rand_a == rand_b)); `signal(REPLACE_NOT_OF_CONST, ~4'd0); - `signal(REPLACE_AND_OF_NOT_AND_NOT, ~crc[0] & ~rcr[0]); + `signal(REPLACE_AND_OF_NOT_AND_NOT, ~rand_a[0] & ~rand_b[0]); + `signal(REPLACE_AND_OF_NOT_AND_NEQ, ~rand_a[0] & (rand_b != 64'd2)); `signal(REPLACE_AND_OF_CONST_AND_CONST, const_a & const_b); - `signal(REPLACE_AND_WITH_ZERO, `ZERO & crc); - `signal(REMOVE_AND_WITH_ONES, `ONES & crc); - `signal(REPLACE_CONTRADICTORY_AND, crc & ~crc); - `signal(REPLACE_OR_OF_NOT_AND_NOT, ~crc[0] | ~rcr[0]); - `signal(REPLACE_OR_OF_NOT_AND_NEQ, ~crc[0] | (rcr != 64'd2)); - `signal(REPLACE_OR_OF_CONCAT_ZERO_LHS_AND_CONCAT_RHS_ZERO, {2'd0, crc[1:0]} | {rcr[1:0], 2'd0}); - `signal(REPLACE_OR_OF_CONCAT_LHS_ZERO_AND_CONCAT_ZERO_RHS, {crc[1:0], 2'd0} | {2'd0, rcr[1:0]}); + `signal(REPLACE_AND_WITH_ZERO, `ZERO & rand_a); + `signal(REMOVE_AND_WITH_ONES, `ONES & rand_a); + `signal(REPLACE_CONTRADICTORY_AND, rand_a & ~rand_a); + `signal(REPLACE_OR_OF_NOT_AND_NOT, ~rand_a[0] | ~rand_b[0]); + `signal(REPLACE_OR_OF_NOT_AND_NEQ, ~rand_a[0] | (rand_b != 64'd2)); + `signal(REPLACE_OR_OF_CONCAT_ZERO_LHS_AND_CONCAT_RHS_ZERO, {2'd0, rand_a[1:0]} | {rand_b[1:0], 2'd0}); + `signal(REPLACE_OR_OF_CONCAT_LHS_ZERO_AND_CONCAT_ZERO_RHS, {rand_a[1:0], 2'd0} | {2'd0, rand_b[1:0]}); `signal(REPLACE_OR_OF_CONST_AND_CONST, const_a | const_b); - `signal(REMOVE_OR_WITH_ZERO, `ZERO | crc); - `signal(REPLACE_OR_WITH_ONES, `ONES | crc); - `signal(REPLACE_TAUTOLOGICAL_OR, crc | ~crc); - `signal(REMOVE_SUB_ZERO, crc - `ZERO); - `signal(REPLACE_SUB_WITH_NOT, crc[0] - 1'b1); - `signal(REMOVE_REDUNDANT_ZEXT_ON_RHS_OF_SHIFT, crc << {2'b0, crc[2:0]}); + `signal(REMOVE_OR_WITH_ZERO, `ZERO | rand_a); + `signal(REPLACE_OR_WITH_ONES, `ONES | rand_a); + `signal(REPLACE_TAUTOLOGICAL_OR, rand_a | ~rand_a); + `signal(REMOVE_SUB_ZERO, rand_a - `ZERO); + `signal(REPLACE_SUB_WITH_NOT, rand_a[0] - 1'b1); + `signal(REMOVE_REDUNDANT_ZEXT_ON_RHS_OF_SHIFT, rand_a << {2'b0, rand_a[2:0]}); `signal(REPLACE_EQ_OF_CONST_AND_CONST, 4'd0 == 4'd1); - `signal(REMOVE_FULL_WIDTH_SEL, crc[63:0]); - `signal(REMOVE_SEL_FROM_RHS_OF_CONCAT, rcr_crc[63:0]); - `signal(REMOVE_SEL_FROM_LHS_OF_CONCAT, rcr_crc[127:64]); - `signal(PUSH_SEL_THROUGH_CONCAT, rcr_crc[120:0]); - `signal(PUSH_SEL_THROUGH_REPLICATE, crc_rep[0]); + `signal(REMOVE_FULL_WIDTH_SEL, rand_a[63:0]); + `signal(REMOVE_SEL_FROM_RHS_OF_CONCAT, rand_ba[63:0]); + `signal(REMOVE_SEL_FROM_LHS_OF_CONCAT, rand_ba[127:64]); + `signal(PUSH_SEL_THROUGH_CONCAT, rand_ba[120:0]); + `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({crc, const_a}), const_b}); - `signal(REPLACE_NESTED_CONCAT_OF_CONSTS_ON_LHS, {const_a, `DFG({const_b, crc})}); - `signal(REPLACE_CONCAT_ZERO_AND_SEL_TOP_WITH_SHIFTR, {62'd0, crc[63:62]}); - `signal(REPLACE_CONCAT_SEL_BOTTOM_AND_ZERO_WITH_SHIFTL, {crc[1:0], 62'd0}); - `signal(PUSH_CONCAT_THROUGH_NOTS, {~crc, ~rcr} ); - `signal(REMOVE_CONCAT_OF_ADJOINING_SELS, {`DFG(crc[10:3]), `DFG(crc[2:1])}); - `signal(REPLACE_NESTED_CONCAT_OF_ADJOINING_SELS_ON_LHS, {crc[10:3], {crc[2:1], rcr}}); - `signal(REPLACE_NESTED_CONCAT_OF_ADJOINING_SELS_ON_RHS, {`DFG({rcr, crc[10:3]}), crc[2:1]}); - `signal(REMOVE_COND_WITH_FALSE_CONDITION, &`ZERO ? crc : rcr); - `signal(REMOVE_COND_WITH_TRUE_CONDITION, |`ONES ? crc : rcr); - `signal(SWAP_COND_WITH_NOT_CONDITION, (~crc[0] & |`ONES) ? crc : rcr); - `signal(SWAP_COND_WITH_NEQ_CONDITION, rcr != crc ? crc : rcr); - `signal(PULL_NOTS_THROUGH_COND, crc[0] ? ~crc[4:0] : ~rcr[4:0]); - `signal(REPLACE_COND_WITH_THEN_BRANCH_ZERO, crc[0] ? |`ZERO : crc[1]); - `signal(REPLACE_COND_WITH_THEN_BRANCH_ONES, crc[0] ? |`ONES : crc[1]); - `signal(REPLACE_COND_WITH_ELSE_BRANCH_ZERO, crc[0] ? crc[1] : |`ZERO); - `signal(REPLACE_COND_WITH_ELSE_BRANCH_ONES, crc[0] ? crc[1] : |`ONES); - - assign const_a = (crc | ~crc) & 64'h0123456789abcdef; - assign const_b = ~(crc & ~crc) & 64'h98badefc10325647; + `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, ~rand_b} ); + `signal(REMOVE_CONCAT_OF_ADJOINING_SELS, {`DFG(rand_a[10:3]), `DFG(rand_a[2:1])}); + `signal(REPLACE_NESTED_CONCAT_OF_ADJOINING_SELS_ON_LHS, {rand_a[10:3], {rand_a[2:1], rand_b}}); + `signal(REPLACE_NESTED_CONCAT_OF_ADJOINING_SELS_ON_RHS, {`DFG({rand_b, rand_a[10:3]}), rand_a[2:1]}); + `signal(REMOVE_COND_WITH_FALSE_CONDITION, &`ZERO ? rand_a : rand_b); + `signal(REMOVE_COND_WITH_TRUE_CONDITION, |`ONES ? rand_a : rand_b); + `signal(SWAP_COND_WITH_NOT_CONDITION, (~rand_a[0] & |`ONES) ? rand_a : rand_b); + `signal(SWAP_COND_WITH_NEQ_CONDITION, rand_b != rand_a ? rand_a : rand_b); + `signal(PULL_NOTS_THROUGH_COND, rand_a[0] ? ~rand_a[4:0] : ~rand_b[4:0]); + `signal(REPLACE_COND_WITH_THEN_BRANCH_ZERO, rand_a[0] ? |`ZERO : rand_a[1]); + `signal(REPLACE_COND_WITH_THEN_BRANCH_ONES, rand_a[0] ? |`ONES : rand_a[1]); + `signal(REPLACE_COND_WITH_ELSE_BRANCH_ZERO, rand_a[0] ? rand_a[1] : |`ZERO); + `signal(REPLACE_COND_WITH_ELSE_BRANCH_ONES, rand_a[0] ? rand_a[1] : |`ONES); + `signal(INLINE_ARRAYSEL, array[0]); + `signal(PUSH_BITWISE_THROUGH_REDUCTION_AND, (&rand_a) & (&rand_b)); + `signal(PUSH_BITWISE_THROUGH_REDUCTION_OR, (|rand_a) | (|rand_b)); + `signal(PUSH_BITWISE_THROUGH_REDUCTION_XOR, (^rand_a) ^ (^rand_b)); + `signal(PUSH_REDUCTION_THROUGH_CONCAT_AND, &`DFG({rand_a, rand_b})); + `signal(PUSH_REDUCTION_THROUGH_CONCAT_OR, |`DFG({rand_a, rand_b})); + `signal(PUSH_REDUCTION_THROUGH_CONCAT_XOR, ^`DFG({rand_a, rand_b})); + `signal(REMOVE_WIDTH_ONE_REDUCTION_AND, &`DFG({randbit_a, rand_b})); + `signal(REMOVE_WIDTH_ONE_REDUCTION_OR, |`DFG({randbit_a, rand_b})); + `signal(REMOVE_WIDTH_ONE_REDUCTION_XOR, ^`DFG({randbit_a, rand_b})); + `signal(REMOVE_XOR_WITH_ZERO, `ZERO ^ rand_a); + `signal(REMOVE_XOR_WITH_ONES, `ONES ^ rand_a); + `signal(REPLACE_COND_DEC, randbit_a ? rand_b - 64'b1 : rand_b); + `signal(REPLACE_COND_INC, randbit_a ? rand_b + 64'b1 : rand_b); + `signal(RIGHT_LEANING_ASSOC, (((rand_a + rand_b) + rand_a) + rand_b)); + `signal(RIGHT_LEANING_CONCET, {{{rand_a, rand_b}, rand_a}, rand_b}); // Some selects need extra temporaries - wire [63:0] sel_from_cond = crc[0] ? crc : const_a; - wire [63:0] sel_from_shiftl = crc << 10; - wire [31:0] sel_from_sel = crc[10+:32]; + wire [63:0] sel_from_cond = rand_a[0] ? rand_a : const_a; + wire [63:0] sel_from_shiftl = rand_a << 10; + wire [31:0] sel_from_sel = rand_a[10+:32]; `signal(PUSH_SEL_THROUGH_COND, sel_from_cond[2]); `signal(PUSH_SEL_THROUGH_SHIFTL, sel_from_shiftl[20:0]); @@ -221,7 +121,11 @@ module t (/*AUTOARG*/ // Sel from not requires the operand to have a sinle sink, so can't use // the chekc due to the raw expression referencing the operand - wire [63:0] sel_from_not_tmp = ~(crc >> rcr[2:0] << crc[3:0]); + wire [63:0] sel_from_not_tmp = ~(rand_a >> rand_b[2:0] << rand_a[3:0]); wire sel_from_not = sel_from_not_tmp[2]; - always @(posedge clk) if ($c(0)) $display(sel_from_not); // Do not remove signal + always @(posedge randbit_a) if ($c(0)) $display(sel_from_not); // Do not remove signal + + // Assigned at the end to avoid inlining by other passes + assign const_a = (rand_a | ~rand_a) & 64'h0123456789abcdef; + assign const_b = ~(rand_a & ~rand_a) & 64'h98badefc10325647; endmodule