commit fdc9c73ea5e848d900c1bc154101d3ee41a0d5c3
parent a9e0c865122ac82d5b27160ac10ad0ec53fa4dd2
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Tue, 16 Jun 2026 19:02:53 -0700
doc: record arm32 Phase 2 delivered (ARM32.md status + PORT.md cross row)
Diffstat:
2 files changed, 40 insertions(+), 0 deletions(-)
diff --git a/doc/PORT.md b/doc/PORT.md
@@ -252,6 +252,7 @@ compiled and ran a program there.*
| freebsd-{aarch64,amd64,riscv64} | ready | ready (VM) | ready (toy via VM) |
| windows-{aarch64,x64} | ready | ready (VM) | ready (toy via VM) |
| freestanding-rv32 | ready | ready (bare) | ready (toy X + parse E, bare) |
+| freestanding-arm32 | ready | ready (bare, -O1) | ready (toy X + parse E, bare) |
| freestanding-{aa64,x64,rv64} | ready | ready (bare smoke) | **deferred** |
`selfhost`: macos (native), linux musl/glibc aarch64 (container), linux x64/rv64
diff --git a/doc/plan/ARM32.md b/doc/plan/ARM32.md
@@ -1,5 +1,44 @@
# Plan: 32-bit ARM (`arm-none-eabi`, ARMv7-M / ARMv7E-M, Thumb-2)
+## Status — 2026-06-16 — Phase 2 (full backend) LANDED
+
+The arm32 backend is now a complete -O0/-O1 Cortex-M C toolchain. All of the
+Phase-2 inventory below is implemented and qemu-validated:
+
+- **-O1 known-frame path** (`func_begin_known_frame`, callee-save PUSH/POP, slim
+ leaf tier) + large frames/offsets staged through IP. The cross lane runs at
+ **-O1** (`scripts/cross_test.sh` no longer forces -O0).
+- **Global address materialization** — MOVW/MOVT-absolute + `R_ARM_THM_MOVW_ABS_NC`/
+ `_MOVT_ABS` (scaled-index folded into `load_addr`); `load_const`/`load_label_addr`.
+- **i64 + soft-double (wide8)** — AAPCS even-register pair alignment, per-lane
+ call/return passing, 8-byte `load_const`; mul/div/shift + all `double`/`float`
+ via the kit-built runtime's libgcc helpers (`__udivdi3`/`__adddf3`/…).
+- **Aggregates / varargs / atomics / inline asm** — `copy_bytes`/`set_bytes`,
+ INDIRECT struct-by-value params/args/returns, AAPCS32 `va_*` (8-byte-aligned),
+ LDREX/STREX + DMB ≤4-byte atomics (8-byte → spinlock libcall), a minimal
+ inline-asm template runner.
+- **Op-groups / intrinsics** — switch jump tables (`indirect_branch`), C bitfields
+ (BFI/UBFX/SBFX), CLZ/CTZ/BSWAP, barriers (DMB/DSB/ISB) + hints, the 6 32-bit
+ `__builtin_*_overflow`, `alloca`, `__builtin_frame_address`/`return_address`.
+- **Single-thread TLS-as-static** (M-profile has no CP15 thread reg).
+- **ARM ELF REL emission** (`.rel.text`, addend in-field) — kit objects now link
+ with stock ARM linkers (ld.lld), not just `kit ld`.
+- **Descriptor-driven disassembler + standalone assembler** (`isa.c`/`disasm.c`/
+ `asm.c`, `test/arch/arm32_decode_test` → `test-isa`, 314/0).
+- **kit self-compiles `libkit_rt.a`** for `arm-eabi-thumb2` (`make
+ rt-arm-eabi-thumb2`; the C compiler-rt sources). The hand-written AEABI alias
+ layer + coroutine asm switch are excluded from the kit self-build (the kit
+ assembler does not yet cover those asm idioms — a follow-on).
+- **Tests**: `test-cross TARGET=freestanding-arm32` smoke at -O1 + full (toy X +
+ parse E, bare); `test-smoke-arm32` (ld.lld + kit-ld lanes); the decode unit
+ test. The freestanding fix to kit ld's linker-script location counter (interior
+ `sym = .` after a glob) landed alongside.
+
+Remaining follow-ons (intentional, documented): tail calls; the AEABI alias
+layer + coroutine asm in the kit-self-built rt (needs broader kit-as coverage);
+hard-float (FPv4-SP); DSP/ARMv7E-M; ARMv6-M/Thumb-1; full `-mcpu`/`-mfpu`
+parsing; `.ARM.attributes`; a real multi-threaded TLS path; `-O0` code density.
+
## Status — 2026-06-16 — Phase 1 (walking skeleton) LANDED
**Phase 1 is green:** `make test-cross TARGET=freestanding-arm32 DEPTH=smoke`