Commit Graph
1 Commits
Author SHA1 Message Date
Malte Ubl cae3e3bd7e Extend integer clones to arrays, mutual tail calls and proven ranges
Clones now cover more recursive number shapes:

- Recursion over array indices: a function may take number arrays it
  borrows (the caller keeps them alive for the call) and read `length`
  and elements. An element inside the array's hole-free prefix that is
  exactly an int32 is read inline; holes, other indices and other numbers
  bail to the ordinary body. Borrowed entries get dispatchers too.
- Mutual tail recursion: tail calls between members of a recursive
  component return the callee's result as is, so LLVM inlines them into
  one loop (isEven/isOdd), as it already does for the ordinary body.
- The proven int32-slots ranges of number parameters (valid at every
  call site, recursive ones included) become `llvm.assume`s in each
  activation, so `%` of non-negative values divides unsigned without -0
  handling (gcd).

A clone now overflows the stack where the ordinary body would, instead of
bailing after 2^14 loop iterations. LLVM turns the ordinary body's plain
tail calls into loops, so the clone's plain tail calls (self or mutual)
run unchecked too: endless tail recursion runs forever on either path,
as it did before clones. An accumulating call (`1 + f(n - 1)`, fib's
`f(n - 1) + f(n - 2)`) is real recursion in the ordinary body, because a
double sum is not associative. Its clone loop carries a virtual stack
pointer that starts at the real one (an inlined activation one frame
below its parent's) and drops 32 bytes, about an ordinary frame of these
functions, per iteration; passing the stack guard throws the
stack-overflow RangeError. Deep finite chains stay on the fast path, and
`1 + down(n - 1)` with n = 1e7 still throws like Node
(4984-generator-exceptions, corpus 5342).

Corpus 5343 covers array-index recursion, binomials, holes and
non-integer elements.
2026-10-15 05:26:05 -07:00