code wiki / _hdl_build / nx_x86emit.nx

nx_x86emit.nx

buildroot/runtime/_hdl_build/nx_x86emit.nx

10281 B140 linesdepth 2pulls 2 transitivereach 61 importersview sourcekind library
docsdependenciesstructsconstsfunctions

about

nx_x86emit.nx -- SOVEREIGN x86-64 MACHINE-CODE EMITTER (P5 baseline-JIT foundation; SOTA ladder). The keystone (nx_js_jit_keystone) proved runtime EMISSION+EXECUTION works with hand-hex. A template JIT needs to emit code PROGRAMMATICALLY, so this is the assembler: one function per instruction form the Sparkplug-tier compiler will template, each producing exact x86-64 bytes into a code buffer. Verified end-to-end by nx_x86emit_gate (emits functions through THIS api, executes them, checks results) -- cardinal rule 2: verify the primitive before building the JIT on it. Conventions: REX.W (64-bit) on everything. Register numbers = hardware encoding (RAX=0..R15=15). Memory base MUST NOT be RSP/R12 (low3==100 forces a SIB the callers here never need); the JIT uses RBX (stack base) + R14 (env base), both SIB-free. load_idx/store_idx emit SIB for [base+index+disp8]. Wide immediates + rel patches are written byte-by-byte with a VARIABLE shift (nx_cc blanks the .s on an IMMEDIATE shift count >31 -- reference-gotcha; i*8 is a register shift, legal for 0..63). license_tier: ORIGINAL

dependencies 1 imports · 2 importers

nx_syscalls.nx nx_x86emit.nx nx_js_vm.nx nx_x86emit_gate.nx

imports: nx_syscalls.nx

imported by: nx_js_vm.nxnx_x86emit_gate.nx

structs

none

consts

17const RAX: i64 = 0
18const RCX: i64 = 1
19const RDX: i64 = 2
20const RBX: i64 = 3
21const RSP: i64 = 4
22const RBP: i64 = 5
23const RSI: i64 = 6
24const RDI: i64 = 7
25const R8: i64 = 8
26const R9: i64 = 9
27const R10: i64 = 10
28const R11: i64 = 11
29const R12: i64 = 12
30const R13: i64 = 13
31const R14: i64 = 14
32const R15: i64 = 15
35const CC_E: i64 = 0x84
36const CC_NE: i64 = 0x85
37const CC_B: i64 = 0x82
38const CC_AE: i64 = 0x83
39const CC_L: i64 = 0x8C
40const CC_GE: i64 = 0x8D
41const CC_LE: i64 = 0x8E
42const CC_G: i64 = 0x8F
43const SET_E: i64 = 0x94
44const SET_NE: i64 = 0x95
45const SET_L: i64 = 0x9C
46const SET_GE: i64 = 0x9D
47const SET_LE: i64 = 0x9E
48const SET_G: i64 = 0x9F

functions

