nx_x86_regalloc.nx
buildroot/runtime/nx_x86_regalloc.nx
about
nx_x86_regalloc.nx -- genuine x86_64 register allocation (G1 keystone).
FRESH, x86_-prefixed, self-host-isolated: re-implements the proven IDEAS of
nx_regalloc.nx (Interval shape, def-to-last-use scan, mark_crosses_call,
ValueLoc lowering) with ZERO shared symbols and NO `import "nx_regalloc.nx"`,
because regalloc_function is on the live RISC-V self-host bootstrap host
(nx_nxc.nx:139, nx_main.nx:64) that compiles the x86 compiler -- re-binding a
shared name there would corrupt the host. See docs/NX_G1_X86_REGALLOC_PLAN.
ALLOCATE-not-COPY: a homed value LIVES in a callee-saved GPR for its whole
live range (producing op computes straight into it -- zero copy), unlike the
reverted K=1 cache (movq %reg,%rbx per result, +2018 insns -> net-negative).
Home pool = the 5 SysV callee-saved GPRs {r12,r13,r14,r15,rbx} (home idx
0..4) -- none used as scratch/operand/arg/clobber by the x86 backend, so they
survive every CALL/SYSCALL/TAIL_CALL/clone with no save-around-call logic.
FIX-12 INVARIANT: never add rcx/rdx/rbp/r10/r11 to this pool.
THIS IS STEP 1b: full interval analysis (build_intervals + mark_crosses_call
+ single_block) RUNS over every function -- crash-tested by the self-host
fixpoint over the whole corpus -- but its result is DISCARDED: every value
lowers to {VL_SPILLED,-1}, mask 0, so emitted code is byte-identical to the
pre-regalloc backend. Home selection + emit-path retarget land in STEP 2.
dependencies 2 imports · 2 importers
imports: nx_syscalls.nxnx_types.nx
imported by: nx_compile_x86.nxnx_x86_64_ctx.nx
structs
| 124 | struct X86Interval |
consts
| 29 | const X86_HOME_CAP: i64 = 5 // {r12,r13,r14,r15,rbx} |
| 46 | const X86_CALLER_POOL_ENABLE: i64 = 1 |
| 47 | const X86_ALLOW_CROSSBLOCK: i64 = 1 |
| 53 | const X86_CALLER_MIN_WCOST: i64 = 256 |
| 57 | const X86_NEGCTL_CALLER_IGNORE_CALL: i64 = 0 |
| 58 | const X86_CALLER_BASE: i64 = 5 |
| 59 | const X86_CALLER_CAP: i64 = 4 // idx 5,6,7,8 |
| 63 | const X86_CALLER_MIN_USES: i64 = 1 |
| 429 | const X86_NEGCTL_NO_BACKEDGE_EXT: i64 = 0 |
| 587 | const X86_HOME_CAP_ENABLE: i64 = 1 // ON: composes with opt_run for the measured crypto win |
| 588 | const X86_HOME_MIN_USES: i64 = 3 // require >= this many uses to beat save/restore |
| 1141 | const X86_NEGCTL_NONNEG_ALWAYS: i64 = 0 |
| 1221 | const X86_FWD_ENABLE: i64 = 1 |
| 1225 | const X86_NEGCTL_FWD_IGNORE_STORE: i64 = 0 |
| 1230 | const X86_NEGCTL_FWD_WRONG_HOME: i64 = 0 |
| 1247 | const X86_CHAIN_ENABLE: i64 = 1 |
| 1251 | const X86_NEGCTL_CHAIN_IGNORE_READ: i64 = 0 |
| 1256 | const X86_NEGCTL_CHAIN_SELFREF_OFF: i64 = 0 |
functions
| 73 | func x86_home_reg_name(idx: i64) -> *u8 |
| 94 | func x86_reg_eq(a: *u8, b: *u8) -> i64 |
| 107 | func x86_home_save_off(slot_index: i64) -> i64 |
| 111 | func x86_popcount(mask: i64) -> i64 called by 1: x86ctx_init |
| 135 | func x86_intv_at(buf: *X86Interval, id: i64) -> *X86Interval |
| 141 | func x86_val_at(f: *Function, id: i64) -> *Value |
| 145 | func x86_block_at(f: *Function, id: i64) -> *BasicBlock |
| 151 | func x86_operand_k(inst: *Instr, k: i64) -> i64 |
| 182 | func x86_n_value_operands(inst: *Instr) -> i64 |
| 193 | func x86_is_call_class(op: i64) -> i64 |
| 202 | func x86_touch_bb(first_bb: *i64, last_bb: *i64, v: i64, bi: i64) -> i64 called by 1: x86_build_intervals |
| 218 | func x86_compute_loop_depth(f: *Function, depth: *i64) -> i64 |
| 248 | func x86_weight_for_depth(d: i64) -> i64 called by 1: x86_compute_wcost |
| 256 | func x86_compute_wcost(f: *Function, depth: *i64, wcost: *i64) -> i64 called by 1: x86_regalloc_function calls 4: x86_weight_for_depthx86_block_atx86_n_value_operandsx86_operand_k |
| 283 | func x86_build_intervals(f: *Function, intv: *X86Interval, |
| 431 | func x86_extend_backedge_intervals(f: *Function, intv: *X86Interval, |
| 471 | func x86_mark_crosses_call(intv: *X86Interval, n_values: i64, |
| 492 | func x86_is_pure_rax_binop(op: i64) -> i64 |
| 505 | func x86_is_homeable(f: *Function, intv: *X86Interval, alloca_off: *i64, |
| 540 | func x86_op_clobbers_caller_saved(op: i64) -> i64 called by 1: x86_fn_has_clobber_intrinsic |
| 561 | func x86_fn_has_clobber_intrinsic(f: *Function) -> i64 |
| 595 | func x86_select_homes(f: *Function, intv: *X86Interval, alloca_off: *i64, |
| 705 | func x86_ah_value_consume_ok(op: i64) -> i64 called by 1: x86_ah_scan |
| 738 | func x86_ah_base_ok(f: *Function, v: i64) -> i64 |
| 753 | func x86_ah_ldst_sz8(inst: *Instr) -> i64 called by 1: x86_ah_scan |
| 763 | func x86_ah_scan(f: *Function, alloca_off: *i64, elig: *i64, cnt: *i64) -> i64 |
| 806 | func x86_ah_select(f: *Function, elig: *i64, cnt: *i64, |
| 862 | func x86_g4_is_binop(op: i64) -> i64 called by 1: x86_g4_pos_ok |
| 878 | func x86_g4_is_cmp(op: i64) -> i64 called by 1: x86_g4_pos_ok |
| 890 | func x86_chain_op_commutative(op: i64) -> i64 |
| 904 | func x86_g4_producer_ok(op: i64) -> i64 called by 1: x86_g4_elide_scan |
| 929 | func x86_g4_pos_ok(jop: i64, k: i64, jres_homed: i64) -> i64 |
| 956 | func x86_g4_elide_scan(f: *Function, locs: *ValueLoc, alloca_off: *i64, |
| 1039 | func x86_g5_imm32_ok(v: i64) -> i64 |
| 1045 | func x86_g5_select_const_homes(f: *Function, intv: *X86Interval, called by 1: x86_regalloc_function calls 5: sys_mmapx86_block_atx86_is_pure_rax_binopx86_val_atx86_g5_imm32_ok |
| 1143 | func x86_const_ge(f: *Function, v: i64, lo: i64) -> i64 |
| 1152 | func x86_val_nonneg(f: *Function, v: i64, depth: i64) -> i64 |
| 1260 | func x86_chain_op_ok(op: i64) -> i64 called by 1: x86_chain_scan |
| 1278 | func x86_chain_scan(f: *Function, alloca_off: *i64, alloca_home: *i64, |
| 1430 | func x86_fwd_const_in(f: *Function, u: i64, a: i64, b: i64, c2: i64, d: i64) -> i64 |
| 1447 | func x86_fwd_is_sibish(f: *Function, u: i64) -> i64 |
| 1473 | func x86_fwd_consumer_ok(f: *Function, J: *Instr, k: i64) -> i64 |
| 1525 | func x86_fwd_scan(f: *Function, alloca_off: *i64, alloca_home: *i64, |
| 1608 | func x86_select_all(f: *Function, intv: *X86Interval, alloca_off: *i64, |
| 1733 | func x86_regalloc_function(f: *Function, alloca_off: *i64, |