Issue #595: Build ADR-342: a chain over a list runs element by element; an overflow in it may stop it at the end; a filter without a branch

Open and answer this issue on GitHub.

performance, ready · opened 2026-10-12 · updated 2026-10-12 · 0 comments

How it came up

An outside proposal (generated by Gemini) suggested four kinds of “pipeline fusion” so that Nikaia reaches Mojo’s speed:

Its premises were partly wrong. It assumed an arena that is built (ADR-327 decides one, but it is not built, see #490), and it claimed that && is “one decision point”. The owner asked what can be taken from it. The goal: Nikaia should compete with Mojo where the plain chain a model writes is as fast as the loop an expert tunes, with every check kept. Mojo gets its speed from written SIMD and vectorize, and does not check overflow.

What was checked (0.0.854)

Decision

ADR-342, with the rule in Part I 4.5 and Part III A.2:

To build

  1. D1, the fusion. In the emitter, a list’s map whose result is not named and goes into another map, iter(), a for or len() is lowered as into_iter().map(f).map(g)…, with one collect where a list is wanted. The condition is the one par_iter lambdas meet (touches empty, no NK2107), without the demand not to pause.
    • Test: xs.map(f).map(g) gives the same output as today.
    • Test: a chain whose first lambda printlns keeps today’s order: all of f, then all of g.
  2. D1, the one measurement it owes. A fused loop where one step is vectorized on its own and the other is not, against two passes. Count it with callgrind (instructions and mispredicted branches), output byte for byte the same. Where fusion is slower for that shape, that shape is not fused.
  3. D3, measure first. A chain map/sum over i64, three ways:
    • today’s code;
    • overflowing_* with the flags OR-ed and one check after the loop;
    • the same, per run of elements.

    Then the same chain where LLVM does not vectorize. Emit D3 only where it is not slower. A value that overflowed must reach no index, division or condition before the check.

    • Test: an overflow in such a chain stops the task with src/main.nika:N: … attempt to add with overflow, naming the line of the +.
  4. D4, measure first. A filter with two cheap conditions, on random data and on sorted data:
    • && (today);
    • &;
    • without a branch (write every element, move the end by the condition).

    Emit each form only where it is not slower.

    • Test: a filter whose second condition can panic keeps &&.
  5. Specification: nothing left. Part I 4.5 and Part III A.2 already say it.

Not decided here (ADR-342 §6)

Back to Open Issues