Fixed topological ordering in freduce pass

This commit is contained in:
Clifford Wolf 2013-08-07 19:38:19 +02:00
parent e729857647
commit 56e01ce389
1 changed files with 67 additions and 54 deletions

View File

@ -46,14 +46,11 @@ struct FreduceHelper
SigPool inputs, nodes; SigPool inputs, nodes;
RTLIL::SigSpec input_sigs; RTLIL::SigSpec input_sigs;
SigSet<RTLIL::SigSpec> driver_inputs; SigSet<RTLIL::SigSpec> source_signals;
std::vector<RTLIL::Const> test_vectors; std::vector<RTLIL::Const> test_vectors;
std::map<RTLIL::SigSpec, RTLIL::Const> node_to_data; std::map<RTLIL::SigSpec, RTLIL::Const> node_to_data;
std::map<RTLIL::SigSpec, RTLIL::SigSpec> node_result; std::map<RTLIL::SigSpec, RTLIL::SigSpec> node_result;
std::vector<RTLIL::SigSig> result_groups;
SigPool groups_unlink;
uint32_t xorshift32_state; uint32_t xorshift32_state;
uint32_t xorshift32() { uint32_t xorshift32() {
@ -93,8 +90,9 @@ struct FreduceHelper
int max_node_len = 20; int max_node_len = 20;
for (auto &it : node_to_data) for (auto &it : node_to_data)
max_node_len = std::max(max_node_len, int(strlen(log_signal(it.first)))); max_node_len = std::max(max_node_len, int(strlen(log_signal(it.first))));
log(" full node fingerprints:\n");
for (auto &it : node_to_data) for (auto &it : node_to_data)
log(" %-*s %s\n", max_node_len+5, log_signal(it.first), log_signal(it.second)); log(" %-*s %s\n", max_node_len+5, log_signal(it.first), log_signal(it.second));
} }
void check(RTLIL::SigSpec sig1, RTLIL::SigSpec sig2) void check(RTLIL::SigSpec sig1, RTLIL::SigSpec sig2)
@ -165,16 +163,20 @@ struct FreduceHelper
} }
} }
bool topsort_helper(RTLIL::SigSpec cursor, RTLIL::SigSpec stoplist) bool toproot_helper(RTLIL::SigSpec cursor, RTLIL::SigSpec stoplist, int level)
{ {
if (stoplist.extract(cursor).width != 0) // log(" %*schecking %s: %s\n", level*2, "", log_signal(cursor), log_signal(stoplist));
if (stoplist.extract(cursor).width != 0) {
// log(" %*s STOP\n", level*2, "");
return false; return false;
}
stoplist.append(cursor); stoplist.append(cursor);
std::set<RTLIL::SigSpec> next = driver_inputs.find(cursor); std::set<RTLIL::SigSpec> next = source_signals.find(cursor);
for (auto &it : next) for (auto &it : next)
if (!topsort_helper(it, stoplist)) if (!toproot_helper(it, stoplist, level+1))
return false; return false;
return true; return true;
@ -182,18 +184,61 @@ struct FreduceHelper
// KISS topological sort of bits in signal. return one element of sig // KISS topological sort of bits in signal. return one element of sig
// without dependencies to the others (or empty if input is not a DAG). // without dependencies to the others (or empty if input is not a DAG).
RTLIL::SigSpec topsort(RTLIL::SigSpec sig) RTLIL::SigSpec toproot(RTLIL::SigSpec sig)
{ {
sig.expand(); sig.expand();
// log(" finding topological root in %s:\n", log_signal(sig));
for (auto &c : sig.chunks) { for (auto &c : sig.chunks) {
RTLIL::SigSpec stoplist = sig; RTLIL::SigSpec stoplist = sig;
stoplist.remove(c); stoplist.remove(c);
if (topsort_helper(c, stoplist)) // log(" testing %s as root:\n", log_signal(c));
if (toproot_helper(c, stoplist, 0))
return c; return c;
} }
return RTLIL::SigSpec(); return RTLIL::SigSpec();
} }
void update_design_for_group(RTLIL::SigSpec root, RTLIL::SigSpec rest)
{
SigPool unlink;
unlink.add(rest);
for (auto &cell_it : module->cells) {
RTLIL::Cell *cell = cell_it.second;
if (!ct.cell_known(cell->type))
continue;
for (auto &conn : cell->connections)
if (ct.cell_output(cell->type, conn.first)) {
RTLIL::SigSpec sig = sigmap(conn.second);
sig.expand();
bool did_something = false;
for (auto &c : sig.chunks) {
if (c.wire == NULL || !unlink.check_any(c))
continue;
c.wire = new RTLIL::Wire;
c.wire->name = NEW_ID;
module->add(c.wire);
assert(c.width == 1);
c.offset = 0;
did_something = true;
}
if (did_something) {
sig.optimize();
conn.second = sig;
}
}
}
rest.expand();
for (auto &c : rest.chunks) {
if (c.wire != NULL && !root.is_fully_const()) {
source_signals.erase(c);
source_signals.insert(c, root);
}
module->connections.push_back(RTLIL::SigSig(c, root));
}
}
void analyze_groups() void analyze_groups()
{ {
SigMap to_group_major; SigMap to_group_major;
@ -212,15 +257,19 @@ struct FreduceHelper
RTLIL::SigSig group = it; RTLIL::SigSig group = it;
if (!it.first.is_fully_const()) { if (!it.first.is_fully_const()) {
group.first = topsort(it.second); group.first = toproot(it.second);
if (group.first.width == 0) if (group.first.width == 0) {
log_error("Operating on non-DAG input: failed to find topological root for `%s'.\n", log_signal(it.second)); log("Operating on non-DAG input: failed to find topological root for `%s'.\n", log_signal(it.second));
return;
}
group.second.remove(group.first); group.second.remove(group.first);
} }
group.first.optimize(); group.first.optimize();
group.second.sort_and_unify(); group.second.sort_and_unify();
result_groups.push_back(group);
log(" found group: %s -> %s\n", log_signal(group.first), log_signal(group.second));
update_design_for_group(group.first, group.second);
} }
} }
@ -249,7 +298,7 @@ struct FreduceHelper
cell_inputs.expand(); cell_inputs.expand();
for (auto &c : cell_inputs.chunks) for (auto &c : cell_inputs.chunks)
if (c.wire != NULL) if (c.wire != NULL)
driver_inputs.insert(cell_outputs, c); source_signals.insert(cell_outputs, c);
if (!satgen.importCell(cell)) if (!satgen.importCell(cell))
log_error("Failed to import cell to SAT solver: %s (%s)\n", log_error("Failed to import cell to SAT solver: %s (%s)\n",
RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type)); RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
@ -276,7 +325,7 @@ struct FreduceHelper
for (auto &test_vec : test_vectors) for (auto &test_vec : test_vectors)
run_test(test_vec); run_test(test_vec);
// run the analysis // run the analysis and update design
analyze_const(); analyze_const();
analyze_alias(); analyze_alias();
@ -285,44 +334,8 @@ struct FreduceHelper
for (auto &test_vec : test_vectors) for (auto &test_vec : test_vectors)
log(" test vector: %s\n", log_signal(test_vec)); log(" test vector: %s\n", log_signal(test_vec));
dump_node_data();
analyze_groups(); analyze_groups();
for (auto &it : result_groups) {
log(" found group: %s -> %s\n", log_signal(it.first), log_signal(it.second));
groups_unlink.add(it.second);
}
for (auto &cell_it : module->cells) {
RTLIL::Cell *cell = cell_it.second;
if (!ct.cell_known(cell->type))
continue;
for (auto &conn : cell->connections)
if (ct.cell_output(cell->type, conn.first)) {
RTLIL::SigSpec sig = sigmap(conn.second);
sig.expand();
bool did_something = false;
for (auto &c : sig.chunks) {
if (c.wire == NULL || !groups_unlink.check_any(c))
continue;
c.wire = new RTLIL::Wire;
c.wire->name = NEW_ID;
module->add(c.wire);
assert(c.width == 1);
c.offset = 0;
did_something = true;
}
if (did_something) {
sig.optimize();
conn.second = sig;
}
}
}
for (auto &it : result_groups) {
it.second.expand();
for (auto &c : it.second.chunks)
module->connections.push_back(RTLIL::SigSig(c, it.first));
}
} }
}; };