feat(aarch64): div/rem + popcnt + f64↔i64 reinterpret — frontier to empty (#851)#858
Open
avrabe wants to merge 6 commits into
Open
feat(aarch64): div/rem + popcnt + f64↔i64 reinterpret — frontier to empty (#851)#858avrabe wants to merge 6 commits into
avrabe wants to merge 6 commits into
Conversation
Lower the three op groups that previously loud-declined on -b aarch64: - Integer div/rem (i32+i64): SDIV/UDIV, rem via MSUB (a-(a/b)*b). A64 div is TOTAL where WASM is PARTIAL, so emit explicit WASM trap guards: divisor==0 -> brk (all four forms, full-width cbnz for i64) and, for SIGNED DIV only, INT_MIN/-1 overflow -> brk. rem_s(INT_MIN,-1)==0 falls out of MSUB naturally (no overflow guard). Localized divrem closure; temps allocated while operands still reserved (the #776 aliasing rule) so MSUB's simultaneous a/b/q reads never clobber. - popcnt (i32+i64): SIMD fmov->CNT.8b->ADDV->fmov (A64 has no scalar popcnt). i32 uses fmov s (zero-fills upper lanes), i64 uses fmov d. - f64<->i64 reinterpret (GI-FPU-001): fmov d,x / fmov x,d bit-casts. New encoders (llvm-mc ground-truth byte tests): sdiv/udiv/msub (+64), cnt_8b, addv_8b, cbnz64. All clang/llvm-mc verified. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
…al (#851) - Map F64ReinterpretI64/I64ReinterpretF64 in convert_operator (they had WasmOp variants but were never decoded, so globally declined). Now reaches the aarch64 fmov d,x / fmov x,d arms. Verified all backends either emit or LOUD-decline (never silent-drop): aarch64 emits; cortex-m7dp ARM emits i64_reinterpret_f64 / loud-declines the f64 return (GI-FPU-002 ABI class); no-FPU ARM + RV32 loud-decline. Cross- backend op-parity gate green. - Fix div_s INT_MIN/-1 overflow-guard branch offset (+3 -> +4: the two mov_imm halfwords make the skip span 3 insns, so b.ne targets +4 words). Caught red by the native matrix (div_s(7,2) spuriously TRAPped). - New aarch64_divrem_851 execution differential: 152 wasmtime cases (34 trap cases) verified native (SIGTRAP) + unicorn (brk). Proves div/rem by-zero (all forms, both widths) and div_s INT_MIN/-1 TRAP exactly where wasmtime traps; rem_s(INT_MIN,-1)==0 (no trap). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
…851) - Add the #851 div/rem trap-and-value execution oracle to the aarch64-oracle CI job. - Remove div/rem/popcnt from the decline-honesty probe (they now lower and are execution-verified) and refresh the job comment. The probe now asserts only rounding + i64<->float conversions still loud-decline (3/3 green). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
…acle Extend the #851 differential beyond div/rem: i32/i64 popcnt (both widths, including the i64 full-8-lane ADDV path) and the f64<->i64 reinterpret round-trip (bit-identity) now execute vs wasmtime too — native SIGTRAP + unicorn. 152 -> 179 cases. Gives the popcnt/reinterpret deliverables the same execution bar as div/rem (previously byte-tested only). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
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.
Summary
L5 of the v0.51 hub. Flips the three op groups that previously loud-declined on
-b aarch64. Gale's acceptance gate (scripts/repro/aarch64_matrix.sh) frontier goespopcnt div_s rem_s→ empty (32 → 35 accepted ops, 86 → 91 native checks, all bit-identical vs wasmtime).1. Integer div/rem (i32 + i64) — with WASM trap guards
div_{s,u}→ A64SDIV/UDIV;rem_{s,u}→SDIV/UDIV+MSUB(rem = a − (a/b)·b).Soundness (the #633/#666/#709 totality class): A64 divide is TOTAL where WASM is PARTIAL — SDIV/UDIV return 0 on ÷0 and INT_MIN on INT_MIN/−1, neither traps. So the lowering emits explicit WASM trap guards:
== 0→brk— all four forms, full-widthcbnzfor i64 (a 32-bit test would miss a divisor like0x1_0000_0000).INT_MIN / −1overflow →brk— signed DIV only.rem_s(INT_MIN,−1) == 0(no trap) falls out ofMSUBnaturally.Aliasing follows the #776 rule:
MSUBreads a, b AND the quotient at once, so every temp is allocated while a/b are still reserved on the value stack.2. popcnt (i32 + i64)
A64 has no scalar popcount:
fmovgpr→SIMD,CNT vN.8b,ADDV bN, vN.8b,fmovback. i32 usesfmov s(zero-fills upper lanes → CNT sees 4 value + 4 zero bytes); i64 usesfmov d.3. f64↔i64 reinterpret (GI-FPU-001)
i64.reinterpret_f64/f64.reinterpret_i64→ bit-preservingfmov x,d/fmov d,x. TheseWasmOpvariants existed but were never decoded (convert_operator), so they globally declined. Un-dropping them at decode also un-blocks ARM's existing VFP lowering — verified every backend still emits OR loud-declines, never silent-drops: aarch64 + cortex-m7dp ARM emit; no-FPU ARM / single-precision Cortex-M / RV32 loud-decline. Cross-backend op-parity gate green.Frontier: before → after
popcnt div_s rem_sTrap evidence
scripts/repro/aarch64_divrem_851_differential.py— 179 cases (34 trap cases) vs wasmtime, executed two ways: unicorn (brk→UcError) and natively on arm64 (each call forked, SIGTRAP observed by parent). Covers ÷0 (all forms, both widths), div_s INT_MIN/−1 TRAP, rem_s(INT_MIN,−1)==0, plus popcnt (both widths) and the reinterpret round-trip. Wired into theaarch64-oracleCI job (unicorn-gated there; native path exercised on the macos-latest native-matrix runner + locally). During bring-up the native matrix caught a real red — the div_s overflow-guard branch offset was off by one (+3→+4), spuriously trappingdiv_s(7,2).New encoders (llvm-mc ground-truth byte tests)
sdiv/udiv/msub(+64-bit),cnt_8b,addv_8b,cbnz64.Verification
cargo test -p synth-backend-aarch64 --lib: 73/73cargo test --workspace: greensynth-backend-aarch64,synth-core): cleanclaim_check.py: 25/25 claims pass (the 2 generated-file staleness failures arestatus.json/FEATURE_MATRIX.md, regenerated by the coordinator at assembly per fix(claims): regenerate status.json + FEATURE_MATRIX for #803 trunc_sat ops (main is red) #805 — not hand-edited here)Notes for coordinator / other lanes
synth-coreconvert_operator(decode) — changes cross-backend op exposure for the two reinterpret ops. Behavior surface verified per-backend above; textual conflict risk with L3/L4 low.aarch64_selector_opsfigure changed — regeneratestatus.json+FEATURE_MATRIX.mdat assembly.Closes the div/rem/popcnt/reinterpret portion of #851.
🤖 Generated with Claude Code
https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L