Skip to content

Sound recursive-numeric specialization to recover the ~20% #7238 cost on 05_fibonacci #7244

Description

@proggeramlug

#7238 removed emit_i64_specializations because neither half of its contract
was provable: a number parameter is a double (the wrapper's fptosi
truncated fractional arguments), and nothing bounded any intermediate at 2^53
(where JS starts rounding and exact i64 arithmetic does not).

That removal has a measured cost. Interleaved A/B on a Mac mini, 9 pairs,
fixed arm slower in 9/9: benchmarks/suite/05_fibonacci.ts fib(40) went
450 ms → 555 ms, about 20%. 14_closure was within noise because its
compute picked up a __typed_f64 clone instead; fib did not, because its
body is not straight-line and so does not qualify for the typed-f64 gate.
(Neither host was quiet — indicative, not controlled.)

The shape a sound version needs, which #7238 was not the place to build:

  1. Guarded entry. The public f64 wrapper proves each argument is an exact
    integer (sitofp(fptosi(x)) == x, and in range) before entering the
    integer body, instead of assuming it.
  2. A deopt edge. The ordinary f64 body must still be emitted — the removed
    pass suppressed it, which is precisely why the wrapper had nowhere to fall
    back to. A failed entry guard calls the f64 body.
  3. A bounded interior, or a checked one. Either a static magnitude bound
    in the style of i32_chain_magnitude_bits (fix(codegen): round JS arithmetic to f64 at every i32-chain step (#7232) #7237) — which needs a bounded
    leaf, and a self-recursive parameter has none — or a per-operation
    |v| <= 2^53 check that deopts to the f64 body with the current (still
    exact) arguments. The per-operation check is the only one that covers the
    recursive accumulator, and it needs measuring: three branches per fib
    call may well erase the 20% it is trying to recover.

Worth noting that the straight-line half of this is already solved by the
typed-ABI clones and the Phase-2 specialized ABI, which prove representations
from call sites rather than assuming them. The open ground is specifically
self-recursive numeric functions whose body is not straight-line, which is
the one case where fib lands and no existing specializer reaches.

Acceptance: 05_fibonacci back to within noise of f8f1e7188, with
test-files/test_gap_7238_i64_specialization_exactness.ts still byte-exact
against the pinned Node — that test already contains the fractional-argument,
2^53-boundary and past-2^63 shapes any such pass has to survive.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions