code wiki / _hdl_build / nx_eqsat_congruence_bench.nx
nx_eqsat_congruence_bench.nx
buildroot/runtime/_hdl_build/nx_eqsat_congruence_bench.nx
about
nx_eqsat_congruence_bench.nx -- NON-TOY CONGRUENCE-HEAVY race vs egg 0.11.0.
THE RACE (engine-only, SAME expression both sides):
egg target = /tmp/race_egg/examples/nx_cong.rs, the congruence-heavy graph:
base a = (* x 8), b = (<< x 3) -- mul-pow2 merges a~b
N pairs la_i = (- a c_i), lb_i = (- b c_i) -- become CONGRUENT after a~b
root = (+ (+ ... (+ 0 (+ la_0 lb_0)) ...) (+ la_{N-1} lb_{N-1}))
so after the single base merge, the engine's congruence closure must propagate
N parent merges (la_i ~ lb_i) -- the exact reachability work egg's deferred
rebuild does and the pre-MEET nx_eqsat could NOT do. This is NOT the toy
(* x 8) single-rewrite race; congruence FIRES N times per iteration.
OUR side, per timed iteration (the SAME end-to-end optimize pipeline egg ran,
no proxy, no membership/provenance machinery egg lacks):
nx_eqsat_init (fresh e-graph)
enable_meet (egg hashcons + congruence rebuild ON)
build a, b, N parent pairs, root (egg's RecExpr build)
nx_eqsat_saturate (egg's Runner::run -- rules + rebuild to fixpoint)
nx_eqsat_recompute_best (egg's Extractor bottom-up cost)
nx_eqsat_extract_best_node(root) (egg's find_best)
FAIL LOUD: before timing, one verified iteration asserts congruence actually
fired -- find(la_i)==find(lb_i) for ALL i (== egg's internal congruence). A
fast wrong answer (congruence NOT propagated) loses, exit nonzero.
Output (one line):
NX_CONG_ENGINE_ONLY N=<n> ITERS=<it> CONG_MERGES=<n> TOTAL_US=<t> US_PER_OP_NS=<u>
(US_PER_OP_NS = total_us*1000/iters = nanoseconds/op; divide by 1000 for us/op.)
SOVEREIGN: no .sh; runs on the pinned NishiLang compiler. license_tier: ORIGINAL
dependencies 1 imports · 0 importers
imports: nx_eqsat.nx
imported by: nobody (leaf or entry point)
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 33 | const K_MAGIC_2000: i64 = 2000 |
| 34 | const K_MAGIC_2048: i64 = 2048 |
| 35 | const K_MAGIC_4096: i64 = 4096 |
| 36 | const K_MAGIC_8192: i64 = 8192 |
functions
| 38 | func _emit_num(v: i64) -> i64 called by 1: main |
| 46 | func _emit_str(s: *u8, len: i64) -> i64 { sys_write(1, s, len); return 0 } called by 1: main |
| 47 | func _nl() -> i64 { let z: *u8 = sys_mmap(2); z[0] = 10; sys_write(1, z, 1); return 0 } called by 1: main |
| 54 | func _one_iter(g: *NxEGraph, |
| 108 | func main() -> i64 |