Skip to content

Allow the LLVM backend to target AArch64 - #15

Open
dougchansan wants to merge 2 commits into
ExpansionPak:mainfrom
dougchansan:llvm19-aarch64-support
Open

Allow the LLVM backend to target AArch64#15
dougchansan wants to merge 2 commits into
ExpansionPak:mainfrom
dougchansan:llvm19-aarch64-support

Conversation

@dougchansan

@dougchansan dougchansan commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

What

dolllvm_emit_object rejected every triple that was not x86-64:

if (triple.getArch() != llvm::Triple::x86_64 || ...)
  fprintf(diagnostics, "dolllvm: supported production targets are x86-64 Linux and Windows\n");

This accepts AArch64 as well.

Why it is safe

The gate looked like a support policy rather than a technical limit, and the code bears that out — the function emitter and both lowering files contain no x86-specific code:

  • no inline asm anywhere in src/backend/llvm/
  • functions are emitted with CallingConv::C
  • the target machine already comes from getDefaultTargetTriple() / getHostCPUName()
  • CMake already links the native / nativecodegen LLVM components

So the IR is target-neutral and LLVM codegens AArch64 objects without further changes.

Verification

Raspberry Pi 4 (Cortex-A72), Debian clang/LLVM 19.1.7, against Luigi's Mansion (GLME01) — a 530,648-instruction DOL, 4164 chunks:

check result
object output ELF 64-bit LSB relocatable, ARM aarch64
module loads under ModernGekko yes
rendering correct (in-game scene renders normally)
smc_failed 0
GX FIFO errors 0
framerate vs C backend, same scene 19.51 vs 19.46 FPS

Runtime counters differ from the C backend as you would expect from a different codegen path, and notably the LLVM backend took zero hook fallbacks against the C backend's 196:

llvm : native=1669  hook_fb=0    verifications=22  bursts=81
c    : native=1974  hook_fb=196  verifications=5   bursts=63

On that framerate number

19.5 FPS is a fixed comparison point, not a figure for the game. Framerate on this hardware is strongly scene-dependent: the mansion foyer used for the benchmark is a heavy scene, title and cutscene sequences run roughly 30–60 FPS, and other rooms are measurably faster. Both backends were measured on the identical savestate, scene, clock and settings, with a fixed 300-second frame-verified window — the point is parity between backends, not the absolute value.

Scope

This enables the target; it is not a performance change. On this workload the AArch64 LLVM backend measured the same as the C backend (the bottleneck there is L1-icache pressure, which codegen does not move). Flagging that explicitly so the change is judged on correctness rather than on a speed claim.

x86-64 behaviour is unchanged.

@dougchansan
dougchansan force-pushed the llvm19-aarch64-support branch from 7b74f36 to 96a2e99 Compare August 13, 2026 23:03
The backend refused any triple that was not x86-64, but that gate was a
support policy rather than a technical limit. The function emitter and the
memory/runtime lowering contain no x86-specific code: there is no inline
asm, and functions are emitted with CallingConv::C, so the IR is
target-neutral and LLVM codegens AArch64 objects directly.

Verified on a Raspberry Pi 4 (Cortex-A72, Debian clang/LLVM 19.1.7)
against Luigi's Mansion (GLME01), a 530k-instruction DOL:

  - dolrecomp emits 4164 chunk objects, "ELF 64-bit LSB relocatable,
    ARM aarch64"
  - the linked module loads and runs under ModernGekko
  - rendering is correct, smc_failed=0, zero GX FIFO errors
  - framerate matches the C backend on the same scene: 19.51 vs 19.46 FPS

Framerate on this hardware is strongly scene-dependent, so the number
above is a fixed comparison point rather than a figure for the game: the
mansion foyer is a heavy scene, while title and cutscene sequences run
roughly 30-60 FPS and other rooms are measurably faster. Both backends
were measured on the identical savestate and scene.

This enables the target; it is not a performance change. On this workload
the AArch64 LLVM backend measured the same as the C backend, though it
took zero hook fallbacks against the C backend's 196.
Relaxing the triple guard let the backend accept an AArch64 target, but an
x86-64 build could still not produce one: LLVM only registers the native
target by default, and a target that was never registered is simply absent
from the registry. lookupTarget then reports it as an unsupported triple --
"No available targets are compatible with triple aarch64-unknown-linux-gnu"
-- which reads like a bad triple rather than a missing component.

Register the AArch64 target explicitly and link the AArch64 CodeGen, AsmParser,
Desc and Info components. This costs binary size on the build machine and
nothing at runtime.

The existing backend test now also emits the same module for
aarch64-unknown-linux-gnu and asserts the result is an ELF64 little-endian
object with e_machine EM_AARCH64. That path is a cross-compile on every host
the suite runs on, and it fails at emission rather than producing a wrong
object if the registration is dropped, which is what makes it worth asserting.

Validated by cross-compiling two titles on an x86-64 Windows host and running
them on a Raspberry Pi 4: Luigi's Mansion (63,029,456 byte module) boots,
renders and plays, with zero hook fallbacks.
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.

1 participant