code wiki / _hdl_build / nx_js_floatfuse_probe.nx
nx_js_floatfuse_probe.nx source
↩ module page · 52 lines · 3833 B
1// nx_js_floatfuse_probe.nx -- SELF-ASSERTING perf-regression GATE for the const-fusion float fallback.
2// `s=s+1` with `s` a FLOAT is the `float +/- int-literal` pattern: it fuses (PUSH 1 is an int const) but the
3// LHS is float at runtime -> the fast path misses -> fallback. The fallback MUST use jit_binop's inline SSE
4// (addsd), NOT the ~10x-slower jit_slow_binop sovereign slow-helper call. This gate catches that regression AUTOMATICALLY (the
5// correctness suite can't -- it's bit-exact, not timed): the SSE fallback puts the FLOAT loop within ~1.2x of
6// the pure-INT control (both are ~1 mem-round-trip/iter); the broken sovereign-slow-helper made it ~10x. Assert float < 4x
7// int (clean separation, robust to the machine's +-25% load noise). This is the gate that would have caught
8// the 2026-07-14 10x regression. expect_exit: 0 license_tier: ORIGINAL
9import "nx_js_vm.nx"
10func pw(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
11func pn(v: i64) -> i64 {
12 if v == 0 { sys_write(1, "0" as *u8, 1); return 0 }
13 var m: i64 = v; if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m }
14 let t: *u8 = sys_mmap(24); var k: i64 = 0
15 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
16 var q: i64 = k - 1; while q >= 0 { sys_write(1, ((t as i64) + q) as *u8, 1); q = q - 1 }
17 return 0
18}
19// time best-of-5 compile_run(src); print us + result + jit-status; RETURN best us.
20func timed(src: *u8, name: *u8) -> i64 {
21 let out: *i64 = sys_mmap(16) as *i64
22 var best: i64 = 0; var r: i64 = 0
23 while r < 5 {
24 let t0: i64 = sys_now_us(); let rc: i64 = compile_run(src, out); let t1: i64 = sys_now_us()
25 var us: i64 = t1 - t0; if us < 1 { us = 1 }
26 if r == 0 { best = us } if us < best { best = us }
27 r = r + 1
28 }
29 pw(" "); pw(name); pw(" best-of-5 = "); pn(best); pw("us result=")
30 if out[0] == VAL_FLOAT { let s: *i64 = ev_f64_str(out[1]); sys_write(1, ev_str_bytes(s), ev_str_len(s)) }
31 else { if out[0] == VAL_NUM { pn(out[1]) } else { pw("tag="); pn(out[0]) } }
32 pw(" [jit="); let jd: i64 = js_jit_probe(src); if jd == 1 { pw("Y") } else { pw("N") } pw("]\n")
33 return best
34}
35func main(argc: i64, argv: *i64) -> i64 {
36 pw("=== nx_js_floatfuse_probe GATE: const-fusion float fallback must stay INLINE-SSE (not the sovereign slow-helper call) ===\n" as *u8)
37 let fl: i64 = timed("var s=0.5;var i=0;while(i<3000000){s=s+1;i=i+1;}s" as *u8, "FLOAT s=s+1 (float+INTconst, fused->fallback)" as *u8)
38 // CONTROL = float + FLOAT-const (`s=s+1.5` -> PUSHK float -> UN-fused jit_binop -> its inline-SSE path).
39 // Both loops are float => both PERMANENTLY decline the int-register tier and run the SAME boxed stack-JIT
40 // shape; healthy fallback == SSE both sides (ratio ~1.0), a slow-helper regression makes the int-const side
41 // ~10x. (The original control was a pure-INT loop -- it became register-tier eligible 2026-07-14 and got
42 // ~5x faster, blowing the ratio past the threshold with NO float regression: a calibration artifact.)
43 let fc: i64 = timed("var s=0.5;var i=0;while(i<3000000){s=s+1.5;i=i+1;}s" as *u8, "FLOAT s=s+1.5 (float+FLOATconst, un-fused SSE)" as *u8)
44 pw(" ratio intconst/floatconst = "); pn(fl * 100 / fc); pw(" (x100; SSE fallback ~100, sovereign-slow-helper regression ~1000)\n" as *u8)
45 // GREEN iff float+intconst is within 4x of float+floatconst -> the fallback is inline SSE, not jit_slow_binop.
46 if fl < fc * 4 {
47 pw("=== GREEN: float+/-int-literal fallback is inline-SSE (within 4x of the un-fused SSE float loop) ===\n" as *u8)
48 return 0
49 }
50 pw("=== RED: float+int-literal is >4x the un-fused float loop -> the const-fusion fallback regressed to the sovereign slow-helper call ===\n" as *u8)
51 return 1
52}