50func xe1(cb: *u8, pb: *i64, b: i64) -> i64 { let p: i64 = pb[0]; cb[p] = (b & 0xff) as u8; pb[0] = p + 1; return 0 }
51func xe_u32(cb: *u8, pb: *i64, v: i64) -> i64 { var i: i64 = 0; while i < 4 { let sh: i64 = i * 8; xe1(cb, pb, (v >> sh) & 0xff); i = i + 1 } return 0 }
52func xe_u64(cb: *u8, pb: *i64, v: i64) -> i64 { var i: i64 = 0; while i < 8 { let sh: i64 = i * 8; xe1(cb, pb, (v >> sh) & 0xff); i = i + 1 } return 0 }
called by 1: xe_mov_ri64 calls 1: xe1
53func xhi(r: i64) -> i64 { if r >= 8 { return 1 } return 0 }
54func xlo(r: i64) -> i64 { return r & 7 }
55func xe_rex(cb: *u8, pb: *i64, w: i64, reg: i64, idx: i64, base: i64) -> i64 { let by: i64 = 0x40 | (w << 3) | (xhi(reg) << 2) | (xhi(idx) << 1) | xhi(base); xe1(cb, pb, by); return 0 }
56func xe_modrm(cb: *u8, pb: *i64, mod: i64, reg: i64, rm: i64) -> i64 { xe1(cb, pb, (mod << 6) | (xlo(reg) << 3) | xlo(rm)); return 0 }
57func xe_sib(cb: *u8, pb: *i64, scale: i64, index: i64, base: i64) -> i64 { xe1(cb, pb, (scale << 6) | (xlo(index) << 3) | xlo(base)); return 0 }
60func xe_mov_rr(cb: *u8, pb: *i64, dst: i64, src: i64) -> i64 { xe_rex(cb, pb, 1, src, 0, dst); xe1(cb, pb, 0x89); xe_modrm(cb, pb, 3, src, dst); return 0 }
62func xe_mov_ri32(cb: *u8, pb: *i64, dst: i64, imm: i64) -> i64 { xe_rex(cb, pb, 1, 0, 0, dst); xe1(cb, pb, 0xC7); xe_modrm(cb, pb, 3, 0, dst); xe_u32(cb, pb, imm); return 0 }
64func xe_mov_ri64(cb: *u8, pb: *i64, dst: i64, imm: i64) -> i64 { xe_rex(cb, pb, 1, 0, 0, dst); xe1(cb, pb, 0xB8 | xlo(dst)); xe_u64(cb, pb, imm); return 0 }
66func xe_load(cb: *u8, pb: *i64, dst: i64, base: i64, disp: i64) -> i64
75func xe_store(cb: *u8, pb: *i64, base: i64, disp: i64, src: i64) -> i64
84func xe_load_idx(cb: *u8, pb: *i64, dst: i64, base: i64, index: i64, disp8: i64) -> i64
93func xe_store_idx(cb: *u8, pb: *i64, base: i64, index: i64, disp8: i64, src: i64) -> i64
102func xe_add_rr(cb: *u8, pb: *i64, dst: i64, src: i64) -> i64 { xe_rex(cb, pb, 1, src, 0, dst); xe1(cb, pb, 0x01); xe_modrm(cb, pb, 3, src, dst); return 0 }
103func xe_sub_rr(cb: *u8, pb: *i64, dst: i64, src: i64) -> i64 { xe_rex(cb, pb, 1, src, 0, dst); xe1(cb, pb, 0x29); xe_modrm(cb, pb, 3, src, dst); return 0 }
104func xe_cmp_rr(cb: *u8, pb: *i64, a: i64, b: i64) -> i64 { xe_rex(cb, pb, 1, b, 0, a); xe1(cb, pb, 0x39); xe_modrm(cb, pb, 3, b, a); return 0 }
106func xe_imul_rr(cb: *u8, pb: *i64, dst: i64, src: i64) -> i64 { xe_rex(cb, pb, 1, dst, 0, src); xe1(cb, pb, 0x0F); xe1(cb, pb, 0xAF); xe_modrm(cb, pb, 3, dst, src); return 0 }
109func xe_movq_xr(cb: *u8, pb: *i64, xmm: i64, gpr: i64) -> i64 { xe1(cb, pb, 0x66); xe_rex(cb, pb, 1, xmm, 0, gpr); xe1(cb, pb, 0x0F); xe1(cb, pb, 0x6E); xe_modrm(cb, pb, 3, xmm, gpr); return 0 } // movq xmm,r64
called by 1: jit_float_operand calls 3: xe1xe_rexxe_modrm
110func xe_movq_rx(cb: *u8, pb: *i64, gpr: i64, xmm: i64) -> i64 { xe1(cb, pb, 0x66); xe_rex(cb, pb, 1, xmm, 0, gpr); xe1(cb, pb, 0x0F); xe1(cb, pb, 0x7E); xe_modrm(cb, pb, 3, xmm, gpr); return 0 } // movq r64,xmm
111func xe_sse_arith(cb: *u8, pb: *i64, opc: i64, xd: i64, xs: i64) -> i64 { xe1(cb, pb, 0xF2); xe1(cb, pb, 0x0F); xe1(cb, pb, opc); xe_modrm(cb, pb, 3, xd, xs); return 0 } // <op>sd xd,xs (add58 sub5C mul59 div5E)
112func xe_cvtsi2sd(cb: *u8, pb: *i64, xmm: i64, gpr: i64) -> i64 { xe1(cb, pb, 0xF2); xe_rex(cb, pb, 1, xmm, 0, gpr); xe1(cb, pb, 0x0F); xe1(cb, pb, 0x2A); xe_modrm(cb, pb, 3, xmm, gpr); return 0 } // cvtsi2sd xmm,r64 (int->double)
called by 1: jit_float_operand calls 3: xe1xe_rexxe_modrm
114func xe_cqo(cb: *u8, pb: *i64) -> i64 { xe1(cb, pb, 0x48); xe1(cb, pb, 0x99); return 0 }
115func xe_idiv(cb: *u8, pb: *i64, src: i64) -> i64 { xe_rex(cb, pb, 1, 0, 0, src); xe1(cb, pb, 0xF7); xe_modrm(cb, pb, 3, 7, src); return 0 }
116func xe_inc(cb: *u8, pb: *i64, dst: i64) -> i64 { xe_rex(cb, pb, 1, 0, 0, dst); xe1(cb, pb, 0xFF); xe_modrm(cb, pb, 3, 0, dst); return 0 }
called by 1: main calls 3: xe_rexxe1xe_modrm
117func xe_add_ri32(cb: *u8, pb: *i64, dst: i64, imm: i64) -> i64 { xe_rex(cb, pb, 1, 0, 0, dst); xe1(cb, pb, 0x81); xe_modrm(cb, pb, 3, 0, dst); xe_u32(cb, pb, imm); return 0 }
118func xe_sub_ri32(cb: *u8, pb: *i64, dst: i64, imm: i64) -> i64 { xe_rex(cb, pb, 1, 0, 0, dst); xe1(cb, pb, 0x81); xe_modrm(cb, pb, 3, 5, dst); xe_u32(cb, pb, imm); return 0 }
119func xe_cmp_ri32(cb: *u8, pb: *i64, dst: i64, imm: i64) -> i64 { xe_rex(cb, pb, 1, 0, 0, dst); xe1(cb, pb, 0x81); xe_modrm(cb, pb, 3, 7, dst); xe_u32(cb, pb, imm); return 0 }
120func xe_shl_imm(cb: *u8, pb: *i64, dst: i64, cnt: i64) -> i64 { xe_rex(cb, pb, 1, 0, 0, dst); xe1(cb, pb, 0xC1); xe_modrm(cb, pb, 3, 4, dst); xe1(cb, pb, cnt & 0xff); return 0 }
121func xe_shr_imm(cb: *u8, pb: *i64, dst: i64, cnt: i64) -> i64 { xe_rex(cb, pb, 1, 0, 0, dst); xe1(cb, pb, 0xC1); xe_modrm(cb, pb, 3, 5, dst); xe1(cb, pb, cnt & 0xff); return 0 }
122func xe_sar_imm(cb: *u8, pb: *i64, dst: i64, cnt: i64) -> i64 { xe_rex(cb, pb, 1, 0, 0, dst); xe1(cb, pb, 0xC1); xe_modrm(cb, pb, 3, 7, dst); xe1(cb, pb, cnt & 0xff); return 0 } // arithmetic shift right (sign-fill)
124func xe_imul1(cb: *u8, pb: *i64, src: i64) -> i64 { xe_rex(cb, pb, 1, 0, 0, src); xe1(cb, pb, 0xF7); xe_modrm(cb, pb, 3, 5, src); return 0 }
126func xe_setcc(cb: *u8, pb: *i64, cc: i64, dst: i64) -> i64 { xe1(cb, pb, 0x40 | xhi(dst)); xe1(cb, pb, 0x0F); xe1(cb, pb, cc); xe_modrm(cb, pb, 3, 0, dst); return 0 }
127func xe_movzx_rb(cb: *u8, pb: *i64, dst: i64, src: i64) -> i64 { xe_rex(cb, pb, 1, dst, 0, src); xe1(cb, pb, 0x0F); xe1(cb, pb, 0xB6); xe_modrm(cb, pb, 3, dst, src); return 0 }
129func xe_jmp(cb: *u8, pb: *i64) -> i64 { xe1(cb, pb, 0xE9); let at: i64 = pb[0]; xe_u32(cb, pb, 0); return at }
130func xe_jcc(cb: *u8, pb: *i64, cc: i64) -> i64 { xe1(cb, pb, 0x0F); xe1(cb, pb, cc); let at: i64 = pb[0]; xe_u32(cb, pb, 0); return at }
132func xe_patch(cb: *u8, at: i64, target: i64) -> i64 { let rel: i64 = target - (at + 4); var i: i64 = 0; while i < 4 { let sh: i64 = i * 8; cb[at + i] = ((rel >> sh) & 0xff) as u8; i = i + 1 } return 0 }
134func xe_call_reg(cb: *u8, pb: *i64, reg: i64) -> i64 { if xhi(reg) == 1 { xe1(cb, pb, 0x41) } xe1(cb, pb, 0xFF); xe_modrm(cb, pb, 3, 2, reg); return 0 }
135func xe_push(cb: *u8, pb: *i64, reg: i64) -> i64 { if xhi(reg) == 1 { xe1(cb, pb, 0x41) } xe1(cb, pb, 0x50 | xlo(reg)); return 0 }
136func xe_pop(cb: *u8, pb: *i64, reg: i64) -> i64 { if xhi(reg) == 1 { xe1(cb, pb, 0x41) } xe1(cb, pb, 0x58 | xlo(reg)); return 0 }
137func xe_ret(cb: *u8, pb: *i64) -> i64 { xe1(cb, pb, 0xC3); return 0 }
140func xe_mmap_rwx(size: i64) -> *u8 { let r: i64 = __syscall(SYS_MMAP, 0, size, 7, 0x22, -1, 0); return r as *u8 }