Skip to content

Commit

Permalink
opt_merge: fix the many collisions case
Browse files Browse the repository at this point in the history
  • Loading branch information
widlarizer committed Oct 18, 2024
1 parent 201b9b5 commit f1ab13f
Showing 1 changed file with 38 additions and 9 deletions.
47 changes: 38 additions & 9 deletions passes/opt/opt_merge.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <set>
#include <unordered_map>


USING_YOSYS_NAMESPACE
Expand Down Expand Up @@ -251,6 +252,11 @@ struct OptMergeWorker
initvals.set(&assign_map, module);

bool did_something = true;
bool warned_collisions = false;
// A cell may have to go through a lot of collisions if the hash
// function is performing poorly, but it's a symptom of something bad
// beyond the user's control.
int threshold = 1000; // adjust to taste
while (did_something)
{
std::vector<RTLIL::Cell*> cells;
Expand All @@ -270,7 +276,10 @@ struct OptMergeWorker
}

did_something = false;
dict<Hasher::hash_t, RTLIL::Cell*> sharemap;
// INVARIANT: All cells associated with the same hash in sharemap
// are distinct as far as compare_cell_parameters_and_connections
// can tell.
std::unordered_multimap<Hasher::hash_t, RTLIL::Cell*> sharemap;
for (auto cell : cells)
{
if ((!mode_share_all && !ct.cell_known(cell->type)) || !cell->known())
Expand All @@ -280,21 +289,30 @@ struct OptMergeWorker
continue;

Hasher::hash_t hash = hash_cell_function(cell, Hasher()).yield();
auto r = sharemap.insert(std::make_pair(hash, cell));
if (!r.second) {
if (compare_cell_parameters_and_connections(cell, r.first->second)) {
// Get all cells with matching hashes
auto matching = sharemap.equal_range(hash);
int collisions = 0;
bool found = false;
for (auto it = matching.first; it != matching.second && !found; ++it) {
if (collisions > threshold && !warned_collisions) {
log_warning("High hash collision counts. opt_merge runtime may be excessive.\n" \
"Please report to maintainers.\n");
warned_collisions = true;
}
auto other_cell = it->second;
if (compare_cell_parameters_and_connections(cell, other_cell)) {
found = true;
if (cell->has_keep_attr()) {
if (r.first->second->has_keep_attr())
if (other_cell->has_keep_attr())
continue;
std::swap(r.first->second, cell);
std::swap(other_cell, cell);
}


did_something = true;
log_debug(" Cell `%s' is identical to cell `%s'.\n", cell->name.c_str(), r.first->second->name.c_str());
log_debug(" Cell `%s' is identical to cell `%s'.\n", cell->name.c_str(), other_cell->name.c_str());
for (auto &it : cell->connections()) {
if (cell->output(it.first)) {
RTLIL::SigSpec other_sig = r.first->second->getPort(it.first);
RTLIL::SigSpec other_sig = other_cell->getPort(it.first);
log_debug(" Redirecting output %s: %s = %s\n", it.first.c_str(),
log_signal(it.second), log_signal(other_sig));
Const init = initvals(other_sig);
Expand All @@ -308,8 +326,18 @@ struct OptMergeWorker
log_debug(" Removing %s cell `%s' from module `%s'.\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str());
module->remove(cell);
total_count++;
break;
} else {
collisions++;
log_debug(" False hash match: `%s' and `%s'.\n", cell->name.c_str(), other_cell->name.c_str());
}
}
if (!did_something) {
// This cell isn't represented yet in the sharemap.
// Either it's the first of its hash,
// or falsely matches all cells in sharemap sharing its hash.
sharemap.insert(std::make_pair(hash, cell));
}
}
}

Expand Down Expand Up @@ -340,6 +368,7 @@ struct OptMergePass : public Pass {
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
Pass::call(design, "dump");
log_header(design, "Executing OPT_MERGE pass (detect identical cells).\n");

bool mode_nomux = false;
Expand Down

0 comments on commit f1ab13f

Please sign in to comment.