code wiki / (root) / regalloc_fpr_evict_test.nx

regalloc_fpr_evict_test.nx source

↩ module page · 78 lines · 2804 B

1// regalloc_fpr_evict_test.nx -- proves linear_scan_fpr's eviction 2// policy fires. Companion smoke to regalloc_evict_test.nx. 3// 4// No public ir_const_f64 / ir_emit_fcast builders exist yet, so we 5// construct Interval entries directly (linear_scan_fpr is leaf- 6// callable: it takes intv + sorted_ids + n + mask + spill_start 7// without touching the Function pointer). The 22-interval workload 8// matches the FPR pool size of 21 (9 caller-clobbered ft-regs after 9// the 3 scratch exclusions + 12 callee-saved fs-regs). 10// 11// Construction: intv[i].end is monotonically decreasing in i, so 12// intv[0] has the LATEST end and intv[21] has the EARLIEST. All 13// crosses_call=0 so the want_cs=0 path is exercised. When intv[21] 14// arrives and the pool is empty, the eviction policy walks active[] 15// backward and finds intv[0] (latest end, in an ft-reg). Since 16// intv[0].end > intv[21].end, evict intv[0]; intv[21] gets that 17// register. 18// 19// Assertion: 20// intv[0].reg == -1 (spilled by eviction) 21// intv[0].slot >= 0 (spill slot assigned) 22// intv[21].reg >= FREG_BASE_T (got a float register) 23 24import "nx_syscalls.nx" 25import "nx_types.nx" 26import "nx_regalloc.nx" 27 28const N_FLOATS: i64 = 22 // 21 reg pool + 1 forces exactly 1 spill 29 30func main() -> i64 { 31 let intv_raw: *u8 = sys_mmap(N_FLOATS * 48 + 16) 32 let intv: *Interval = intv_raw as *Interval 33 34 var i: i64 = 0 35 while i < N_FLOATS { 36 let iv: *Interval = intv_at(intv, i) 37 iv.v = i 38 iv.start = i + 1 39 iv.end = 50 - i 40 iv.reg = -1 41 iv.slot = -1 42 iv.crosses_call = 0 43 i = i + 1 44 } 45 46 // Force intv[21] to have an EARLIER end than every active by the 47 // time it arrives. expire(cur_start=22) sees intv[k].end for 48 // k=0..20 ranges 50..30 -- all >= 22, so nothing expires. 49 let iv_last: *Interval = intv_at(intv, N_FLOATS - 1) 50 iv_last.end = 23 51 52 let ids_raw: *u8 = sys_mmap(N_FLOATS * 8 + 16) 53 let ids: *i64 = ids_raw as *i64 54 i = 0 55 while i < N_FLOATS { 56 ids[i] = i 57 i = i + 1 58 } 59 sort_by_start(ids, N_FLOATS, intv) 60 61 let mask_raw: *u8 = sys_mmap(16) 62 let mask_fpr: *i64 = mask_raw as *i64 63 *mask_fpr = 0 64 65 let spill_end: i64 = linear_scan_fpr(intv, ids, N_FLOATS, mask_fpr, 0) 66 67 if spill_end < 8 { return 10 } // at least one slot 68 if spill_end > 24 { return 11 } // shouldn't over-spill 69 70 let iv0: *Interval = intv_at(intv, 0) 71 let iv21: *Interval = intv_at(intv, N_FLOATS - 1) 72 73 if iv0.reg != -1 { return 20 } // evicted -> reg cleared 74 if iv0.slot < 0 { return 21 } // slot assigned 75 if iv21.reg < FREG_BASE_T { return 22 } // latecomer got float reg 76 77 return 0 78}