While in signorm mode the module's index already holds a complete SigMap
of its alias connectivity; connections_ is only a scratch buffer that
restore_connections() materializes that map into on demand. So every
`SigMap sigmap(module)` was a round trip: restore_connections() walked
the entire union-find emitting (bit, sigmap(bit)) pairs, and SigMap::set()
hashed all of them straight back into an identical union-find. Worse,
set() iterates connections() twice, so each construction paid for two
full materializations.
Since restore_connections() emits the representative as the right-hand
side and SigMap::add() leaves the right-hand side as the root, the
rebuild reproduces exactly the classes and representatives it started
from -- so copy the mfp instead. Module::signorm_sigmap() hands it out
after merging any pending connections, and returns nullptr outside
signorm mode, where the old path stands.
The copy also carries entries for bits that map to themselves, which the
connection-derived rebuild would omit. That is only observable through
SigMap::allbits() or by iterating .database, neither of which has a
caller outside sigtools.h.
Measured on a 2000-stage pipeline with dead logic (Debug build, `opt`):
signorm_restore drops from 0.76s over 22 calls to 0.08s over 12, and the
whole run from 7.24s to 6.40s. The sigmap being round-tripped there peaks
at 1.29M entries, which is the alias structure of the post-proc netlist.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MQU5XCqDYY8MbivGkNRrDo
kernel/compressor_tree.cc, passes/tests/test_kogge_stone.cc,
passes/opt/peepopt_shiftpow2.pmg, and techlibs/lattice/lattice_dsp_nexus.pmg
(plus the 5 new constids it needs: A0, B0, PIPELINED, SIGNED, SUBTRACT)
were all added to main after the emil/twines-proc-srcloc fork point, so no
commit in this phase's range ever touches them. They still use the old
IdString-based addWire/addCell/setPort/getParam APIs (NEW_ID, plain \X
port names) that the twine migration replaces, so they fail to build
against current HEAD. Not attributable to any single commit in this
phase per task.md's carve-out for genuinely phase-spanning fixes -
bundled here as its own commit rather than folded into an unrelated
pick.