feat(#851): aarch64 linear-memory load/store lowering + gale's acceptance gate#855
Merged
Conversation
…word)
Lower WASM linear-memory ops in the host-native A64 backend against a
dedicated base register (x28 = __linear_memory_base on entry), mirroring
the ARM R11 / RV32 s11 convention. Adds LDR/STR (w/x) + LDRB/STRB +
LDRH/STRH + LDRSB/LDRSH (w and x sign forms) + LDRSW encoders, all
clang-ground-truth-verified, and an add-extended (uxtw) address form.
Effective address = x28 + uxtw(i32 addr) + memarg.offset. Offsets that
fit the size-scaled imm12 fold into the load/store immediate; larger
offsets materialize-and-add. Covers I32/I64 load/store and every
sub-word i32/i64 variant; MultiMemory and everything else still
loud-decline (no silent miscompile).
Honest frontier: computes+dereferences the effective address but does
NOT bounds-check — WASM OOB-trap, data-segment init, and
memory.{size,grow} are documented follow-ons (host-native subset has no
memory-size convention yet). In-bounds load/store is execution-verified
vs wasmtime.
Refs #851
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
…orn gates Vendor gale's self-contained aarch64 execution-differential acceptance gate to scripts/repro/aarch64_matrix.sh (reproduces the stated baseline: 32 ops / 86 native checks PASS, frontier popcnt/div_s/rem_s). Exits non-zero ONLY on a miscompile so each op auto-flips declined->verified as its lowering lands. Add a memory execution-differential (aarch64_mem_851_differential.py + .wat): 38 store/load round-trips run under unicorn with a real linear-memory region and x28 set to the base, diffed bit-exact vs wasmtime. Covers i32/i64 + all sub-word sign/zero forms, the big-offset materialize path, and a cross-function wr/rd pair that proves the shared-base convention (not sp-scratch). Red-first: before the lowering every memory op is skipped from the symtab (symbol-missing => fail). CI: run the memory differential in the existing host-independent aarch64-oracle (unicorn) job; add an aarch64-native-matrix job on macos-latest (arm64) that installs wasm-tools+wasmtime and runs gale's native MAP_JIT matrix as the real-silicon acceptance gate. Refs #851 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
…tablishment frontier - macos native-matrix job: point OBJCOPY at brew llvm (not on default PATH) and assert accepted-op count >= 32. The matrix counts an op as DECLINED (=PASS) when .text extraction yields empty hex, so a missing objcopy/objdump would green the gate having verified nothing — the vacuous-gate class. The assertion makes that a hard failure. - Selector: document that the backend does NOT yet EMIT code that establishes x28 (no aarch64 startup/linker script, unlike RV32 s11) — the lowering is correct given the x28=base precondition the #851 differential supplies; wiring the ABI/startup is a documented follow-on. Refs #851 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
… warnings) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
…native-matrix rc check - Feature-matrix template: aarch64 row now states linear-memory load/store is handled (in-bounds, x28 base, #851) instead of 'memory ... declines'; regenerated FEATURE_MATRIX.md + status.json (aarch64 selector ops 111->130, the claim-check count gate that this change moved). - claims.yaml VCR-VER-003 note (d): aarch64 is N/A for the static-data addressing validator because it has load/store but no data segments yet (not because it has no memory ops) — accurate post-#851. - ci.yml native-matrix: capture the matrix exit code explicitly and fail on it (the miscompile signal), rather than leaning on set -e propagating through $(...); keep the accepted-op non-vacuity assert. - CHANGELOG [Unreleased]: the #851 memory lowering + gate. Refs #851 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
avrabe
force-pushed
the
feat/aarch64-memory-851
branch
from
July 23, 2026 18:23
82f057a to
c070878
Compare
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
aarch64 linear-memory load/store lowering (#851, the biggest blocker) + gale's acceptance gate
Lowers WASM linear-memory ops in the host-native A64 backend (
-b aarch64) andwires gale's execution-differential as the standing acceptance gate.
What landed
synth-backend-aarch64):i32.load/store,i64.load/store, and every sub-word form —i32.load8_{s,u}/16_{s,u},i32.store8/16,i64.load8_{s,u}/16_{s,u}/32_{s,u},i64.store8/16/32. Effective address =x28 (linear-memory base) + uxtw(i32 addr) + memarg.offset; offsets fold into the size-scaled imm12 when they fit, else materialize-and-add.add …, uxtwaddress form — all clang-ground-truth-verified.x28 = __linear_memory_baseon entry, mirroring ARM R11 / RV32 s11. Chosen outside the temp pool (x9–x15), the AAPCS64 arg/result registers, and platform/frame regs. The lowering only reads it.MultiMemoryand everything uncovered still loud-decline (no silent miscompile).Gate evidence (frontier before → after)
scripts/repro/aarch64_matrix.sh; it reproduces the stated baseline exactly: 32 ops / 86 native checks PASS, frontierpopcnt div_s rem_s(memory ops aren't in gale's op-set, so the matrix is unchanged — as required).aarch64_mem_851_differential.py): 38/38 store/load round-trips bit-identical vs wasmtime under unicorn with a real linear-memory region + x28 set. Covers i32/i64, all sub-word sign/zero forms, the big-offset materialize path, and a cross-functionwr/rdpair proving the shared-base convention (not sp-scratch)..textsymtab (warning: skipping function), so the differential'ssymbol missing → failpath is RED; after, GREEN. (Structurally identical to howdiv_sdeclines today.)Verification scope (honest)
fn(int32,int32)runner that cannot set thex28base, so it exercises the ALU/float/control ops on real arm64 but not memory. The unicorn differential setsx28+ a real linear-memory region and diffs vs wasmtime.CI
aarch64-oracle(unicorn) job.aarch64-native-matrixjob onmacos-latest(arm64) runs gale's native MAP_JIT matrix as the real-silicon acceptance gate — with a non-vacuity guard (points OBJCOPY at brew llvm, assertsaccepted ops >= 32) so a broken objcopy/objdump can't green the gate having verified nothing.Documented residual frontier (honest, not silent)
Per the selector comment + differential docstring:
startup.rs). The lowering is correct given thex28 = baseprecondition, which the differential supplies; wiring the ABI/startup that establishes it in a real program is a follow-on.memory.{size,grow}are follow-ons.Refs #851
🤖 Generated with Claude Code
https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L