opt_dff: Don't mutate muxes while ModWalker is active.

This commit is contained in:
Marcelina Kościelnicka 2022-01-27 17:06:57 +01:00
parent bac750fb99
commit db33b1e535
1 changed files with 112 additions and 98 deletions

View File

@ -58,13 +58,10 @@ struct OptDffWorker
typedef std::pair<RTLIL::SigBit, bool> ctrl_t;
typedef std::set<ctrl_t> ctrls_t;
ModWalker modwalker;
QuickConeSat qcsat;
// Used as a queue.
std::vector<Cell *> dff_cells;
OptDffWorker(const OptDffOptions &opt, Module *mod) : opt(opt), module(mod), sigmap(mod), initvals(&sigmap, mod), modwalker(module->design, module), qcsat(modwalker) {
OptDffWorker(const OptDffOptions &opt, Module *mod) : opt(opt), module(mod), sigmap(mod), initvals(&sigmap, mod) {
// Gathering two kinds of information here for every sigmapped SigBit:
//
// - bitusers: how many users it has (muxes will only be merged into FFs if this is 1, making the FF the only user)
@ -569,100 +566,6 @@ struct OptDffWorker
changed = true;
}
// Now check if any bit can be replaced by a constant.
pool<int> removed_sigbits;
for (int i = 0; i < ff.width; i++) {
State val = ff.val_init[i];
if (ff.has_arst)
val = combine_const(val, ff.val_arst[i]);
if (ff.has_srst)
val = combine_const(val, ff.val_srst[i]);
if (ff.has_sr) {
if (ff.sig_clr[i] != (ff.pol_clr ? State::S0 : State::S1))
val = combine_const(val, State::S0);
if (ff.sig_set[i] != (ff.pol_set ? State::S0 : State::S1))
val = combine_const(val, State::S1);
}
if (val == State::Sm)
continue;
if (ff.has_clk || ff.has_gclk) {
if (!ff.sig_d[i].wire) {
val = combine_const(val, ff.sig_d[i].data);
if (val == State::Sm)
continue;
} else {
if (!opt.sat)
continue;
// For each register bit, try to prove that it cannot change from the initial value. If so, remove it
if (!modwalker.has_drivers(ff.sig_d.extract(i)))
continue;
if (val != State::S0 && val != State::S1)
continue;
int init_sat_pi = qcsat.importSigBit(val);
int q_sat_pi = qcsat.importSigBit(ff.sig_q[i]);
int d_sat_pi = qcsat.importSigBit(ff.sig_d[i]);
qcsat.prepare();
// Try to find out whether the register bit can change under some circumstances
bool counter_example_found = qcsat.ez->solve(qcsat.ez->IFF(q_sat_pi, init_sat_pi), qcsat.ez->NOT(qcsat.ez->IFF(d_sat_pi, init_sat_pi)));
// If the register bit cannot change, we can replace it with a constant
if (counter_example_found)
continue;
}
}
if (ff.has_aload) {
if (!ff.sig_ad[i].wire) {
val = combine_const(val, ff.sig_ad[i].data);
if (val == State::Sm)
continue;
} else {
if (!opt.sat)
continue;
// For each register bit, try to prove that it cannot change from the initial value. If so, remove it
if (!modwalker.has_drivers(ff.sig_ad.extract(i)))
continue;
if (val != State::S0 && val != State::S1)
continue;
int init_sat_pi = qcsat.importSigBit(val);
int q_sat_pi = qcsat.importSigBit(ff.sig_q[i]);
int d_sat_pi = qcsat.importSigBit(ff.sig_ad[i]);
qcsat.prepare();
// Try to find out whether the register bit can change under some circumstances
bool counter_example_found = qcsat.ez->solve(qcsat.ez->IFF(q_sat_pi, init_sat_pi), qcsat.ez->NOT(qcsat.ez->IFF(d_sat_pi, init_sat_pi)));
// If the register bit cannot change, we can replace it with a constant
if (counter_example_found)
continue;
}
}
log("Setting constant %d-bit at position %d on %s (%s) from module %s.\n", val ? 1 : 0,
i, log_id(cell), log_id(cell->type), log_id(module));
initvals.remove_init(ff.sig_q[i]);
module->connect(ff.sig_q[i], val);
removed_sigbits.insert(i);
}
if (!removed_sigbits.empty()) {
std::vector<int> keep_bits;
for (int i = 0; i < ff.width; i++)
if (!removed_sigbits.count(i))
keep_bits.push_back(i);
if (keep_bits.empty()) {
module->remove(cell);
did_something = true;
continue;
}
ff = ff.slice(keep_bits);
ff.cell = cell;
changed = true;
}
// The cell has been simplified as much as possible already. Now try to spice it up with enables / sync resets.
if (ff.has_clk) {
if (!ff.has_arst && !ff.has_sr && (!ff.has_srst || !ff.has_ce || ff.ce_over_srst) && !opt.nosdff) {
@ -818,6 +721,115 @@ struct OptDffWorker
}
return did_something;
}
bool run_constbits() {
ModWalker modwalker(module->design, module);
QuickConeSat qcsat(modwalker);
// Run as a separate sub-pass, so that we don't mutate (non-FF) cells under ModWalker.
bool did_something = false;
for (auto cell : module->selected_cells()) {
if (!RTLIL::builtin_ff_cell_types().count(cell->type))
continue;
FfData ff(&initvals, cell);
// Now check if any bit can be replaced by a constant.
pool<int> removed_sigbits;
for (int i = 0; i < ff.width; i++) {
State val = ff.val_init[i];
if (ff.has_arst)
val = combine_const(val, ff.val_arst[i]);
if (ff.has_srst)
val = combine_const(val, ff.val_srst[i]);
if (ff.has_sr) {
if (ff.sig_clr[i] != (ff.pol_clr ? State::S0 : State::S1))
val = combine_const(val, State::S0);
if (ff.sig_set[i] != (ff.pol_set ? State::S0 : State::S1))
val = combine_const(val, State::S1);
}
if (val == State::Sm)
continue;
if (ff.has_clk || ff.has_gclk) {
if (!ff.sig_d[i].wire) {
val = combine_const(val, ff.sig_d[i].data);
if (val == State::Sm)
continue;
} else {
if (!opt.sat)
continue;
// For each register bit, try to prove that it cannot change from the initial value. If so, remove it
if (!modwalker.has_drivers(ff.sig_d.extract(i)))
continue;
if (val != State::S0 && val != State::S1)
continue;
int init_sat_pi = qcsat.importSigBit(val);
int q_sat_pi = qcsat.importSigBit(ff.sig_q[i]);
int d_sat_pi = qcsat.importSigBit(ff.sig_d[i]);
qcsat.prepare();
// Try to find out whether the register bit can change under some circumstances
bool counter_example_found = qcsat.ez->solve(qcsat.ez->IFF(q_sat_pi, init_sat_pi), qcsat.ez->NOT(qcsat.ez->IFF(d_sat_pi, init_sat_pi)));
// If the register bit cannot change, we can replace it with a constant
if (counter_example_found)
continue;
}
}
if (ff.has_aload) {
if (!ff.sig_ad[i].wire) {
val = combine_const(val, ff.sig_ad[i].data);
if (val == State::Sm)
continue;
} else {
if (!opt.sat)
continue;
// For each register bit, try to prove that it cannot change from the initial value. If so, remove it
if (!modwalker.has_drivers(ff.sig_ad.extract(i)))
continue;
if (val != State::S0 && val != State::S1)
continue;
int init_sat_pi = qcsat.importSigBit(val);
int q_sat_pi = qcsat.importSigBit(ff.sig_q[i]);
int d_sat_pi = qcsat.importSigBit(ff.sig_ad[i]);
qcsat.prepare();
// Try to find out whether the register bit can change under some circumstances
bool counter_example_found = qcsat.ez->solve(qcsat.ez->IFF(q_sat_pi, init_sat_pi), qcsat.ez->NOT(qcsat.ez->IFF(d_sat_pi, init_sat_pi)));
// If the register bit cannot change, we can replace it with a constant
if (counter_example_found)
continue;
}
}
log("Setting constant %d-bit at position %d on %s (%s) from module %s.\n", val ? 1 : 0,
i, log_id(cell), log_id(cell->type), log_id(module));
initvals.remove_init(ff.sig_q[i]);
module->connect(ff.sig_q[i], val);
removed_sigbits.insert(i);
}
if (!removed_sigbits.empty()) {
std::vector<int> keep_bits;
for (int i = 0; i < ff.width; i++)
if (!removed_sigbits.count(i))
keep_bits.push_back(i);
if (keep_bits.empty()) {
module->remove(cell);
did_something = true;
continue;
}
ff = ff.slice(keep_bits);
ff.cell = cell;
ff.emit();
did_something = true;
}
}
return did_something;
}
};
struct OptDffPass : public Pass {
@ -894,6 +906,8 @@ struct OptDffPass : public Pass {
OptDffWorker worker(opt, mod);
if (worker.run())
did_something = true;
if (worker.run_constbits())
did_something = true;
}
if (did_something)