Skip to content

AArch64 backend for the IR-based JIT - #932

Open
bmdhacks wants to merge 3 commits into
HaxeFoundation:masterfrom
bmdhacks:aarch64-ir
Open

bmdhacks wants to merge 3 commits into
HaxeFoundation:masterfrom
bmdhacks:aarch64-ir

Conversation

@bmdhacks

@bmdhacks bmdhacks commented May 11, 2026

Copy link
Copy Markdown

Adds an AArch64 codegen backend that plugs into the new IR pipeline (jit.c -> jit_regs.c -> jit_aarch64.c), mirroring the role of jit_x86_64.c. Targets Linux and macOS ARM64 (AAPCS64; X15/X16/X17 reserved as backend temporaries, 16-byte internal push stride, native overflow arguments at the platform ABI).

Backend surface:
hl_jit_init_regs AAPCS64 register classes (X0..X14 scratch with X5
remapped to logical slot 32, X19..X28 persist;
V0..V7 and V16..V28 scratch, V8..V15 persist,
V29..V31 reserved)
hl_codegen_init module preamble: null-access stubs, c2hl/hl2c
trampolines
hl_codegen_function IR einstr stream -> AArch64 machine code
hl_codegen_flush_consts ADRP+LDR patching for the per-module pool
(distinguishes LDR Xt/Dt/St for correct imm12
scaling)
hl_codegen_final BL relocations, jump-table absolute fixups

Encoding layer (jit_aarch64_emit.c/h) supplies the instruction encoders shared with the trampolines; floating conditional moves use FCSEL and parallel-move cycles use XCHG/CXCHG.

regs_config gains a stack_arg_size field so the IR's stack-argument accounting agrees with the backend's 16-byte-per-push convention required by AAPCS64 stack alignment.

module.c: on AArch64, walk the X29 frame-pointer chain in module_capture_stack instead of the heuristic stack scanner. The scanner produces false-positive frames from callee-saved STP X19,X20 spills that look like (stack_addr, code_addr) pairs. PUSH_ADDR emits output-relative ADRP+ADD fixups so null-access frames resolve to the correct source line.

Build: CMake selects src/jit_aarch64.c when the target processor is aarch64/arm64; the Makefile gains an ARCH=arm64 branch. CI runs the ARM64 JIT tests.

macOS arm64 code memory uses MAP_JIT and pthread_jit_write_protect_np.

Validated against unit.hl with all tests passing.

This was referenced May 11, 2026
Comment thread src/jit.c Outdated
Comment thread src/jit_regs.c Outdated
@bmdhacks

Copy link
Copy Markdown
Author

rebased to latest hl2_ir code

@tritao

tritao commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

@bmdhacks Can you rebase this again?

@bmdhacks

Copy link
Copy Markdown
Author

@bmdhacks Can you rebase this again?

Working on this now!

@RblSb RblSb mentioned this pull request Sep 11, 2026
@bmdhacks
bmdhacks changed the base branch from hl2_ir to master September 12, 2026 03:44
Port the AArch64 code generator onto the current IR contract on
upstream master.  Folds the original backend commit and its follow-up
ABI fixes into one topic:

  * AAPCS64 register classes; 16-byte PUSH stride so SP stays 16-byte
    aligned, with the native stack layout (8-byte Linux slots,
    natural-size Apple packing) derived from the configured push width
  * PUSH_ADDR lowering for null-access source locations, patched with
    output-relative ADRP+ADD page arithmetic
  * debug callback trampoline registered via hl_jit_trampoline
  * CMOV materialized at the value's real width so sub-word sources
    (notably bools) are zero-extended instead of loading adjacent bytes
  * V29-V31 reserved as codegen temporaries and kept out of the
    allocator's visible scratch set
  * persistent-save accounting at the backend push unit (16 bytes on
    AArch64) rather than the x86 default
  * gc.c: MAP_JIT plus hl_flush_executable_memory (I-cache flush and
    W^X flip) so Apple ARM64 can allocate and publish JIT pages
  * module.c: walk the X29 frame-pointer chain on AArch64 instead of
    the heuristic scanner, and recover the synthetic PUSH_ADDR call
    site so null-access stack traces report the access line
  * profile.c: extract the program counter and stack pointer from the
    Darwin arm64 mcontext
  * CMake and Make: select the AArch64 backend and build the VM on
    aarch64/arm64 instead of skipping it
The AArch64 backend is now present, so run the full build, smoke, and
Haxe test matrix on arm64 instead of faking a non-JIT `hl`:

  * run the Makefile smoke test on arm64 (remove the arm64 guard)
  * drop the `--skip-hl-jit` test flag for arm64
  * install the real arm64 `hl` binary instead of a stub
@bmdhacks

Copy link
Copy Markdown
Author

Updated to latest. All unit tests pass and it runs Dead Cells on asahi linux on my M2 mac.
Screenshot From 2026-09-11 21-38-01

@bmdhacks

Copy link
Copy Markdown
Author

BTW, @ncannasse I avoided making any changes to the IR since I wanted this to be as drop-in as possible to make it easyish for you to accept (I know it's still a big giant wall of code). But there are some more optimizations I could do like using NEON for some ops if you'd be up for a later PR with some IR additions/alterations.

Also thanks for your time and consideration and all the work. Your contributions to gaming are amazing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants