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}