D268 - Floating-point arguments never reached an implementation

decided · 2026-08-25 · thirteen conformance failures, one cause

GuestFn was fn(&[u64; 6]) -> u64: six integer registers in, one out. That is the whole call boundary, and there was no xmm anywhere in the dispatch path.

A double travels in xmm0-xmm7 and never in the integer registers. So the guest put 4.0 in xmm0, the handler read six integer registers that did not contain it, and answered in rax, which the guest was not reading. sqrt(4) came back as 4 - the guest's own argument, still sitting in xmm0 because nothing had written it.

Thirteen checks in one section failed that way. Every floating-point function on the platform was unreachable, and no title had said so, because a title just faults somewhere downstream.

The trampoline spills all eight floating-point argument registers and loads xmm0 from a slot the handler writes. Eight stores, unconditionally, against six pushes and a call that already happen - the alternative is a second trampoline chosen per import at table build time, which the stubs could carry because they already hold their own trampoline address. That is the escape hatch if it ever measures badly; half an ABI is not.

GuestFloatFn is a second type rather than a widened first one, because the busiest import in the corpus is called ninety-nine million times without touching a float. It answers raw bits rather than an f64, so sqrtf does not have to lie about its return type.