3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2026-07-15 11:45:41 +00:00

Merge pull request #193 from Silimate/opt_compact_prefix_fix3

opt_compact_prefix fix 3
This commit is contained in:
Akash Levy 2026-06-25 00:49:38 -07:00 committed by GitHub
commit 3876f53c73
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 73 additions and 18 deletions

View file

@ -961,6 +961,22 @@ struct OptCompactPrefixWorker : CutRegionWorker
true, std::max(8192, max_width * max_width * 4), max_width * (max_width + 8));
}
// True if any bit of `sig` is driven by a cell this pass emitted on an
// earlier fixpoint sweep (tagged in execute()). The emitted compaction
// logic still fingerprints as the same function, so this guard stops the
// outer fixpoint loop from re-rewriting its own output indefinitely.
bool root_driver_emitted(const SigSpec &sig)
{
for (auto bit : sigmap(sig)) {
if (!bit.wire)
continue;
Cell *drv = bit_to_driver.at(bit, nullptr);
if (drv && drv->get_bool_attribute(ID(opt_compact_prefix_emitted)))
return true;
}
return false;
}
void run()
{
if (module->has_processes_warn())
@ -990,6 +1006,8 @@ struct OptCompactPrefixWorker : CutRegionWorker
}
if (root_claimed(root.sig))
continue;
if (root_driver_emitted(root.sig))
continue;
int width = GetSize(root.sig);
// Wide roots (>62) are valid forward-pack candidates; the
@ -1505,28 +1523,63 @@ struct OptCompactPrefixPass : public Pass
int total_removed = 0;
int total_emitted = 0;
// Overlapping compaction loops can share post-synthesis logic (e.g. one
// loop's start mask feeding the other loop's cone), so a single sweep
// claims the first region and masks the second. Iterate each module to
// a fixpoint: rewrite, tag the freshly-emitted cells, clean, and re-scan
// until a sweep finds nothing new. The tag (consumed by
// root_driver_emitted) stops the next sweep from re-matching this pass's
// own output, which still fingerprints as the same compaction function.
const int max_sweeps = 16;
for (auto module : design->selected_modules()) {
OptCompactPrefixWorker worker(module, max_width);
if (walk_budget > 0)
worker.walk_budget = walk_budget;
if (eval_budget > 0)
worker.eval_budget = eval_budget;
if (attempt_budget > 0)
worker.attempt_budget = attempt_budget;
worker.run();
total_forward += worker.forward_rewrites;
total_reverse += worker.reverse_rewrites;
total_modulo += worker.modulo_rewrites;
total_removed += worker.old_cells_removed;
total_emitted += worker.new_cells_emitted;
for (int sweep = 0; sweep < max_sweeps; sweep++) {
pool<Cell *> before;
for (auto c : module->cells())
before.insert(c);
OptCompactPrefixWorker worker(module, max_width);
if (walk_budget > 0)
worker.walk_budget = walk_budget;
if (eval_budget > 0)
worker.eval_budget = eval_budget;
if (attempt_budget > 0)
worker.attempt_budget = attempt_budget;
worker.run();
total_forward += worker.forward_rewrites;
total_reverse += worker.reverse_rewrites;
total_modulo += worker.modulo_rewrites;
total_removed += worker.old_cells_removed;
total_emitted += worker.new_cells_emitted;
if (worker.forward_rewrites + worker.reverse_rewrites +
worker.modulo_rewrites == 0)
break;
if (sweep == max_sweeps - 1)
log_warning("opt_compact_prefix: fixpoint not reached for module %s "
"after %d sweeps; some compaction opportunities may remain.\n",
log_id(module), max_sweeps);
// Tag the cells emitted by this sweep so the next sweep skips
// them, then drop the now-dangling old cone so the masked
// sibling region becomes visible. Scope the clean to the module
// under rewrite so untouched modules keep their dangling cells
// until their own sweep, matching the original single-call run.
for (auto c : module->cells())
if (!before.count(c))
c->set_bool_attribute(ID(opt_compact_prefix_emitted));
Pass::call_on_module(design, module, "clean -purge");
}
}
// Drop the internal bookkeeping tag so it never leaks into the netlist.
for (auto module : design->modules())
for (auto c : module->cells())
c->attributes.erase(ID(opt_compact_prefix_emitted));
log("Rewrote %d forward pack(s), %d reverse suffix read(s), %d modulo decimation(s); "
"removed %d old cell(s), emitted %d new cell(s).\n",
total_forward, total_reverse, total_modulo, total_removed, total_emitted);
if (total_forward || total_reverse || total_modulo)
Yosys::run_pass("clean -purge");
}
} OptCompactPrefixPass;

View file

@ -112,7 +112,9 @@ endmodule
EOT
# Mixed implicit and explicit 2
(${YOSYS} -f "verilog -sv" -qp "prep -flatten -top top; select -assert-count 1 t:\$add" - <<EOT
# Port resize is now an informational log() (see "Reduce port resize to warning"),
# which -q suppresses, so run without -q to observe the message.
(${YOSYS} -f "verilog -sv" -p "prep -flatten -top top; select -assert-count 1 t:\$add" - <<EOT
module add(input [7:0] a, input [7:0] b, output [7:0] q);
assign q = a + b;
endmodule
@ -121,4 +123,4 @@ module top(input [7:0] a, input [9:0] b, output [7:0] q);
add add_i(.b, .*);
endmodule
EOT
) 2>&1 | grep -F "Warning: Resizing cell port top.add_i.b from 10 bits to 8 bits." > /dev/null
) 2>&1 | grep -F "Resizing cell port top.add_i.b from 10 bits to 8 bits." > /dev/null