finding: synth#869 — whole 64-bit int<->float family unlowered (ARMv7E-M VFP root cause); relay's source dodge verified exhausted - #172
Merged
Conversation
…owered (root cause: ARMv7E-M VFP has no such instruction); source-side dodge verified exhausted relay chased jess's GI-FPU-001 dodge and reported a clean NEGATIVE result: call site is Timestamp::as_secs_f32() (seconds:u64 + fraction:u32), and the crate correlation confirms the diagnosis from both ends (relay-rate/ekf/pos CALL it = exactly the 3 GI-FPU-001 stages; relay-att only DEFINES it and is GI-FPU-002-blocked). Four narrowings tried, disassembled each time: LLVM clamps in integer domain but won't narrow to i32 before the convert; op persisted even after deleting the helper. No producer-side form exists. jess then probed synth 0.51.0 with a minimal WAT over the whole family. Single coherent gap: ALL SIX 64-bit int<->float ops unlowered (f32/f64.convert_i64_u/s, i64.trunc_f32_u/s) while EVERY 32-bit form lowers, INCLUDING i32.wrap_i64 + f32.convert_i32_u — so the canonical shape exists in wasm but is unreachable from Rust. ROOT CAUSE: ARMv7E-M VFP has NO 64-bit-integer<->float instruction (VCVT on FPv4-SP/FPv5-D16 encodes only S32/U32 <-> F32/F64; 64-bit forms arrive with AArch64 SCVTF/UCVTF). Cortex-M toolchains route these via AEABI builtins — and synth already has a --builtins path, so no new machinery. Filed synth#869 (both prior anchors #369/#782 are CLOSED; this family had no open issue). Gate is now exactly two synth items, neither needing anything from relay: (1) synth#869 -> unblocks rate/position/ekf (2) GI-FPU-002 VFP spilling -> attitude/iekf (3) mixer already through -> next jess rung = lower mixer + Renode-vs-SIL differential. Verified: probe run on synth 0.51.0 (nm-confirmed lowered/skipped sets); rivet validate PASS. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
relay chased the GI-FPU-001 dodge jess proposed and reported a clean negative result — exactly the right call. Call site confirmed as
Timestamp::as_secs_f32()(seconds: u64+fraction: u32), and the crate correlation closes the diagnosis from both ends:relay-rate/relay-ekf/relay-poscall it = precisely the three GI-FPU-001 stages;relay-attonly definesTimestampand is GI-FPU-002-blocked instead.Four narrowings tried (integer-domain differencing,
u64::mincap, mask-truncate, small-cap early-narrow), disassembled after each: LLVM clamps in the integer domain correctly but won't narrow to i32 before the convert — on wasm both widths cost the same. The op persisted even after deleting the helper outright. No producer-side form exists.jess probed synth directly — one coherent gap
Minimal WAT over the whole conversion family on synth 0.51.0:
f32.convert_i32_u/_s,i32.trunc_f32_s,i32.wrap_i64+f32.convert_i32_uf32.convert_i64_u/_s,f64.convert_i64_u/_s,i64.trunc_f32_u/_sAll six 64-bit integer↔float ops are unlowered; every 32-bit form works. So the canonical lowering shape exists in wasm but is unreachable from Rust.
Root cause — an implementation task, not a wiring bug
ARMv7E-M VFP has no 64-bit-integer↔float instruction at all.
VCVTon FPv4-SP/FPv5-D16 encodes onlyS32/U32↔F32/F64; the 64-bit integer forms arrive only with AArch64SCVTF/UCVTF. Every Cortex-M toolchain routes these through AEABI builtins (__aeabi_ul2f,__aeabi_l2f,__aeabi_ul2d,__aeabi_l2d,__aeabi_f2ulz,__aeabi_f2lz) — and synth already has a--builtinslinking path, so the fix needs no new machinery.Filed synth#869 with the minimal repro, AEABI mapping, per-stage impact (entry symbols named) and relay's exhausted-workaround credited so nobody re-treads it. Both prior anchors (#369, #782) are closed — this family had no open upstream issue.
The gate is now exactly two synth items, neither needing anything from relay
rate/position/ekfattitude/iekfmixeris already through (0 skips) → next jess rung: lowermixer+ run it in the RT1176 Renode model against a SIL differential — the first real relay flight component executing on the M7, exercising the whole consumption path with the gate still open.rivet validate→ PASS.🤖 Generated with Claude Code