DFG: Add more peephole patterns

This commit is contained in:
Geza Lore 2022-09-30 16:19:53 +01:00
parent 694bdbc130
commit 84b9502af4
6 changed files with 493 additions and 367 deletions

View File

@ -39,6 +39,7 @@
#include "V3Hasher.h"
#include "V3List.h"
#include <algorithm>
#include <array>
#include <functional>
#include <type_traits>
@ -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<bool(const DfgEdge&, size_t)> p);
inline const DfgEdge* findSourceEdge(std::function<bool(const DfgEdge&, size_t)> 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<void(const DfgEdge&)> f) const {
}
}
DfgEdge* DfgVertex::findSourceEdge(std::function<bool(const DfgEdge&, size_t)> p) {
const DfgEdge* DfgVertex::findSourceEdge(std::function<bool(const DfgEdge&, size_t)> 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;

View File

@ -62,6 +62,24 @@ V3DfgPeepholeContext::~V3DfgPeepholeContext() {
#undef OPTIMIZATION_EMIT_STATS
}
// clang-format off
template <typename T_Reduction>
struct ReductionToBitwiseImpl {};
template <> struct ReductionToBitwiseImpl<DfgRedAnd> { using type = DfgAnd; };
template <> struct ReductionToBitwiseImpl<DfgRedOr> { using type = DfgOr; };
template <> struct ReductionToBitwiseImpl<DfgRedXor> { using type = DfgXor; };
template <typename T_Reductoin>
using ReductionToBitwise = typename ReductionToBitwiseImpl<T_Reductoin>::type;
template <typename T_Bitwise>
struct BitwiseToReductionImpl {};
template <> struct BitwiseToReductionImpl<DfgAnd> { using type = DfgRedAnd; };
template <> struct BitwiseToReductionImpl<DfgOr> { using type = DfgRedOr; };
template <> struct BitwiseToReductionImpl<DfgXor> { using type = DfgRedXor; };
template <typename T_Reductoin>
using BitwiseToReduction = typename BitwiseToReductionImpl<T_Reductoin>::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<DfgVertexWithArity<2>*>(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 <typename Vertex>
bool tryPushBitwiseOpThroughConcat(Vertex* vtxp, DfgConst* constp, DfgConcat* concatp) {
@ -226,33 +260,56 @@ class V3DfgPeephole final : public DfgVisitor {
return false;
}
template <typename Vertex>
void optimizeReduction(Vertex* vtxp) {
static_assert(std::is_same<Vertex, DfgRedAnd>::value
|| std::is_same<Vertex, DfgRedOr>::value
|| std::is_same<Vertex, DfgRedXor>::value,
"Invalid 'Vertex' type for this method");
template <typename Bitwise>
bool tryPushBitwiseOpThroughReductions(Bitwise* vtxp) {
using Reduction = BitwiseToReduction<Bitwise>;
if (Reduction* const lRedp = vtxp->lhsp()->template cast<Reduction>()) {
if (Reduction* const rRedp = vtxp->rhsp()->template cast<Reduction>()) {
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 <typename Reduction>
void optimizeReduction(Reduction* vtxp) {
using Bitwise = ReductionToBitwise<Reduction>;
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<DfgCond>()) {
if (condp->thenp()->is<DfgConst>() || condp->elsep()->is<DfgConst>()) {
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<DfgConcat>()) {
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<DfgConst>()) {
APPLYING(REPLACE_REDUCTION_OF_CONST) {
DfgConst* const replacementp = makeZero(vtxp->fileline(), 1);
if (std::is_same<Vertex, DfgRedAnd>::value) {
DfgConst* const replacementp = makeZero(flp, 1);
if VL_CONSTEXPR_CXX17 (std::is_same<Reduction, DfgRedAnd>::value) {
replacementp->num().opRedAnd(constp->num());
} else if (std::is_same<Vertex, DfgRedOr>::value) {
} else if VL_CONSTEXPR_CXX17 (std::is_same<Reduction, DfgRedOr>::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<DfgEq>()) {
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<DfgNeq>()) {
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<DfgNot>() && rhsp->is<DfgNot>()) {
APPLYING(REPLACE_AND_OF_NOT_AND_NOT) {
DfgOr* const orp = new DfgOr{m_dfg, flp, vtxp->dtypep()};
orp->lhsp(lhsp->as<DfgNot>()->srcp());
orp->rhsp(rhsp->as<DfgNot>()->srcp());
DfgNot* const notp = new DfgNot{m_dfg, flp, vtxp->dtypep()};
notp->srcp(orp);
vtxp->replaceWith(notp);
return;
if (DfgNot* const lhsNotp = lhsp->cast<DfgNot>()) {
if (DfgNot* const rhsNotp = rhsp->cast<DfgNot>()) {
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<DfgNeq>()) {
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<DfgNot>()) {
// ~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<DfgNot>()) {
// ~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<DfgConst>()) {
if (DfgConcat* const rhsConcatp = rhsp->cast<DfgConcat>()) {
if (tryPushBitwiseOpThroughConcat(vtxp, lhsConstp, rhsConcatp)) return;
if (DfgConst* const lConstp = lhsp->cast<DfgConst>()) {
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<DfgConcat>()) {
tryPushBitwiseOpThroughConcat(vtxp, lConstp, rConcatp);
return;
}
if (DfgConst* const rConstp = rhsp->cast<DfgConst>()) {
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<DfgConcat>()) {
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<DfgAdd>()) {
if (DfgConst* const constp = thenAddp->lhsp()->cast<DfgConst>()) {
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<DfgSub>()) {
if (DfgConst* const constp = thenSubp->rhsp()->cast<DfgConst>()) {
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<DfgConst>()) {
if (DfgVarArray* const varp = vtxp->fromp()->cast<DfgVarArray>()) {
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()) {

View File

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

View File

@ -13,6 +13,12 @@
#include <Vref.h>
#include <iostream>
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";
}

View File

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

View File

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