code wiki / _hdl_build / nx_rv64_jit.nx
nx_rv64_jit.nx
buildroot/runtime/_hdl_build/nx_rv64_jit.nx
about
nx_rv64_jit.nx -- a SOVEREIGN RV64 -> x86-64 JIT (dynamic binary translation): the SOTA emulator technique, above
the decode-cache interpreter. It TRANSLATES a basic block of predecoded RV64 ops into NATIVE x86-64 machine code
(per-instruction, not a shape template): the 32 RV64 registers live in a caller-provided i64 array (base in rdi per
SysV); each RV64 instruction emits x86 that loads operands from reg[], computes in rax, stores back; a backward
branch emits a NATIVE conditional jump so a loop runs entirely in host code. The block is mmap'd RWX and CALLED
(the RWX + cast-fn-ptr primitive is proven by nx_nxe_loader). Equivalence with the golden behavioral sim is proven
by nx_rv64_jit_gate; the speedup is measured there. Subset: LUI/ADDI/ADD/SUB/ANDI/ORI/SLLI + BEQ/BNE/BLT/BGE
(backward branches). license_tier: ORIGINAL
dependencies 2 imports · 17 importers
diagram shows first 10 each side; +0 more imports, +7 more importers in the complete lists below.
imports: nx_syscalls.nxnx_rv64_fast.nx
imported by: nx_hwtest_matrix.nxnx_jit_ra_probe.nxnx_rv64_cjit_gate.nxnx_rv64_ctier_gate.nxnx_rv64_difftest.nxnx_rv64_jit_fwd_gate.nxnx_rv64_jit_gate.nxnx_rv64_jit_mem_gate.nxnx_rv64_jit_ra_gate.nxnx_rv64_jit_w_gate.nxnx_rv64_m_gate.nxnx_rv64_mulh_gate.nxnx_rv64_realc_gate.nxnx_rv64_run_bin_tier.nxnx_rv64_tier.nxnx_rv64_tier_gate.nxnx_rv64_toolchain_gate.nx
structs
| none |
consts
| none |
functions
| 12 | func j_b(out: *u8, o: i64, v: i64) -> i64 { out[o]=(v&0xff) as u8; return o+1 } |
| 13 | func j_w32(out: *u8, o: i64, v: i64) -> i64 { out[o]=(v&0xff) as u8; out[o+1]=((v>>8)&0xff) as u8; out[o+2]=((v>>16)&0xff) as u8; out[o+3]=((v>>24)&0xff) as u8; return o+4 } |
| 15 | func e_load(out: *u8, o: i64, ri: i64) -> i64 { var p: i64=o; p=j_b(out,p,0x48); p=j_b(out,p,0x8B); p=j_b(out,p,0x87); p=j_w32(out,p,ri*8); return p } // mov rax,[rdi+ri*8] |
| 16 | func e_store(out: *u8, o: i64, ri: i64) -> i64 { var p: i64=o; p=j_b(out,p,0x48); p=j_b(out,p,0x89); p=j_b(out,p,0x87); p=j_w32(out,p,ri*8); return p } // mov [rdi+ri*8],rax |
| 17 | func e_movimm(out: *u8, o: i64, imm: i64) -> i64 { var p: i64=o; p=j_b(out,p,0x48); p=j_b(out,p,0xC7); p=j_b(out,p,0xC0); p=j_w32(out,p,imm); return p } // mov rax,imm32(sx) |
| 18 | func e_addimm(out: *u8, o: i64, imm: i64) -> i64 { var p: i64=o; p=j_b(out,p,0x48); p=j_b(out,p,0x05); p=j_w32(out,p,imm); return p } // add rax,imm32 |
| 19 | func e_andimm(out: *u8, o: i64, imm: i64) -> i64 { var p: i64=o; p=j_b(out,p,0x48); p=j_b(out,p,0x25); p=j_w32(out,p,imm); return p } // and rax,imm32 |
| 20 | func e_orimm(out: *u8, o: i64, imm: i64) -> i64 { var p: i64=o; p=j_b(out,p,0x48); p=j_b(out,p,0x0D); p=j_w32(out,p,imm); return p } // or rax,imm32 |
| 21 | func e_opreg(out: *u8, o: i64, opc: i64, ri: i64) -> i64 { var p: i64=o; p=j_b(out,p,0x48); p=j_b(out,p,opc); p=j_b(out,p,0x87); p=j_w32(out,p,ri*8); return p } // <op> rax,[rdi+ri*8] |
| 22 | func e_imul_mem(out: *u8, o: i64, ri: i64) -> i64 { var p: i64=o; p=j_b(out,p,0x48); p=j_b(out,p,0x0F); p=j_b(out,p,0xAF); p=j_b(out,p,0x87); p=j_w32(out,p,ri*8); return p } // imul rax,[rdi+ri*8] |
| 23 | func e_mulhi_u(out: *u8, o: i64, ri: i64) -> i64 { var p: i64=o; p=j_b(out,p,0x48); p=j_b(out,p,0xF7); p=j_b(out,p,0xA7); p=j_w32(out,p,ri*8); return p } // mul qword[rdi+ri*8] -> rdx:rax (unsigned) |
| 24 | func e_mulhi_s(out: *u8, o: i64, ri: i64) -> i64 { var p: i64=o; p=j_b(out,p,0x48); p=j_b(out,p,0xF7); p=j_b(out,p,0xAF); p=j_w32(out,p,ri*8); return p } // imul qword[rdi+ri*8] -> rdx:rax (signed) |
| 25 | func e_mov_rax_rdx(out: *u8, o: i64) -> i64 { var p: i64=o; p=j_b(out,p,0x48); p=j_b(out,p,0x89); p=j_b(out,p,0xD0); return p } // mov rax,rdx (grab the high half) |
| 26 | func e_shl(out: *u8, o: i64, sh: i64) -> i64 { var p: i64=o; p=j_b(out,p,0x48); p=j_b(out,p,0xC1); p=j_b(out,p,0xE0); p=j_b(out,p,sh); return p } // shl rax,imm8 |
| 27 | func e_jcc(out: *u8, o: i64, cc: i64, rel: i64) -> i64 { var p: i64=o; p=j_b(out,p,0x0F); p=j_b(out,p,cc); p=j_w32(out,p,rel); return p } // jcc rel32 |
| 30 | func e_load32(out: *u8, o: i64, ri: i64) -> i64 { var p: i64=o; p=j_b(out,p,0x8B); p=j_b(out,p,0x87); p=j_w32(out,p,ri*8); return p } // mov eax,[rdi+ri*8] |
| 31 | func e_op32_mem(out: *u8, o: i64, opc: i64, ri: i64) -> i64 { var p: i64=o; p=j_b(out,p,opc); p=j_b(out,p,0x87); p=j_w32(out,p,ri*8); return p } // <op> eax,[rdi+ri*8] (03 add / 2B sub) |
| 32 | func e_imul32_mem(out: *u8, o: i64, ri: i64) -> i64 { var p: i64=o; p=j_b(out,p,0x0F); p=j_b(out,p,0xAF); p=j_b(out,p,0x87); p=j_w32(out,p,ri*8); return p } // imul eax,[rdi+ri*8] |
| 33 | func e_addimm32(out: *u8, o: i64, imm: i64) -> i64 { var p: i64=o; p=j_b(out,p,0x05); p=j_w32(out,p,imm); return p } // add eax,imm32 |
| 34 | func e_shl32(out: *u8, o: i64, sh: i64) -> i64 { var p: i64=o; p=j_b(out,p,0xC1); p=j_b(out,p,0xE0); p=j_b(out,p,sh); return p } // shl eax,imm8 |
| 35 | func e_shr32(out: *u8, o: i64, sh: i64) -> i64 { var p: i64=o; p=j_b(out,p,0xC1); p=j_b(out,p,0xE8); p=j_b(out,p,sh); return p } // shr eax,imm8 |
| 36 | func e_sar32(out: *u8, o: i64, sh: i64) -> i64 { var p: i64=o; p=j_b(out,p,0xC1); p=j_b(out,p,0xF8); p=j_b(out,p,sh); return p } // sar eax,imm8 |
| 37 | func e_movsxd(out: *u8, o: i64) -> i64 { var p: i64=o; p=j_b(out,p,0x48); p=j_b(out,p,0x63); p=j_b(out,p,0xC0); return p } // movsxd rax,eax (sext32->64) |
| 38 | func e_ret(out: *u8, o: i64) -> i64 { return j_b(out,o,0xC3) } |
| 39 | func jit_mmap_rwx(size: i64) -> *u8 { let r: i64 = __syscall(SYS_MMAP, 0, size, 7, 0x22, -1, 0); return r as *u8 } |
| 40 | func j_w64(out: *u8, o: i64, v: i64) -> i64 { var i: i64=0; while i<8 { out[o+i]=((v>>(i*8))&0xff) as u8; i=i+1 } return o+8 } called by 1: e_movimm64_rsi |
| 44 | func e_movimm64_rsi(out: *u8, o: i64, imm: i64) -> i64 { var p: i64=o; p=j_b(out,p,0x48); p=j_b(out,p,0xBE); p=j_w64(out,p,imm); return p } // mov rsi, imm64 |
| 45 | func e_ld_rdx(out: *u8, o: i64, ri: i64) -> i64 { var p: i64=o; p=j_b(out,p,0x48); p=j_b(out,p,0x8B); p=j_b(out,p,0x97); p=j_w32(out,p,ri*8); return p } // mov rdx,[rdi+ri*8] |
| 46 | func e_lw_mem(out: *u8, o: i64) -> i64 { var p: i64=o; p=j_b(out,p,0x48); p=j_b(out,p,0x63); p=j_b(out,p,0x04); p=j_b(out,p,0x06); return p } // movsxd rax,dword[rsi+rax] |
| 47 | func e_ld_mem(out: *u8, o: i64) -> i64 { var p: i64=o; p=j_b(out,p,0x48); p=j_b(out,p,0x8B); p=j_b(out,p,0x04); p=j_b(out,p,0x06); return p } // mov rax,[rsi+rax] |
| 48 | func e_sw_mem(out: *u8, o: i64) -> i64 { var p: i64=o; p=j_b(out,p,0x89); p=j_b(out,p,0x14); p=j_b(out,p,0x06); return p } // mov [rsi+rax],edx (store 32) |
| 49 | func e_sd_mem(out: *u8, o: i64) -> i64 { var p: i64=o; p=j_b(out,p,0x48); p=j_b(out,p,0x89); p=j_b(out,p,0x14); p=j_b(out,p,0x06); return p } // mov [rsi+rax],rdx (store 64) |
| 50 | func e_shr(out: *u8, o: i64, sh: i64) -> i64 { var p: i64=o; p=j_b(out,p,0x48); p=j_b(out,p,0xC1); p=j_b(out,p,0xE8); p=j_b(out,p,sh); return p } // shr rax,imm8 (SRLI) |
| 51 | func e_sar(out: *u8, o: i64, sh: i64) -> i64 { var p: i64=o; p=j_b(out,p,0x48); p=j_b(out,p,0xC1); p=j_b(out,p,0xF8); p=j_b(out,p,sh); return p } // sar rax,imm8 (SRAI) |
| 56 | func jit_set_membase(v: i64, membytes: i64) -> i64 { jit_membase = v; jit_membytes = membytes; return 0 } |
| 61 | func e_bcheck(out: *u8, o: i64, width: i64) -> i64 |
| 71 | func jit_compile(opk: *i64, rd: *i64, rs1: *i64, rs2: *i64, imm: *i64, nidx: i64, out: *u8, x86off: *i64) -> i64 |
| 135 | func jit_run(x86: *u8, len: i64, reg: *i64) -> i64 |
| 150 | func ra_pool(s: i64) -> i64 { if s==0 { return 1 } if s==1 { return 2 } return 6 } // rcx, rdx, rsi |
| 151 | func era_fill(out: *u8, o: i64, preg: i64, disp: i64) -> i64 { var p: i64=o; p=j_b(out,p,0x48); p=j_b(out,p,0x8B); p=j_b(out,p,0x87|(preg<<3)); p=j_w32(out,p,disp); return p } // mov preg,[rdi+disp] |
| 152 | func era_spill(out: *u8, o: i64, preg: i64, disp: i64) -> i64 { var p: i64=o; p=j_b(out,p,0x48); p=j_b(out,p,0x89); p=j_b(out,p,0x87|(preg<<3)); p=j_w32(out,p,disp); return p } // mov [rdi+disp],preg |
| 153 | func era_mov_rr(out: *u8, o: i64, dst: i64, src: i64) -> i64 { var p: i64=o; p=j_b(out,p,0x48); p=j_b(out,p,0x8B); p=j_b(out,p,0xC0|(dst<<3)|src); return p } // mov dst,src |
| 154 | func era_alu_rr(out: *u8, o: i64, opc: i64, dst: i64, src: i64) -> i64 { var p: i64=o; p=j_b(out,p,0x48); p=j_b(out,p,opc); p=j_b(out,p,0xC0|(dst<<3)|src); return p } // <op> dst,src (03/2B/23/0B/3B) |
| 155 | func era_alu_ri(out: *u8, o: i64, slash: i64, dst: i64, imm: i64) -> i64 { var p: i64=o; p=j_b(out,p,0x48); p=j_b(out,p,0x81); p=j_b(out,p,0xC0|(slash<<3)|dst); p=j_w32(out,p,imm); return p } // add(/0)/or(/1)/and(/4) dst,imm32 |
| 156 | func era_shl_ri(out: *u8, o: i64, dst: i64, sh: i64) -> i64 { var p: i64=o; p=j_b(out,p,0x48); p=j_b(out,p,0xC1); p=j_b(out,p,0xE0|dst); p=j_b(out,p,sh); return p } // shl dst,imm8 |
| 157 | func era_mov_ri(out: *u8, o: i64, dst: i64, imm: i64) -> i64 { var p: i64=o; p=j_b(out,p,0x48); p=j_b(out,p,0xC7); p=j_b(out,p,0xC0|dst); p=j_w32(out,p,imm); return p } // mov dst,imm32(sx) |
| 158 | func era_jcc(out: *u8, o: i64, cc: i64, rel: i64) -> i64 { var p: i64=o; p=j_b(out,p,0x0F); p=j_b(out,p,cc); p=j_w32(out,p,rel); return p } |
| 160 | func jit_ra_alloc(rvmap: *i64, nbox: *i64, r: i64) -> i64 { if r==0 { return 0 } if rvmap[r]>=0 { return 0 } if nbox[0]>=3 { return 0-2 } rvmap[r]=ra_pool(nbox[0]); nbox[0]=nbox[0]+1; return 0 } |
| 164 | func jit_compile_ra(opk: *i64, rd: *i64, rs1: *i64, rs2: *i64, imm: *i64, nidx: i64, out: *u8, x86off: *i64, rvmap: *i64) -> i64 |
| 217 | func jit_main_ignore() -> i64 { return 0 } |