Archive — history, not state. Kept for its reasoning and its evidence; its plan is closed.
Native complete checked-array-store fold
Status: accepted isolated experiment on 530a9fcf; not merged upstream.
Hypothesis
M5 made the final array store itself fast, but fannkuch still executed the entire semantic checked-index diamond around every store:
is_int pred, key
jump_false pred, bad
length len, array
lt scratch, key, 0
jump_true scratch, bad
gt scratch, key, len
jump_true scratch, bad
store array, value, key
jump done
bad: disrupt
done:
The native emitter already has all information needed to implement this region directly. Doing so should remove tagged predicate construction, three scratch frame round trips, a generic length operation, and redundant branches while preserving the same observable bad-index and append behavior. This is a native-only lowering; semantic mcode and Mach output must remain unchanged.
Accepted implementation
qbe_emit scans final, fact-indexed mcode and selects only the exact ten-entry
shape above. Selection additionally requires:
- an independently exact
arraytype at the store use; - an exact point-specific integer constant
0for the lower-bound test; - the bad label immediately after the source jump and exactly the three shown incoming references;
- a private done label with exactly the source jump as predecessor;
- distinct predicate/length/comparison scratch slots that are neither captured nor live at the bad or done entries;
- no disruption handler in the function.
Any label, instruction, slot alias, fact gap, handler, extra predecessor, or live scratch value makes the recognizer decline. The emitter leaves both source labels in place and skips only the proven private hot region.
The replacement first tests the integer tag and signed lower bound. It then uses the existing semantics-complete direct store lowering at the original store instruction index, so receiver/RHS type spans and write-barrier decisions remain exact. The direct path:
- chases a forwarded array;
- rejects
key > length, while retainingkey == lengthappend semantics; - checks capacity and calls the ordinary rooted growth path when necessary;
- preserves the stone check and disruption path;
- stores the value and retains the old-to-young generational write barrier.
No semantic mcode operation, runtime object layout, Pit frame slot, actor state, heap allocation, per-program table, or serialized metadata was added. The only new state is temporary compiler data inside the QBE emitter. An initial scanner used many function locals and made self-hosted QBE emission inflate toward a 2 GiB compiler heap; that version was rejected before timing. Packing scanner temporaries into one nested record restored ordinary roughly 128 MiB compiler memory. Compiler speed and temporary memory are not campaign goals, but catastrophic self-host overhead is still not acceptable.
Generated-code evidence
Focused fannkuch.ce output on the exact parent and candidate:
| artifact | parent | candidate | delta |
|---|---|---|---|
| QBE IL | 178,984 B | 167,625 B | -11,359 B (-6.35%) |
| assembly | 117,570 B | 114,287 B | -3,283 B (-2.79%) |
linked __text | 32,160 B | 31,036 B | -1,124 B (-3.50%) |
dylib file / mapped __TEXT | 87,648 B / 49,152 B | 87,648 B / 49,152 B | unchanged page footprint |
The generated dylib data, bss, and other mapped segments are unchanged. This therefore improves target code density without spending target RAM. The mapped page count is unchanged for this one host fixture because both text sections fit the same page-aligned segment; a ROM image without Mach-O page padding retains the 1,124-byte text reduction.
Performance
Fresh-process, eleven-sample medians were interleaved to control thermal drift. The median of the three process medians is the claimed result:
| arm | process medians (ms) | median (ms) |
|---|---|---|
exact parent 530a9fcf | 201.222, 184.077, 185.108 | 185.108 |
| complete-store fold | 117.495, 112.742, 113.575 | 113.575 |
That is a 38.6% native fannkuch speedup with the independent result
3000008629. The first pair was thermally higher in both arms; the two later
brackets independently show approximately the same 38-39% improvement.
A final dual-lane matrix measured Mach 226.3 ms and native 117.2 ms, with exact
results. Mach is intentionally unchanged. array_grow produced a byte-for-byte
identical focused dylib on parent and candidate and stayed around 1.9 ms; its
source does not contain this checked diamond. Mandelbrot also produced the same
dylib and stayed around 8.9 ms. Spectralnorm and binarytrees retained exact
results; neither selected this fold in the focused artifacts. The generational
array-barrier oracle, stone-write oracle, growth microbenchmark, and fannkuch
all matched Mach in the final matrix.
Correctness gates
- Compiler lowering tests: 95/95.
- Added a positive exact-region fixture that requires the upper-bound branch, absence of the length helper, and presence of the pointer write barrier.
- Added a negative fixture with a second incoming bad-label edge; it must retain the original checked diamond.
- Default suite outside the restricted socket sandbox: 1,918/1,918.
- Deterministic differential fuzz, 500 iterations at seed 20260713: 3,733/3,733.
- Dual-lane barrier, stone, growth, and fannkuch matrix: all exact.
The first sandboxed default-suite attempt reported six local bind/port failures
(Operation not permitted) and 1,901 passes. Running the identical suite with
normal local-socket permissions immediately passed all 1,918 tests; this was a
test-environment restriction, not a product failure.
Tradeoff and disposition
This is a favorable constrained-target trade: large AOT speedup, smaller generated text, no target data or runtime memory, no ABI or language change, and a conservative decline path. The cost is 142 source lines in the already large QBE emitter plus compiler-only scanning work. Keep it for composition and retest after the record-template, structured-TCO, and recursive-call branches are combined.
Source: plans/archive/perf-2026-07/perf-native-checked-store-region.md