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}