← All issues

[JSC] GreedyRegAlloc: Add loop-aware live range splitting (disabled by default)

899099b

JSTests/stress/regalloc-loop-splitting.js

+//@ requireOptions("--airGreedyRegAllocSplitAroundLoops=true")
+function test(p) {
+ let v0=p+0, v1=p+1, ..., v15=p+15;
+ let sum = 0;
+ for (let i = 0; i < 100; i++)
+ sum = clobber(sum + i); // call clobbers all caller-saved regs
+ return v0+v1+...+v15+sum;
+}

B3 is JSC's optimizing JIT compiler; Air is its low-level assembly IR where physical register assignment happens. The greedy register allocator assigns physical registers to virtual registers (tmps) by processing live ranges in priority order; when a tmp cannot be allocated, it is either spilled or split into independently-allocatable sub-ranges. Loop-aware splitting frees a register held across an entire loop but unused inside it, by splitting the live range and inserting Shuffle-based fixup at loop entry/exit.

This commit adds loop-aware live range splitting to JSC's greedy register allocator. A new CFG normalization pass (ensureDedicatedLoopEntryExitBlocks) ensures safe insertion of Shuffle-based fixup code at loop entry and exit edges; the feature is gated behind airGreedyRegAllocSplitAroundLoops and disabled by default. Air's Shuffle instruction handles parallel moves including cycles (e.g., A↔B swap). The commit explicitly states that the splitting policy and integration with the allocator's priority-driven allocation order are incomplete.

Shuffle-based parallel-move fixup at loop entry/exit must resolve register cycles correctly; a bug in cycle resolution produces silent value corruption in JIT output rather than a crash.

🔒

New JIT infrastructure with CFG rewriting and parallel-move fixup generation — multiple audit directions across the fixup and range-rewrite logic.

Subscribe to read more