Optimize conditional patterns sharing common MBSs/LSBs in DfgPeephole (#7760)
Replace 3 DfgCond patterns with 2 more general ones that convert DfgCond with common MSBs/LSBs in both branches into a DfgConcat with a narrower DfgCond. This pattern arises frequently with Dfg synthesis.
This commit is contained in:
parent
e2e1bfe8dd
commit
901909d3c7
|
|
@ -139,6 +139,7 @@ public:
|
|||
|
||||
// Returns a Packed type of the given width
|
||||
static const DfgDataType& packed(uint32_t width) {
|
||||
UASSERT(width > 0, "Width must be positive");
|
||||
// Find or create the right sized packed type
|
||||
const DfgDataType*& entryr = s_packedTypes[width];
|
||||
if (!entryr) entryr = new DfgDataType{width};
|
||||
|
|
|
|||
|
|
@ -1188,6 +1188,102 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
return {fromp, lsb};
|
||||
}
|
||||
|
||||
// Given a pair of vertices, returns a vertex representing the common LSBs of the two,
|
||||
// and the number of common LSBs. Returns {nullptr, 0} if no common LSBs are found.
|
||||
std::pair<DfgVertex*, uint32_t> commonLSBs(DfgVertex* ap, DfgVertex* bp) {
|
||||
if (ap == bp) return {ap, ap->width()};
|
||||
|
||||
// If both constants, check LSBs
|
||||
if (DfgConst* const aConstp = ap->cast<DfgConst>()) {
|
||||
if (DfgConst* const bConstp = bp->cast<DfgConst>()) {
|
||||
const V3Number& aNum = aConstp->num();
|
||||
const V3Number& bNum = bConstp->num();
|
||||
// Max match is the shorter constant
|
||||
const uint32_t maxMatch = std::min(aConstp->width(), bConstp->width());
|
||||
// Check all bits
|
||||
uint32_t matchWidth = 0;
|
||||
for (; matchWidth < maxMatch; ++matchWidth) {
|
||||
if (aNum.bitIs0(matchWidth) != bNum.bitIs0(matchWidth)) break;
|
||||
}
|
||||
// Will always return the shorter constant in case it can be used directly
|
||||
DfgConst* const shorterp = aConstp->width() < bConstp->width() ? aConstp : bConstp;
|
||||
return {matchWidth ? shorterp : nullptr, matchWidth};
|
||||
}
|
||||
}
|
||||
|
||||
// If Concat, check against the RHS
|
||||
if (DfgConcat* const catp = ap->cast<DfgConcat>()) return commonLSBs(catp->rhsp(), bp);
|
||||
if (DfgConcat* const catp = bp->cast<DfgConcat>()) return commonLSBs(ap, catp->rhsp());
|
||||
|
||||
// If selecting the LSBs, check against the source of the Sel
|
||||
if (DfgSel* const selp = ap->cast<DfgSel>()) {
|
||||
if (selp->lsb() == 0) {
|
||||
DfgVertex* const fromp = selp->fromp();
|
||||
const std::pair<DfgVertex*, uint32_t> common = commonLSBs(fromp, bp);
|
||||
return {common.first, std::min(common.second, selp->width())};
|
||||
}
|
||||
}
|
||||
if (DfgSel* const selp = bp->cast<DfgSel>()) {
|
||||
if (selp->lsb() == 0) {
|
||||
DfgVertex* const fromp = selp->fromp();
|
||||
const std::pair<DfgVertex*, uint32_t> common = commonLSBs(ap, fromp);
|
||||
return {common.first, std::min(common.second, selp->width())};
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise no common LSBs
|
||||
return {nullptr, 0};
|
||||
}
|
||||
|
||||
// Given a pair of vertices, returns a vertex representing the common MSBs of the two,
|
||||
// and the number of common LSBs. Returns {nullptr, 0} if no common LSBs are found.
|
||||
std::pair<DfgVertex*, uint32_t> commonMSBs(DfgVertex* ap, DfgVertex* bp) {
|
||||
if (ap == bp) return {ap, ap->width()};
|
||||
|
||||
// If both constants, check MSBs
|
||||
if (DfgConst* const aConstp = ap->cast<DfgConst>()) {
|
||||
if (DfgConst* const bConstp = bp->cast<DfgConst>()) {
|
||||
const uint32_t aMsb = aConstp->width() - 1;
|
||||
const uint32_t bMsb = bConstp->width() - 1;
|
||||
const V3Number& aNum = aConstp->num();
|
||||
const V3Number& bNum = bConstp->num();
|
||||
// Max match is the shorter constant
|
||||
const uint32_t maxMatch = std::min(aConstp->width(), bConstp->width());
|
||||
// Check all bits
|
||||
uint32_t matchWidth = 0;
|
||||
for (; matchWidth < maxMatch; ++matchWidth) {
|
||||
if (aNum.bitIs0(aMsb - matchWidth) != bNum.bitIs0(bMsb - matchWidth)) break;
|
||||
}
|
||||
// Will always return the shorter constant in case it can be used directly
|
||||
DfgConst* const shorterp = aMsb < bMsb ? aConstp : bConstp;
|
||||
return {matchWidth ? shorterp : nullptr, matchWidth};
|
||||
}
|
||||
}
|
||||
|
||||
// If Concat, check against the LHS
|
||||
if (DfgConcat* const catp = ap->cast<DfgConcat>()) return commonMSBs(catp->lhsp(), bp);
|
||||
if (DfgConcat* const catp = bp->cast<DfgConcat>()) return commonMSBs(ap, catp->lhsp());
|
||||
|
||||
// If selecting the MSBs, check against the source of the Sel
|
||||
if (DfgSel* const selp = ap->cast<DfgSel>()) {
|
||||
DfgVertex* const fromp = selp->fromp();
|
||||
if (selp->msb() == fromp->width() - 1) {
|
||||
const std::pair<DfgVertex*, uint32_t> common = commonMSBs(fromp, bp);
|
||||
return {common.first, std::min(common.second, selp->width())};
|
||||
}
|
||||
}
|
||||
if (DfgSel* const selp = bp->cast<DfgSel>()) {
|
||||
DfgVertex* const fromp = selp->fromp();
|
||||
if (selp->msb() == fromp->width() - 1) {
|
||||
const std::pair<DfgVertex*, uint32_t> common = commonMSBs(ap, fromp);
|
||||
return {common.first, std::min(common.second, selp->width())};
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise no common MSBs
|
||||
return {nullptr, 0};
|
||||
}
|
||||
|
||||
// VISIT methods
|
||||
|
||||
void visit(DfgVertex*) override {}
|
||||
|
|
@ -2834,56 +2930,62 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
if (DfgConcat* const tConcatp = thenp->cast<DfgConcat>()) {
|
||||
if (DfgConcat* const eConcatp = elsep->cast<DfgConcat>()) {
|
||||
DfgVertex* const tRhsp = tConcatp->rhsp();
|
||||
DfgVertex* const tLhsp = tConcatp->lhsp();
|
||||
DfgVertex* const eRhsp = eConcatp->rhsp();
|
||||
DfgVertex* const eLhsp = eConcatp->lhsp();
|
||||
|
||||
if (isSame(tRhsp, eRhsp)) {
|
||||
APPLYING(REPLACE_COND_SAME_CAT_RHS) {
|
||||
DfgCond* const newCondp
|
||||
= make<DfgCond>(flp, tLhsp->dtype(), condp, tLhsp, eLhsp);
|
||||
replace(make<DfgConcat>(vtxp, newCondp, tRhsp));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (isSame(tLhsp, eLhsp)) {
|
||||
APPLYING(REPLACE_COND_SAME_CAT_LHS) {
|
||||
DfgCond* const newCondp
|
||||
= make<DfgCond>(flp, tRhsp->dtype(), condp, tRhsp, eRhsp);
|
||||
replace(make<DfgConcat>(vtxp, tLhsp, newCondp));
|
||||
if (!thenp->is<DfgConst>() && !elsep->is<DfgConst>()) {
|
||||
const std::pair<DfgVertex*, uint32_t> cLSBs = commonLSBs(thenp, elsep);
|
||||
if (cLSBs.first) {
|
||||
APPLYING(REPLACE_COND_COMMON_LSBS) {
|
||||
// Create new RHS
|
||||
const uint32_t rWidth = cLSBs.second;
|
||||
DfgVertex* rhsp = cLSBs.first;
|
||||
if (rWidth != rhsp->width()) {
|
||||
const DfgDataType& rDtype = DfgDataType::packed(rWidth);
|
||||
rhsp = make<DfgSel>(flp, rDtype, rhsp, 0U);
|
||||
}
|
||||
// If it's all the same, just replace
|
||||
if (rhsp->dtype() == vtxp->dtype()) {
|
||||
// Note this branch can only be hit if rules run in the right order,
|
||||
// it might have missing code coverage after a refactor.
|
||||
replace(rhsp);
|
||||
return;
|
||||
}
|
||||
// Create new LHS
|
||||
const uint32_t lWidth = vtxp->width() - rWidth;
|
||||
const DfgDataType& lDtype = DfgDataType::packed(lWidth);
|
||||
DfgVertex* const lThenp = make<DfgSel>(flp, lDtype, thenp, rWidth);
|
||||
DfgVertex* const lElsep = make<DfgSel>(flp, lDtype, elsep, rWidth);
|
||||
DfgVertex* const lhsp = make<DfgCond>(flp, lDtype, condp, lThenp, lElsep);
|
||||
// Replace with concat
|
||||
replace(make<DfgConcat>(vtxp, lhsp, rhsp));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!tConcatp->hasMultipleSinks()) {
|
||||
if (DfgConcat* const tRCatp = tConcatp->rhsp()->cast<DfgConcat>()) {
|
||||
if (!tRCatp->hasMultipleSinks()) {
|
||||
if (DfgSel* const tLSelp = tConcatp->lhsp()->cast<DfgSel>()) {
|
||||
if (DfgSel* const tRRSelp = tRCatp->rhsp()->cast<DfgSel>()) {
|
||||
if (tLSelp->lsb() == tRCatp->width() //
|
||||
&& tRRSelp->lsb() == 0 //
|
||||
&& isSame(tLSelp->fromp(), elsep) //
|
||||
&& isSame(tRRSelp->fromp(), elsep)) {
|
||||
APPLYING(REPLACE_COND_INSERT) {
|
||||
DfgVertex* const newTp = tRCatp->lhsp();
|
||||
DfgVertex* const newEp = make<DfgSel>(
|
||||
flp, newTp->dtype(), elsep, tRRSelp->width());
|
||||
DfgCond* const newCp = make<DfgCond>(flp, newTp->dtype(),
|
||||
condp, newTp, newEp);
|
||||
replace(make<DfgConcat>(
|
||||
vtxp, tLSelp,
|
||||
make<DfgConcat>(tRCatp, newCp, tRRSelp)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const std::pair<DfgVertex*, uint32_t> cMSBs = commonMSBs(thenp, elsep);
|
||||
if (cMSBs.first) {
|
||||
APPLYING(REPLACE_COND_COMMON_MSBS) {
|
||||
// Create new LHS
|
||||
const uint32_t lWidth = cMSBs.second;
|
||||
DfgVertex* lhsp = cMSBs.first;
|
||||
if (lWidth != lhsp->width()) {
|
||||
const DfgDataType& lDtype = DfgDataType::packed(lWidth);
|
||||
lhsp = make<DfgSel>(flp, lDtype, lhsp, lhsp->width() - lWidth);
|
||||
}
|
||||
// If it's all the same, just replace
|
||||
if (lhsp->dtype() == vtxp->dtype()) {
|
||||
// Note this branch can only be hit if rules run in the right order,
|
||||
// it might have missing code coverage after a refactor.
|
||||
replace(lhsp);
|
||||
return;
|
||||
}
|
||||
// Create new RHS
|
||||
const uint32_t rWidth = vtxp->width() - lWidth;
|
||||
const DfgDataType& rDtype = DfgDataType::packed(rWidth);
|
||||
DfgVertex* const rThenp = make<DfgSel>(flp, rDtype, thenp, 0U);
|
||||
DfgVertex* const rElsep = make<DfgSel>(flp, rDtype, elsep, 0U);
|
||||
DfgVertex* const rhsp = make<DfgCond>(flp, rDtype, condp, rThenp, rElsep);
|
||||
// Replace with concat
|
||||
replace(make<DfgConcat>(vtxp, lhsp, rhsp));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -112,17 +112,16 @@
|
|||
_FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_CONCAT_SAME_REP_ON_RHS) \
|
||||
_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_COMMON_LSBS) \
|
||||
_FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_COND_COMMON_MSBS) \
|
||||
_FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_COND_CONST_ONES_ZERO) \
|
||||
_FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_COND_CONST_ONE_ZERO) \
|
||||
_FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_COND_CONST_ZERO_ONE) \
|
||||
_FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_COND_CONST_ZERO_ONES) \
|
||||
_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_INSERT) \
|
||||
_FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_COND_OR_THEN_COND_LHS) \
|
||||
_FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_COND_OR_THEN_COND_RHS) \
|
||||
_FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_COND_SAME_CAT_LHS) \
|
||||
_FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_COND_SAME_CAT_RHS) \
|
||||
_FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_COND_SAME_COND_ELSE) \
|
||||
_FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_COND_SAME_COND_THEN) \
|
||||
_FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION_APPLY(macro, REPLACE_COND_THEN_OR_LHS) \
|
||||
|
|
|
|||
|
|
@ -299,6 +299,7 @@ public:
|
|||
void fromp(DfgVertex* vtxp) { srcp(vtxp); }
|
||||
uint32_t lsb() const { return m_lsb; }
|
||||
void lsb(uint32_t value) { m_lsb = value; }
|
||||
uint32_t msb() const { return m_lsb + width() - 1; }
|
||||
};
|
||||
|
||||
class DfgUnitArray final : public DfgVertexUnary {
|
||||
|
|
|
|||
|
|
@ -283,10 +283,20 @@ module t (
|
|||
`signal(REPLACE_COND_CONST_ZERO_ONAE, rand_a[0] ? 80'b0 : -80'b1);
|
||||
`signal(REPLACE_COND_CAT_LHS_CONST_ONE_ZERO, rand_a[0] ? {8'b1, rand_b[0]} : {8'b0, rand_b[1]});
|
||||
`signal(REPLACE_COND_CAT_LHS_CONST_ZERO_ONE, rand_a[0] ? {8'b0, rand_b[0]} : {8'b1, rand_b[1]});
|
||||
`signal(REPLACE_COND_SAME_CAT_LHS, rand_a[0] ? {8'd0, rand_b[0]} : {8'd0, rand_b[1]});
|
||||
`signal(REPLACE_COND_SAME_CAT_RHS, rand_a[0] ? {rand_b[0], 8'd0} : {rand_b[1], 8'd0});
|
||||
`signal(REPLACE_COND_SAM_COND_THEN, rand_a[0] ? (rand_a[0] ? rand_b[1:0] : rand_b[3:2]) : rand_b[5:4]);
|
||||
`signal(REPLACE_COND_SAM_COND_ELSE, rand_a[0] ? rand_b[1:0] : (rand_a[0] ? rand_b[3:2] : rand_b[5:4]));
|
||||
|
||||
`signal(REPLACE_COND_COMMON_MSBS_A, rand_a[0] ? {8'd0, rand_b[0]} : {8'd0, rand_b[1]});
|
||||
`signal(REPLACE_COND_COMMON_MSBS_B, rand_a[0] ? {8'hf0, rand_b[1:0]} : {9'h1e2, rand_b[1]});
|
||||
`signal(REPLACE_COND_COMMON_MSBS_C, rand_a[0] ? {rand_a[63 -: 3] , rand_b[0]} : {rand_a[63 -: 2], rand_b[2:1]});
|
||||
`signal(REPLACE_COND_COMMON_LSBS_A, rand_a[0] ? {rand_b[0], 8'd0} : {rand_b[1], 8'd0});
|
||||
`signal(REPLACE_COND_COMMON_LSBS_B, rand_a[0] ? {rand_b[2:1], 8'h0f} : {rand_b[1], 9'h08f});
|
||||
`signal(REPLACE_COND_COMMON_LSBS_C, rand_a[0] ? {rand_b[0], rand_a[3:0]} : {rand_b[1:0], rand_a[2:0]});
|
||||
wire [5:0] tmp_REPLACE_COND_COMMON_LSBS_D = rand_b[5:0];
|
||||
wire [5:0] tmp_REPLACE_COND_COMMON_MSBS_D = rand_b[63:58];
|
||||
`signal(REPLACE_COND_COMMON_LSBS_D, rand_a[0] ? rand_b[4:0] : tmp_REPLACE_COND_COMMON_LSBS_D[4:0]);
|
||||
`signal(REPLACE_COND_COMMON_MSBS_D, rand_a[0] ? rand_b[63:59] : tmp_REPLACE_COND_COMMON_MSBS_D[5:1]);
|
||||
|
||||
`signal(REMOVE_SHIFTL_ZERO, rand_a << 0);
|
||||
`signal(REPLACE_SHIFTL_OVER, rand_a << 64);
|
||||
`signal(REPLACE_SHIFTL_SEL, rand_a[27:0] << 4);
|
||||
|
|
@ -352,7 +362,6 @@ module t (
|
|||
`signal(REMOVE_EQ_BIT_1, 1'b1 == rand_a[0]);
|
||||
`signal(REMOVE_NEQ_BIT_0, 1'b0 != rand_a[0]);
|
||||
`signal(REPLACE_NEQ_BIT_1, 1'b1 != rand_a[0]);
|
||||
`signal(REPLACE_COND_INSERT, rand_a[0] ? {rand_b[63:40], {1'd0, rand_b[38:0]}} : rand_b);
|
||||
`signal(REPLACE_REP_REP, {2{({3{rand_a[0]}})}});
|
||||
|
||||
// Operators that should work wiht mismatched widths
|
||||
|
|
|
|||
Loading…
Reference in New Issue