code wiki / _hdl_build / nx_codegen_defect_census.nx

nx_codegen_defect_census.nx source

↩ module page · 395 lines · 15605 B

1// nx_codegen_defect_census.nx -- SOVEREIGN read-only codegen defect census for 2// rung X-PERF-003c1 (the honest BEFORE defect-count the codegen-win rung drives 3// toward zero). 4// 5// WHAT IT DOES (no compiler change -- pure read-only analysis): 6// (1) invokes the REAL sovereign toolchain (fork+execve nx_cc_sovereign.elf on 7// runtime/_hdl_build/nx_clbg_fannkuch.nx, stdout redirected to /tmp/fk.s) to 8// regenerate the actual asm for the fannkuch hot loop -- NOT a fixture. 9// (2) brackets the scan to the fannkuch_redux function body (from "fannkuch_redux:" 10// to the next function label "fk_puts:") and mechanically tallies, per 11// redundant-codegen defect class, occurrences in that hot region: 12// (a) store-then-reload-same-slot : "movq %rR, -K(%rbp)" followed (within a 13// small window) by "movq -K(%rbp), %rR" -- the value just spilled is read 14// straight back into the same register (regalloc not coalescing). 15// (b) dead spill stores : "movq %rR, -K(%rbp)" where slot -K(%rbp) is NEVER 16// referenced again in the region -> the store is dead (regalloc homing a 17// temp that nothing consumes). 18// (c) constant rematerialization : "movabsq $C, ..." emitted more than once 19// for the same constant C inside the region (no constant pool / no CSE in 20// the home-everything emitter). 21// (3) names the SINGLE dominant class by count and pins the originating module: 22// store-then-reload / dead-spill -> origin=regalloc-home-everything (the 23// linear-scan register allocator is not firing on this path: every IR temp 24// gets a unique -NNNN(%rbp) home and round-trips through memory). 25// constant rematerialization -> origin=peephole-missing-in-emitter (the 26// instruction emitter rematerializes constants instead of reusing a live 27// value / constant pool). 28// (4) prints a single machine-parseable MEASURED line the gate reads back: 29// CODEGENDEFECT target=fannkuch_hot total_redundant=<N> store_reload=<a> 30// dead_spill=<b> const_remat=<c> dominant=<class> count=<n> origin=<module> 31// region_lines=<L> verdict=MEASURED 32// 33// PASS (enforced by _xperf003c1_gate): census runs on the REAL sovereign-emitted asm, 34// emits the MEASURED line, and the dominant defect count is > 0 (a real, addressable 35// ROI target exists). spec: knowledge/specs/2026-06-13-codegen-defect-census.md 36// genealogy_id: codegen_defect_census 37// lineage_id: function 38import "nx_syscalls.nx" 39 40const C_MODE_RWX: i64 = 0x1a4 // 0644 41const C_BUFSZ: i64 = 262144 // 256 KiB asm slurp buffer (fk.s ~62 KiB) 42const C_MAXLINES: i64 = 8192 // line-index table capacity 43const C_WIN: i64 = 6 // store->reload lookahead window (lines) 44const C_MAXCONST: i64 = 256 // distinct-constant table capacity 45 46func c_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 47func c_putn(v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m;sys_write(1,"-" as *u8,1)}; let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48;k=1}; while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1}; var i: i64=0; while i<k{bb[i]=t[k-1-i];i=i+1}; sys_write(1,bb,k); return 0 } 48 49// fork + redirect child stdout -> redir_out fd + execve; parent waits; returns 50// WEXITSTATUS or 128+signal. 51func c_run(path: *u8, argv: *i64, envp: *i64, redir_out: i64) -> i64 { 52 let pid: i64 = sys_fork() 53 if pid == 0 { 54 if redir_out >= 0 { sys_dup3(redir_out, 1, 0) } 55 sys_execve(path, argv, envp) 56 sys_exit(127) 57 } 58 let st: *i64 = sys_mmap(16) as *i64 59 sys_wait4(pid, st, 0) 60 let sig: i64 = st[0] & 0x7f 61 if sig != 0 { return 128 + sig } 62 return (st[0] >> 8) & 0xff 63} 64 65// read whole file into buf (NUL-terminated); return byte count. 66func c_slurp(path: *u8, buf: *u8, cap: i64) -> i64 { 67 let fd: i64 = sys_openat_rd(path) 68 if fd < 0 { return 0 } 69 var total: i64 = 0 70 var n: i64 = sys_read(fd, (buf + total) as *u8, cap - 1 - total) 71 while n > 0 { 72 total = total + n 73 n = sys_read(fd, (buf + total) as *u8, cap - 1 - total) 74 } 75 sys_close(fd) 76 buf[total] = 0 as u8 77 return total 78} 79 80// returns 1 if buf[i..] begins with key (NUL-terminated); else 0. 81func c_match_at(buf: *u8, i: i64, key: *u8) -> i64 { 82 var j: i64 = 0 83 while key[j] != (0 as u8) { 84 if buf[i + j] != key[j] { return 0 } 85 j = j + 1 86 } 87 return 1 88} 89 90// index every line: lstart[k] = byte offset of line k's first char. Returns line count. 91func c_index_lines(buf: *u8, blen: i64, lstart: *i64) -> i64 { 92 var nl: i64 = 0 93 lstart[0] = 0 94 nl = 1 95 var i: i64 = 0 96 while i < blen { 97 if buf[i] == (10 as u8) { 98 if nl < C_MAXLINES { 99 lstart[nl] = i + 1 100 nl = nl + 1 101 } 102 } 103 i = i + 1 104 } 105 return nl 106} 107 108// scan a line for the spill-store form " movq %rR, -K(%rbp)". 109// On match: writes reg-tag into regbuf[0] (last char of the reg name = unique enough 110// among rax/rcx/rdx/rbx/rsi/rdi/r8..r15) and returns the slot number K (>0). 111// On no-match returns -1. 112func c_parse_store(buf: *u8, off: i64, regbuf: *i64) -> i64 { 113 if c_match_at(buf, off, " movq %r" as *u8) == 0 { return 0 - 1 } 114 var p: i64 = off + 11 115 // read register name until ',' ; tag = whole reg string folded into an int 116 var tag: i64 = 0 117 var any: i64 = 0 118 while buf[p] != (44 as u8) { 119 if buf[p] == (10 as u8) { return 0 - 1 } 120 if buf[p] == (0 as u8) { return 0 - 1 } 121 tag = tag * 131 + (buf[p] as i64) 122 any = 1 123 p = p + 1 124 } 125 if any == 0 { return 0 - 1 } 126 // expect ", -" 127 if buf[p] != (44 as u8) { return 0 - 1 } 128 p = p + 1 129 if buf[p] != (32 as u8) { return 0 - 1 } 130 p = p + 1 131 if buf[p] != (45 as u8) { return 0 - 1 } 132 p = p + 1 133 var k: i64 = 0 134 var kd: i64 = 0 135 while buf[p] >= (48 as u8) { 136 if buf[p] > (57 as u8) { kd = kd } 137 if buf[p] > (57 as u8) { p = p } 138 if buf[p] <= (57 as u8) { 139 k = k * 10 + ((buf[p] as i64) - 48) 140 kd = 1 141 p = p + 1 142 } 143 if buf[p] > (57 as u8) { kd = kd + 0 } 144 if buf[p] > (57 as u8) { tag = tag } 145 if buf[p] > (57 as u8) { regbuf[0] = tag } 146 if buf[p] > (57 as u8) { return 0 - 2 } 147 } 148 if kd == 0 { return 0 - 1 } 149 // expect "(%rbp)" 150 if c_match_at(buf, p, "(%rbp)" as *u8) == 0 { return 0 - 1 } 151 regbuf[0] = tag 152 return k 153} 154 155// scan a line for the spill-RELOAD form " movq -K(%rbp), %rR". 156// On match: writes reg-tag into regbuf[0] and returns slot K (>0). Else -1. 157func c_parse_reload(buf: *u8, off: i64, regbuf: *i64) -> i64 { 158 if c_match_at(buf, off, " movq -" as *u8) == 0 { return 0 - 1 } 159 var p: i64 = off + 10 160 var k: i64 = 0 161 var kd: i64 = 0 162 while buf[p] >= (48 as u8) { 163 if buf[p] <= (57 as u8) { 164 k = k * 10 + ((buf[p] as i64) - 48) 165 kd = 1 166 p = p + 1 167 } 168 if buf[p] > (57 as u8) { p = p } 169 if buf[p] > (57 as u8) { kd = kd } 170 if buf[p] > (57 as u8) { return 0 - 2 } 171 } 172 if kd == 0 { return 0 - 1 } 173 if c_match_at(buf, p, "(%rbp), %r" as *u8) == 0 { return 0 - 1 } 174 p = p + 10 175 var tag: i64 = 0 176 while buf[p] != (10 as u8) { 177 if buf[p] == (0 as u8) { p = p } 178 if buf[p] == (0 as u8) { return 0 - 1 } 179 tag = tag * 131 + (buf[p] as i64) 180 p = p + 1 181 } 182 regbuf[0] = tag 183 return k 184} 185 186// does slot -K(%rbp) appear anywhere in buf[from..to)? (any reference: store, reload, 187// address-form). Builds the needle "-K(%rbp)" and searches. Returns 1/0. 188func c_slot_used(buf: *u8, from: i64, to: i64, k: i64, needle: *u8) -> i64 { 189 // build needle = "-<k>(%rbp)" NUL-terminated 190 needle[0] = 45 as u8 // '-' 191 var tmp: *u8 = sys_mmap(28) 192 var m: i64 = k 193 var d: i64 = 0 194 if m == 0 { tmp[0] = 48; d = 1 } 195 while m > 0 { tmp[d] = (48 + (m % 10)) as u8; m = m / 10; d = d + 1 } 196 var w: i64 = 1 197 var z: i64 = 0 198 while z < d { needle[w] = tmp[d - 1 - z]; w = w + 1; z = z + 1 } 199 let tail: *u8 = "(%rbp)" as *u8 200 var tj: i64 = 0 201 while tail[tj] != (0 as u8) { needle[w] = tail[tj]; w = w + 1; tj = tj + 1 } 202 needle[w] = 0 as u8 203 var i: i64 = from 204 while i < to { 205 if c_match_at(buf, i, needle) == 1 { return 1 } 206 i = i + 1 207 } 208 return 0 209} 210 211// parse the constant C from " movabsq $C, ..." ; returns C, or the sentinel 212// 0x7fffffffffffffff if the line is not a movabsq. 213func c_parse_movabsq(buf: *u8, off: i64) -> i64 { 214 if c_match_at(buf, off, " movabsq $" as *u8) == 0 { return 0x7fffffffffffffff } 215 var p: i64 = off + 13 216 var neg: i64 = 0 217 if buf[p] == (45 as u8) { neg = 1; p = p + 1 } 218 var v: i64 = 0 219 var any: i64 = 0 220 while buf[p] >= (48 as u8) { 221 if buf[p] <= (57 as u8) { 222 v = v * 10 + ((buf[p] as i64) - 48) 223 any = 1 224 p = p + 1 225 } 226 if buf[p] > (57 as u8) { p = p } 227 if buf[p] > (57 as u8) { any = any } 228 if buf[p] > (57 as u8) { v = v } 229 if buf[p] > (57 as u8) { return v } 230 } 231 if any == 0 { return 0x7fffffffffffffff } 232 if neg == 1 { return 0 - v } 233 return v 234} 235 236func main() -> i64 { 237 c_puts("=== nx_codegen_defect_census (X-PERF-003c1; read-only census of SOVEREIGN fannkuch asm) ===\n" as *u8) 238 239 let envp: *i64 = sys_mmap(8*4) as *i64 240 envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64; envp[1] = 0 241 242 // -------- (1) regenerate the REAL asm via the sovereign compiler -------- 243 let cc: *u8 = "_offc/nx_cc_sovereign.elf" as *u8 244 let src: *u8 = "runtime/_hdl_build/nx_clbg_fannkuch.nx" as *u8 245 let asmp: *u8 = "/tmp/fk.s" as *u8 246 let afd: i64 = sys_openat_wr(asmp, C_MODE_RWX) 247 if afd < 0 { 248 c_puts("CENSUS verdict=RED reason=cannot-open-asm-out\n" as *u8) 249 sys_exit(1); return 1 250 } 251 let cargv: *i64 = sys_mmap(8*4) as *i64 252 cargv[0] = cc as i64; cargv[1] = src as i64; cargv[2] = 0 253 let crc: i64 = c_run(cc, cargv, envp, afd) 254 sys_close(afd) 255 if crc != 0 { 256 c_puts("CENSUS verdict=RED reason=sovereign-compile-nonzero rc=" as *u8); c_putn(crc); c_puts("\n" as *u8) 257 sys_exit(1); return 1 258 } 259 260 let buf: *u8 = sys_mmap(C_BUFSZ) 261 let blen: i64 = c_slurp(asmp, buf, C_BUFSZ) 262 c_puts(" emitted asm bytes=" as *u8); c_putn(blen); c_puts("\n" as *u8) 263 if blen <= 0 { 264 c_puts("CENSUS verdict=RED reason=empty-asm\n" as *u8) 265 sys_exit(1); return 1 266 } 267 268 // -------- (2) index lines + bracket the fannkuch_redux region -------- 269 let lstart: *i64 = sys_mmap(C_MAXLINES * 8) as *i64 270 let nl: i64 = c_index_lines(buf, blen, lstart) 271 272 var lo: i64 = 0 - 1 273 var hi: i64 = 0 - 1 274 var li: i64 = 0 275 while li < nl { 276 let off: i64 = lstart[li] 277 if lo < 0 { 278 if c_match_at(buf, off, "fannkuch_redux:" as *u8) == 1 { lo = li } 279 } 280 if lo >= 0 { 281 if hi < 0 { 282 if li > lo { 283 if c_match_at(buf, off, "fk_puts:" as *u8) == 1 { hi = li } 284 } 285 } 286 } 287 li = li + 1 288 } 289 if lo < 0 { 290 c_puts("CENSUS verdict=RED reason=fannkuch_redux-label-not-found\n" as *u8) 291 sys_exit(1); return 1 292 } 293 if hi < 0 { hi = nl } 294 let region_lines: i64 = hi - lo 295 let region_from: i64 = lstart[lo] 296 var region_to: i64 = blen 297 if hi < nl { region_to = lstart[hi] } 298 c_puts(" region fannkuch_redux:[line " as *u8); c_putn(lo) 299 c_puts("..fk_puts:line " as *u8); c_putn(hi) 300 c_puts("] = " as *u8); c_putn(region_lines); c_puts(" lines\n" as *u8) 301 302 // -------- tally the three defect classes over [lo, hi) -------- 303 let reg_a: *i64 = sys_mmap(8) as *i64 // store-reg tag out 304 let reg_b: *i64 = sys_mmap(8) as *i64 // reload-reg tag out 305 let needle: *u8 = sys_mmap(64) 306 let seen: *i64 = sys_mmap(C_MAXCONST * 8) as *i64 307 var nseen: i64 = 0 308 309 var store_reload: i64 = 0 310 var dead_spill: i64 = 0 311 var const_remat: i64 = 0 312 313 var x: i64 = lo 314 while x < hi { 315 let off: i64 = lstart[x] 316 317 // store-form classification 318 let sk: i64 = c_parse_store(buf, off, reg_a) 319 if sk > 0 { 320 let sreg: i64 = reg_a[0] 321 // (a) store-then-reload-same-slot within window 322 var matched: i64 = 0 323 var y: i64 = x + 1 324 var ylim: i64 = x + 1 + C_WIN 325 if ylim > hi { ylim = hi } 326 while y < ylim { 327 let rk: i64 = c_parse_reload(buf, lstart[y], reg_b) 328 if rk == sk { 329 if reg_b[0] == sreg { matched = 1 } 330 if reg_b[0] == sreg { y = ylim } 331 } 332 y = y + 1 333 } 334 if matched == 1 { store_reload = store_reload + 1 } 335 336 // (b) dead spill: slot sk never referenced again in [x+1, hi) 337 let nextoff: i64 = lstart[x + 1] 338 let used: i64 = c_slot_used(buf, nextoff, region_to, sk, needle) 339 if used == 0 { dead_spill = dead_spill + 1 } 340 } 341 342 // (c) constant rematerialization 343 let cv: i64 = c_parse_movabsq(buf, off) 344 if cv != 0x7fffffffffffffff { 345 var seenbefore: i64 = 0 346 var s: i64 = 0 347 while s < nseen { 348 if seen[s] == cv { seenbefore = 1 } 349 if seen[s] == cv { s = nseen } 350 s = s + 1 351 } 352 if seenbefore == 1 { const_remat = const_remat + 1 } 353 if seenbefore == 0 { 354 if nseen < C_MAXCONST { seen[nseen] = cv; nseen = nseen + 1 } 355 } 356 } 357 358 x = x + 1 359 } 360 361 let total_redundant: i64 = store_reload + dead_spill + const_remat 362 363 // -------- (3) name the dominant class + pin the origin module -------- 364 var dom_count: i64 = store_reload 365 let dclass: *u8 = "store_reload" as *u8 366 let dorigin: *u8 = "regalloc-home-everything" as *u8 367 var dom_sel: i64 = 0 // 0=store_reload 1=dead_spill 2=const_remat 368 if dead_spill > dom_count { dom_count = dead_spill; dom_sel = 1 } 369 if const_remat > dom_count { dom_count = const_remat; dom_sel = 2 } 370 371 c_puts(" store_reload=" as *u8); c_putn(store_reload) 372 c_puts(" dead_spill=" as *u8); c_putn(dead_spill) 373 c_puts(" const_remat=" as *u8); c_putn(const_remat) 374 c_puts(" total_redundant=" as *u8); c_putn(total_redundant); c_puts("\n" as *u8) 375 376 // -------- (4) emit the machine-parseable MEASURED line -------- 377 c_puts("CODEGENDEFECT target=fannkuch_hot total_redundant=" as *u8); c_putn(total_redundant) 378 c_puts(" store_reload=" as *u8); c_putn(store_reload) 379 c_puts(" dead_spill=" as *u8); c_putn(dead_spill) 380 c_puts(" const_remat=" as *u8); c_putn(const_remat) 381 c_puts(" dominant=" as *u8) 382 if dom_sel == 0 { c_puts("store_reload" as *u8) } 383 if dom_sel == 1 { c_puts("dead_spill" as *u8) } 384 if dom_sel == 2 { c_puts("const_remat" as *u8) } 385 c_puts(" count=" as *u8); c_putn(dom_count) 386 c_puts(" origin=" as *u8) 387 if dom_sel == 0 { c_puts("regalloc-home-everything" as *u8) } 388 if dom_sel == 1 { c_puts("regalloc-home-everything" as *u8) } 389 if dom_sel == 2 { c_puts("peephole-missing-in-emitter" as *u8) } 390 c_puts(" region_lines=" as *u8); c_putn(region_lines) 391 c_puts(" verdict=MEASURED\n" as *u8) 392 393 sys_exit(0) 394 return 0 395}