kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

commit 0711b27c9cd911ac8d8794d313ea5cf03a88bc6f
parent 51681b4548f8b4046ecb863e175c4ab64179aa5f
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Wed, 17 Jun 2026 13:12:09 -0700

doc/ARM32: record parse-corpus wrong-result closure (12 reds → 0)

All 12 wrong-runtime-result parse reds are resolved: 3 arm32 codegen fixes
(struct-param ABI, signed-negative switch SUB-imm truncation, many-int variadic
spill aliasing), 2 shared-corpus cases made data-model-agnostic (far_slot_large_
frame → long long, builtin_generic_overflow → __LONG_MAX__), and 2 data-model
skips (6_5_64_unsigned_size_division, rv64_atomic_widths_orders, matching rv32).

Parse lane now 928 pass / 5 fail / 62 skip; the 5 remaining fails are all the
pre-existing emit/codegen gaps (asm_01_grammar, builtin_31_readcyclecounter,
gnu_labels_as_values_threaded), not wrong results.

Diffstat:
Mdoc/plan/ARM32.md | 79+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
1 file changed, 51 insertions(+), 28 deletions(-)

diff --git a/doc/plan/ARM32.md b/doc/plan/ARM32.md @@ -33,40 +33,63 @@ the qemu gate). See the "Follow-on variants / polish" checklist below for status (and MVN shift suffix) matching llvm-objdump. Verification note: `make test-cross TARGET=freestanding-arm32 DEPTH=full` toy lane -is **423/0/2**; the broad parse lane is **921 pass / 17 fail / 58 skip**. The 58 -skips are the i128 + binary128-long-double cases (unsupported by design, now -`.arm32.skip`-sidecar'd to match rv32). The remaining 17 fails are a genuine -follow-on triage list — see "Broad parse-corpus triage" below. The fix that took -the parse lane from 33 to 17 fails: the O1 frameless-leaf tier returned through a -bare `BX lr` while the backend uses `lr` as an emit scratch (global-address -staging, overflow/popcount/bitfield/byte-copy), so any such leaf clobbered its -return address (the 16-case O1 globals/statics/attributes `rc 134` cluster). The -slim tier now saves `lr` (`PUSH {lr}`/`POP {pc}`). - -### Broad parse-corpus triage — outstanding (NOT core; freestanding-arm32 parse lane) - -17 reds remain in `make test-cross TARGET=freestanding-arm32 DEPTH=full` (parse -lane). None are in the closed core checklist; each needs separate triage: -- **Emit/codegen gaps (5):** +is **423/0/2**; the broad parse lane is **928 pass / 5 fail / 62 skip** (the run +also showed one transient `6_5_41_ptr_sub_ptr/O1/E` qemu timeout under parallel +load — `got 124` = GNU `timeout`'s exit code at 22 s vs the usual 140 ms; it +passes 3/3 isolated, an infrastructure flake, not a red). The 62 skips are the +i128 + binary128-long-double cases plus the two data-model-only cases +(`6_5_64_unsigned_size_division`, `rv64_atomic_widths_orders`), all +`.arm32.skip`-sidecar'd to match rv32. The remaining **5 fails are all +emit/codegen gaps** (`asm_01_grammar`, `builtin_31_readcyclecounter`, +`gnu_labels_as_values_threaded`) — see "Broad parse-corpus triage" below; the 12 +wrong-runtime-result reds are CLOSED (2026-06-17). The earlier fix that took the +lane from 33 to 17 fails: the O1 frameless-leaf tier returned through a bare +`BX lr` while the backend uses `lr` as an emit scratch (global-address staging, +overflow/popcount/bitfield/byte-copy), so any such leaf clobbered its return +address (the 16-case O1 globals/statics/attributes `rc 134` cluster). The slim +tier now saves `lr` (`PUSH {lr}`/`POP {pc}`). + +### Broad parse-corpus triage — wrong-results CLOSED 2026-06-17 + +The 12 **wrong-runtime-result** reds are all resolved (3 codegen fixes, 2 +data-model-agnostic test rewrites, 2 data-model skips). Only the 5 emit/codegen +gaps remain on the parse lane: +- **Emit/codegen gaps (5) — outstanding:** - [ ] `asm_01_grammar` O0+O1 — `arm32 inline asm: optimizer asm input not in a register` (inline-asm operand binding at the parse-corpus's harder cases). - [ ] `builtin_31_readcyclecounter` O0+O1 — `arm32` does not support the `readcyclecounter` intrinsic (needs a DWT/CYCCNT or unsupported gate). - [ ] `gnu_labels_as_values_threaded` O1 — `opt native emit: no scratch register` (computed-goto under -O1 register pressure). -- **Wrong runtime result (12):** - - [ ] `6_5_2_2_06_struct_param_mixed_fp_int` O0 (got 229) + O1 (got 5) — mixed - fp/int struct-param ABI lowering. - - [ ] `6_5_64_unsigned_size_division` O0+O1 (got 10) — unsigned size division. - - [ ] `6_8_29_switch_signed_negative` O1 (got 42, want 100) — signed-negative - switch at O1. - - [ ] `builtin_generic_overflow` O0+O1 (got 6, want 7) — `__builtin_*_overflow` - generic-selection edge. - - [ ] `far_slot_large_frame` O0+O1 (got 4, want 7) — large-frame far slot - addressing. - - [ ] `rv64_atomic_widths_orders` O0+O1 (got 9, want 42) — atomics widths/orders - (the case is rv64-named but runs in the arm32 lane). - - [ ] `variadic_02_many_ints` O1 (got 0) — many-int varargs at O1. +- **Wrong runtime result (12) — DONE:** + - [x] `6_5_2_2_06_struct_param_mixed_fp_int` O0+O1 — AAPCS32 8-byte-aligned + aggregate (struct{double;long;}) was mis-split between core regs and stack; + caller/callee disagreed. Fixed: surface the record alignment on parts[0], + one `arm_arg_needs_even` predicate everywhere, round-to-even + naive + straddle (drop the no-straddle override). (commit 8d022009) + - [x] `6_8_29_switch_signed_negative` O1 — the jump-table `idx = sel - vmin` + with vmin=-3 emitted `subw #4093` (the −3 constant truncated to 12 bits); + legality accepted the negate-trick but emit never implemented it. Fixed: + shared `arm_resolve_addsub_imm` for legality + emit. (commit e98cc403) + - [x] `variadic_02_many_ints` O1 — under pressure the spilled constant call args + rematerialized into the round-robin opt-scratch (ip/lr), aliasing the + simultaneously-live register args. Fixed: exclude call-arg values from + remat (keep their spill store) + store register-resident stack args + directly. (commit 51681b45) + - [x] `far_slot_large_frame` — was a data-model artifact (`long` is 32-bit on + arm32, so `x`'s 8-byte check failed and the 8-byte far slot wasn't even + exercised). Made the shared case `long long` → tests the 8-byte far slot + on every arch and passes (arm32 + LP64). (commit 8d022009) + - [x] `builtin_generic_overflow` — LP64-only by construction; the one + data-model-dependent line used a magic 0x7fff…ffffL. Switched to + `(long)__LONG_MAX__` (overflows `long` under both ILP32 and LP64) → now + data-model-agnostic, passes on arm32 + LP64. (commit 8d022009) + - [x] `6_5_64_unsigned_size_division` — 64-bit-size_t overflow idiom; on a + 32-bit target size_t IS 32-bit and the clamp legitimately fires (clang + returns 10 too). `.arm32.skip` (matches the rv32 skip). (commit 8d022009) + - [x] `rv64_atomic_widths_orders` — exercises rv64's 64-bit A-extension atomics + through `long`; 64-bit atomics are out of ILP32 scope (32-bit atomics + covered by builtin_06..25). `.arm32.skip` (matches rv32). (commit 8d022009) ## Core checklist — remaining items (single source of truth)