code wiki / (root) / nx_divprobe.nx

nx_divprobe.nx

buildroot/runtime/nx_divprobe.nx

4760 B95 linesdepth 3pulls 3 transitivereach 0 importersview sourcekind tool
docsdependenciesstructsconstsfunctions

about

nx_divprobe.nx -- DOES nx_cc STRENGTH-REDUCE DIVISION BY A CONSTANT POWER OF TWO? WHY THIS PROBE EXISTS. A render-performance lane measured gs_resolve at 12.3 ns/pixel while doing six divisions by 256 -- a power of two -- and concluded from an OUTLINE GREP that the x86 backend has no strength-reduction pass. That is an absence claimed from a FILTERED READ, which this estate does not accept as evidence: a grep that finds no function named "shr" cannot see a shift emitted inline, and would report the same nothing either way. Before any compiler is edited on the strength of that claim, the claim itself gets an instrument. THE EXPERIMENT DISCRIMINATES, which is the only reason to run it. Three loops, identical in every respect except the arithmetic in the hot line: A: / DP_POW2 -- divisor IS a power of two, so a strength-reducing compiler emits a shift B: / DP_NOTPOW2 -- divisor is one less, NOT a power of two, so no compiler can avoid the idiv C: * DP_MUL -- a multiply, the cost floor for "arithmetic that is not division" If A is much faster than B and close to C -> strength reduction EXISTS; the rung is REFUTED. If A and B are alike and both far above C -> no strength reduction; the rung is CONFIRMED. Either outcome is a result. The probe is written to be unable to flatter the answer it was built hoping for: the two divisors differ by one, so nothing but the power-of-two property distinguishes them, and the accumulator is PRINTED so no loop can be optimised away as dead. DP_ITERS is DERIVED, not picked: the clock is microsecond-resolution, and a measurement worth trusting needs to exceed that by a wide margin, so the loop runs long enough that each arm takes order-milliseconds. The three arms share one iteration count so their times are directly comparable.

dependencies 2 imports · 0 importers

nx_syscalls.nx nx_gate_verdict.nx nx_divprobe.nx

imports: nx_syscalls.nxnx_gate_verdict.nx

imported by: nobody (leaf or entry point)

call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown

main gv_head gv_puts sys_write sys_clock_now_us sys_now_us sys_mmap nxa_die sys_write ↻ sys_exit nxa_lock_take nxa_lock_addr sys_write ↻ nxa_lock_give nxa_lock_addr ↻ nxa_report_overrun sys_write ↻ nxa_dump_printable sys_write ↻ nxa_dump_sizes sys_write ↻ sys_clock_gettime_mono gv_puts ↻ gv_num sys_mmap ↻ sys_write ↻ sys_munmap

structs

none

consts

29const DP_ITERS: i64 = 20000000
30const DP_POW2: i64 = 256 // the divisor gs_resolve and gs_blend_rect actually use (GFXA)
31const DP_NOTPOW2: i64 = 255 // one less: identical magnitude, NOT a power of two
32const DP_MUL: i64 = 3 // the non-division cost floor
33const DP_SEED: i64 = 1103515245 // an odd starting value so the accumulator does not degenerate

functions

35func main() -> i64