Improve DFG to enable breaking more combinational cycles
This commit is contained in:
parent
7696b0651c
commit
762c5f573c
|
|
@ -74,7 +74,9 @@ class TraceDriver final : public DfgVisitor {
|
|||
// Denotes if a 'Visited' entry appear in m_stack
|
||||
std::unordered_map<Visited, bool, Visited::Hash, Visited::Equal> m_visited;
|
||||
|
||||
#ifdef VL_DEBUG
|
||||
std::ofstream m_lineCoverageFile; // Line coverage file, just for testing
|
||||
#endif
|
||||
|
||||
// METHODS
|
||||
|
||||
|
|
@ -190,7 +192,7 @@ class TraceDriver final : public DfgVisitor {
|
|||
}
|
||||
|
||||
template <typename Vertex>
|
||||
Vertex* bitwiseBinary(Vertex* vtxp) {
|
||||
Vertex* traceBinary(Vertex* vtxp) {
|
||||
static_assert(std::is_base_of<DfgVertexBinary, Vertex>::value,
|
||||
"Should only call on DfgVertexBinary");
|
||||
if (DfgVertex* const rp = trace(vtxp->rhsp(), m_msb, m_lsb)) {
|
||||
|
|
@ -229,11 +231,15 @@ class TraceDriver final : public DfgVisitor {
|
|||
// Use this macro to set the result in 'visit' methods. This also emits
|
||||
// a line to m_lineCoverageFile for testing.
|
||||
// TODO: Use C++20 std::source_location instead of a macro
|
||||
#ifdef VL_DEBUG
|
||||
#define SET_RESULT(vtxp) \
|
||||
do { \
|
||||
m_resp = vtxp; \
|
||||
if (VL_UNLIKELY(m_lineCoverageFile.is_open())) m_lineCoverageFile << __LINE__ << '\n'; \
|
||||
} while (false)
|
||||
#else
|
||||
#define SET_RESULT(vtxp) m_resp = vtxp;
|
||||
#endif
|
||||
|
||||
// VISITORS
|
||||
void visit(DfgVertex* vtxp) override {
|
||||
|
|
@ -350,15 +356,47 @@ class TraceDriver final : public DfgVisitor {
|
|||
|
||||
void visit(DfgAnd* vtxp) override {
|
||||
if (!m_aggressive) return;
|
||||
SET_RESULT(bitwiseBinary(vtxp));
|
||||
SET_RESULT(traceBinary(vtxp));
|
||||
}
|
||||
void visit(DfgOr* vtxp) override {
|
||||
if (!m_aggressive) return;
|
||||
SET_RESULT(bitwiseBinary(vtxp));
|
||||
SET_RESULT(traceBinary(vtxp));
|
||||
}
|
||||
void visit(DfgXor* vtxp) override {
|
||||
if (!m_aggressive) return;
|
||||
SET_RESULT(bitwiseBinary(vtxp));
|
||||
SET_RESULT(traceBinary(vtxp));
|
||||
}
|
||||
void visit(DfgAdd* vtxp) override {
|
||||
if (!m_aggressive) return;
|
||||
SET_RESULT(traceBinary(vtxp));
|
||||
}
|
||||
void visit(DfgSub* vtxp) override {
|
||||
if (!m_aggressive) return;
|
||||
SET_RESULT(traceBinary(vtxp));
|
||||
}
|
||||
void visit(DfgEq* vtxp) override {
|
||||
if (!m_aggressive) return;
|
||||
SET_RESULT(traceBinary(vtxp));
|
||||
}
|
||||
void visit(DfgNeq* vtxp) override {
|
||||
if (!m_aggressive) return;
|
||||
SET_RESULT(traceBinary(vtxp));
|
||||
}
|
||||
void visit(DfgLt* vtxp) override {
|
||||
if (!m_aggressive) return;
|
||||
SET_RESULT(traceBinary(vtxp));
|
||||
}
|
||||
void visit(DfgLte* vtxp) override {
|
||||
if (!m_aggressive) return;
|
||||
SET_RESULT(traceBinary(vtxp));
|
||||
}
|
||||
void visit(DfgGt* vtxp) override {
|
||||
if (!m_aggressive) return;
|
||||
SET_RESULT(traceBinary(vtxp));
|
||||
}
|
||||
void visit(DfgGte* vtxp) override {
|
||||
if (!m_aggressive) return;
|
||||
SET_RESULT(traceBinary(vtxp));
|
||||
}
|
||||
|
||||
void visit(DfgShiftR* vtxp) override {
|
||||
|
|
@ -432,6 +470,22 @@ class TraceDriver final : public DfgVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
void visit(DfgCond* vtxp) override {
|
||||
if (!m_aggressive) return;
|
||||
if (DfgVertex* const condp = trace(vtxp->condp(), 0, 0)) {
|
||||
if (DfgVertex* const thenp = trace(vtxp->thenp(), m_msb, m_lsb)) {
|
||||
if (DfgVertex* const elsep = trace(vtxp->elsep(), m_msb, m_lsb)) {
|
||||
DfgCond* const resp = make<DfgCond>(vtxp, m_msb - m_lsb + 1);
|
||||
resp->condp(condp);
|
||||
resp->thenp(thenp);
|
||||
resp->elsep(elsep);
|
||||
SET_RESULT(resp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef SET_RESULT
|
||||
|
||||
// CONSTRUCTOR
|
||||
|
|
@ -439,12 +493,14 @@ class TraceDriver final : public DfgVisitor {
|
|||
: m_dfg{dfg}
|
||||
, m_component{component}
|
||||
, m_aggressive{aggressive} {
|
||||
#ifdef VL_DEBUG
|
||||
if (v3Global.opt.debugCheck()) {
|
||||
m_lineCoverageFile.open( //
|
||||
v3Global.opt.makeDir() + "/" + v3Global.opt.prefix()
|
||||
+ "__V3DfgBreakCycles-TraceDriver-line-coverage.txt", //
|
||||
std::ios_base::out | std::ios_base::app);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
|
|
@ -503,15 +559,37 @@ class IndependentBits final : public DfgVisitor {
|
|||
// Use this macro to call 'mask' in 'visit' methods. This also emits
|
||||
// a line to m_lineCoverageFile for testing.
|
||||
// TODO: Use C++20 std::source_location instead of a macro
|
||||
#ifdef VL_DEBUG
|
||||
#define MASK(vtxp) \
|
||||
([this](const DfgVertex* p) -> V3Number& { \
|
||||
if (VL_UNLIKELY(m_lineCoverageFile.is_open())) m_lineCoverageFile << __LINE__ << '\n'; \
|
||||
return mask(p); \
|
||||
}(vtxp))
|
||||
#else
|
||||
#define MASK(vtxp) mask(vtxp)
|
||||
#endif
|
||||
|
||||
// Set all bits at or below the most signicant set bit
|
||||
void floodTowardsLsb(V3Number& num) {
|
||||
bool set = false;
|
||||
for (int i = num.width() - 1; i >= 0; --i) {
|
||||
if (num.bitIs1(i)) set = true;
|
||||
if (set) num.setBit(i, '1');
|
||||
}
|
||||
}
|
||||
|
||||
// Set all bits at or above the least signicant set bit
|
||||
void floodTowardsMsb(V3Number& num) {
|
||||
bool set = false;
|
||||
for (int i = 0; i < num.width(); ++i) {
|
||||
if (num.bitIs1(i)) set = true;
|
||||
if (set) num.setBit(i, '1');
|
||||
}
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
void visit(DfgVertex* vtxp) override {
|
||||
UINFO(9, "Unhandled vertex type " << vtxp->typeName());
|
||||
UINFO(9, "IndependentBits - Unhandled vertex type: " << vtxp->typeName());
|
||||
// Conservative assumption about all bits being dependent prevails
|
||||
}
|
||||
|
||||
|
|
@ -594,6 +672,42 @@ class IndependentBits final : public DfgVisitor {
|
|||
MASK(vtxp).opOr(MASK(vtxp->lhsp()), MASK(vtxp->rhsp()));
|
||||
}
|
||||
|
||||
void visit(DfgAdd* vtxp) override {
|
||||
V3Number& m = MASK(vtxp);
|
||||
m.opOr(MASK(vtxp->lhsp()), MASK(vtxp->rhsp()));
|
||||
floodTowardsMsb(m);
|
||||
}
|
||||
void visit(DfgSub* vtxp) override { // Same as Add: 2's complement (a - b) == (a + ~b + 1)
|
||||
V3Number& m = MASK(vtxp);
|
||||
m.opOr(MASK(vtxp->lhsp()), MASK(vtxp->rhsp()));
|
||||
floodTowardsMsb(m);
|
||||
}
|
||||
|
||||
void visit(DfgEq* vtxp) override {
|
||||
const bool independent = MASK(vtxp->lhsp()).isEqZero() && MASK(vtxp->rhsp()).isEqZero();
|
||||
MASK(vtxp).setBit(0, independent ? '0' : '1');
|
||||
}
|
||||
void visit(DfgNeq* vtxp) override {
|
||||
const bool independent = MASK(vtxp->lhsp()).isEqZero() && MASK(vtxp->rhsp()).isEqZero();
|
||||
MASK(vtxp).setBit(0, independent ? '0' : '1');
|
||||
}
|
||||
void visit(DfgLt* vtxp) override {
|
||||
const bool independent = MASK(vtxp->lhsp()).isEqZero() && MASK(vtxp->rhsp()).isEqZero();
|
||||
MASK(vtxp).setBit(0, independent ? '0' : '1');
|
||||
}
|
||||
void visit(DfgLte* vtxp) override {
|
||||
const bool independent = MASK(vtxp->lhsp()).isEqZero() && MASK(vtxp->rhsp()).isEqZero();
|
||||
MASK(vtxp).setBit(0, independent ? '0' : '1');
|
||||
}
|
||||
void visit(DfgGt* vtxp) override {
|
||||
const bool independent = MASK(vtxp->lhsp()).isEqZero() && MASK(vtxp->rhsp()).isEqZero();
|
||||
MASK(vtxp).setBit(0, independent ? '0' : '1');
|
||||
}
|
||||
void visit(DfgGte* vtxp) override {
|
||||
const bool independent = MASK(vtxp->lhsp()).isEqZero() && MASK(vtxp->rhsp()).isEqZero();
|
||||
MASK(vtxp).setBit(0, independent ? '0' : '1');
|
||||
}
|
||||
|
||||
void visit(DfgShiftR* vtxp) override {
|
||||
DfgVertex* const rhsp = vtxp->rhsp();
|
||||
DfgVertex* const lhsp = vtxp->lhsp();
|
||||
|
|
@ -602,22 +716,20 @@ class IndependentBits final : public DfgVisitor {
|
|||
// Constant shift can be computed precisely
|
||||
if (DfgConst* const rConstp = rhsp->cast<DfgConst>()) {
|
||||
const uint32_t shiftAmount = rConstp->toU32();
|
||||
if (shiftAmount >= width) return;
|
||||
V3Number shiftedMask{lhsp->fileline(), static_cast<int>(width), 0};
|
||||
shiftedMask.opShiftR(MASK(lhsp), rConstp->num());
|
||||
V3Number& m = MASK(vtxp);
|
||||
m.opSelInto(shiftedMask, 0, width - shiftAmount);
|
||||
m.opSetRange(width - shiftAmount, shiftAmount, '0');
|
||||
if (shiftAmount >= width) {
|
||||
m.setAllBits0();
|
||||
} else {
|
||||
m.opShiftR(MASK(lhsp), rConstp->num());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, as the shift amount is non-negative, any bit at or below
|
||||
// the most significant dependent bit might be dependent
|
||||
V3Number& lMask = MASK(lhsp);
|
||||
V3Number& vMask = MASK(vtxp);
|
||||
uint32_t lzc = 0; // Leading zero count
|
||||
while (lzc < width && lMask.bitIs0(width - 1 - lzc)) ++lzc;
|
||||
while (lzc > 0) vMask.setBit(width - 1 - (--lzc), '0');
|
||||
V3Number& m = MASK(vtxp);
|
||||
m = MASK(lhsp);
|
||||
floodTowardsLsb(m);
|
||||
}
|
||||
|
||||
void visit(DfgShiftL* vtxp) override {
|
||||
|
|
@ -628,22 +740,28 @@ class IndependentBits final : public DfgVisitor {
|
|||
// Constant shift can be computed precisely
|
||||
if (DfgConst* const rConstp = rhsp->cast<DfgConst>()) {
|
||||
const uint32_t shiftAmount = rConstp->toU32();
|
||||
if (shiftAmount >= width) return;
|
||||
V3Number shiftedMask{lhsp->fileline(), static_cast<int>(width), 0};
|
||||
shiftedMask.opShiftL(MASK(lhsp), rConstp->num());
|
||||
V3Number& m = MASK(vtxp);
|
||||
m.opSelInto(shiftedMask, shiftAmount, width - shiftAmount);
|
||||
m.opSetRange(0, shiftAmount, '0');
|
||||
if (shiftAmount >= width) {
|
||||
m.setAllBits0();
|
||||
} else {
|
||||
m.opShiftL(MASK(lhsp), rConstp->num());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, as the shift amount is non-negative, any bit at or above
|
||||
// the least significant dependent bit might be dependent
|
||||
V3Number& lMask = MASK(lhsp);
|
||||
V3Number& vMask = MASK(vtxp);
|
||||
uint32_t tzc = 0; // Trailing zero count
|
||||
while (tzc < width && lMask.bitIs0(tzc)) ++tzc;
|
||||
while (tzc > 0) vMask.setBit(--tzc, '0');
|
||||
V3Number& m = MASK(vtxp);
|
||||
m = MASK(lhsp);
|
||||
floodTowardsMsb(m);
|
||||
}
|
||||
|
||||
void visit(DfgCond* vtxp) override {
|
||||
if (!MASK(vtxp->condp()).isEqZero()) {
|
||||
MASK(vtxp).setAllBits1();
|
||||
} else {
|
||||
MASK(vtxp).opOr(MASK(vtxp->thenp()), MASK(vtxp->elsep()));
|
||||
}
|
||||
}
|
||||
|
||||
#undef MASK
|
||||
|
|
@ -651,12 +769,15 @@ class IndependentBits final : public DfgVisitor {
|
|||
// CONSTRUCTOR
|
||||
IndependentBits(DfgGraph& dfg, DfgVertex* vtxp)
|
||||
: m_component{vtxp->getUser<uint64_t>()} {
|
||||
|
||||
#ifdef VL_DEBUG
|
||||
if (v3Global.opt.debugCheck()) {
|
||||
m_lineCoverageFile.open( //
|
||||
v3Global.opt.makeDir() + "/" + v3Global.opt.prefix()
|
||||
+ "__V3DfgBreakCycles-IndependentBits-line-coverage.txt", //
|
||||
std::ios_base::out | std::ios_base::app);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Work list for the traversal
|
||||
std::deque<DfgVertex*> workList;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
// any use, without warranty, 2025 by Geza Lore.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
`define signal(name, width) wire [width-1:0] name;
|
||||
`define signal(name, width) wire [width-1:0] name
|
||||
|
||||
module t (
|
||||
`include "portlist.vh" // Boilerplate generated by t_dfg_break_cycles.py
|
||||
|
|
@ -140,4 +140,38 @@ module t (
|
|||
assign array_3[1] = array_3[0];
|
||||
`signal(ARRAY_3, 3);
|
||||
assign ARRAY_3 = array_3[0];
|
||||
|
||||
`signal(ADD, 8);
|
||||
assign ADD = ((ADD << 4) + 8'(rand_a[3:0]));
|
||||
|
||||
`signal(SUB, 8);
|
||||
assign SUB = ((SUB << 4) - 8'(rand_a[3:0]));
|
||||
|
||||
`signal(EQ, 2);
|
||||
assign EQ = {rand_a[0], EQ >> 1 == rand_b[1:0]};
|
||||
|
||||
`signal(NEQ, 2);
|
||||
assign NEQ = {rand_a[0], NEQ >> 1 != rand_b[1:0]};
|
||||
|
||||
`signal(LT, 2);
|
||||
assign LT = {rand_a[0], LT >> 1 < rand_b[1:0]};
|
||||
|
||||
`signal(LTE, 2);
|
||||
assign LTE = {rand_a[0], LTE >> 1 <= rand_b[1:0]};
|
||||
|
||||
`signal(GT, 2);
|
||||
assign GT = {rand_a[0], GT >> 1 > rand_b[1:0]};
|
||||
|
||||
`signal(GTE, 2);
|
||||
assign GTE = {rand_a[0], GTE >> 1 >= rand_b[1:0]};
|
||||
|
||||
`signal(COND_THEN, 3);
|
||||
assign COND_THEN = {rand_a[0], rand_a[0] ? 2'(COND_THEN << 2) : rand_b[1:0]};
|
||||
|
||||
`signal(COND_ELSE, 3);
|
||||
assign COND_ELSE = {rand_a[0], rand_a[0] ? rand_b[1:0] : 2'(COND_ELSE << 2)};
|
||||
|
||||
`signal(COND_COND, 3);
|
||||
assign COND_COND = {rand_a[0], (COND_COND >> 2) == 3'b001 ? rand_b[3:2] : rand_b[1:0]};
|
||||
|
||||
endmodule
|
||||
|
|
|
|||
Loading…
Reference in New Issue