How Stone Is Fast
Stone achieves C-level performance not through manual optimisation, but through language design choices that give the compiler enough information to optimise effectively.
See the benchmark results for measured performance data.
Most languages choose between high-level abstractions and low-level performance. Stone takes a different approach: immutability, structured iteration, and expression-oriented design give the compiler enough information to generate the same code a human would write by hand. You write clear, declarative code; the compiler does the rest.
Language Design
Stone values are immutable by default. Once created, they cannot be changed. State transitions happen through explicit evolve loops that declare exactly which variables change. Because nothing changes unexpectedly, the compiler can safely reorder, combine, and remove computations — enabling , , and dead code elimination without needing .
The language is expression-oriented — conditionals, loops, and blocks all produce values. Every computation is traceable through its result, so dead code elimination is straightforward: if nothing uses the result, the expression can be removed.
Instead of arbitrary while loops with mutable counters, Stone uses evolve — a structured iteration construct that explicitly declares state variables, how they update (primed bindings like x'), and when to stop. The compiler sees the full loop structure at a glance, enabling loop reduction, copy elimination, and closed-form replacement.
Stone has complete type resolution — no type annotations required, no runtime type checks. Every value's type is known at compile time. Generic functions are for each concrete type, eliminating runtime type dispatch and overhead. There is no null value and no exception mechanism — functions always return a value of their declared type, so the generated code has no null checks, no exception tables, and simpler control flow.
Finally, indexed arrays are language primitives. Writing result[i] = expr tells the compiler each iteration is independent — it's a . The compiler knows the output size, can process iterations in parallel, and allocates the result array once upfront. This enables bounds check elimination, , and pattern recognition.
Optimisation Pipeline
Stone's compiler runs 20+ optimisation passes in a carefully ordered sequence. Each pass enables subsequent passes by exposing new opportunities.
The HIR uses form with explicit blocks and loop metadata. All optimisations attach annotations to the HIR rather than restructuring it, so they're safe to run in any order.
Constant Propagation
Evaluates constant expressions at compile time and propagates known values through the program. Simplifies branches with constant conditions.
Dead Code Elimination
Removes instructions whose results are never used and unreachable blocks. Runs multiple times throughout the pipeline to clean up after other passes.
Evolve Copy Elimination
Eliminates redundant copies of primed state variables in evolve loop bodies. Writes directly to the base variable instead of through a temporary.
Strength Reduction
Replaces expensive operations with cheaper equivalents. x ** 2 becomes x * x (avoids libm pow), x ** 0.5 becomes sqrt(x), x / C becomes x * (1/C) when C is constant.
Loop Invariant Code Motion
Moves computations that don't change within a loop to outside the loop. Hoists array lookups and arithmetic out of hot inner loops.
Common Subexpression Elimination
When the same expression appears multiple times with the same inputs, computes it once and reuses the result.
Array Get Fusion
Fuses chained array accesses — arr[i][j] compiles as a single strided access instead of extracting an intermediate row array.
Bounds Check Elimination
Proves array accesses in bounded loops are always within range and removes runtime bounds checks. Enables vectorisation by removing conditional branches.
BLAS Recognition
Detects triple-nested matrix multiply patterns and annotates them for inline WASM compilation with direct memory loads. Annotation-only — never mutates the IR.
Record SROA
Scalar Replacement of Aggregates. When a record is created only to have its fields read out, skips the allocation entirely and forwards the values directly.
Integer Promotion
Identifies variables that always hold integer values, so the backend can use faster integer arithmetic instead of floating-point.
If-Conversion
Converts simple if-then-else patterns to branchless instructions, avoiding costly branch mispredictions in tight loops.
Loop Reduction
Detects accumulation loops and replaces them with closed-form mathematical expressions. A loop summing i² for 100M iterations becomes a single formula evaluation.
Block Merging
Coalesces linear chains of basic blocks into larger blocks, creating more opportunities for subsequent passes.
Loop Reduction
One of Stone's most dramatic optimisations. The compiler recognises accumulation patterns and replaces entire loops with constant-time formulas.
Sum of squares
100M iterations → 1 formula evaluations = evolve {acc = 0, i = 0} while (i < N) {
acc' = acc + i * i
i' = i + 1
}
result = s.accresult = (N - 1) * N * (2 * N - 1) / 6
Triangular number
10M iterations → 1 formula evaluations = evolve {sum = 0, i = 0} while (i < N) {
sum' = sum + i
i' = i + 1
}
result = s.sumresult = N * (N - 1) / 2
This works because evolve loops explicitly declare their state variables and update rules. The compiler can recognise the accumulation pattern and replace it with the equivalent formula. A traditional while loop with arbitrary mutation wouldn't give the compiler enough information to do this.
WASM Backend
The WASM backend generates WebAssembly bytecode that runs at near-native speed in any browser. All arrays live directly in WebAssembly using a , not as JavaScript objects. Array access is a single load instruction — no JavaScript boundary crossing, no property lookup, no GC pressure. This alone took matrix-multiply from 1.2ms (JS-backed) to 226µs (native).
When the compiler detects a matrix multiply pattern, it emits the entire computation as inline WASM bytecode using for cache-friendly memory access, integer loop counters, and direct memory loads — no function calls in the hot loop. The result is 226µs WASM vs 45µs C, within 5x of native C with -O3.
When a function only works with integers, the compiler promotes to WASM i64 instructions instead of f64, avoiding conversion overhead. Simple conditionals in tight loops are compiled to WASM's instruction instead of if-else blocks, avoiding branch misprediction. Memory is allocated by incrementing a pointer, and allow temporary allocations to be reclaimed in bulk — zero GC pauses, O(1) allocation, deterministic memory usage.
LLVM Backend
Stone compiles to , which is then compiled by clang with full optimisations. This gives Stone programs access to the same optimisation suite used by C and Rust compilers — the LLVM backend is consistently 1.0-1.5x of C across most benchmarks.
Variables identified as always holding integers are emitted as native i64 instead of double, letting LLVM apply integer-specific optimisations: strength reduction, simplification, and wider vectorisation. Integer-heavy benchmarks run within 9% of equivalent C.
Stone runs its own optimisation passes before handing code to LLVM. This means LLVM receives cleaner, simpler input — redundant work already removed, loops already simplified, temporary records already eliminated. LLVM starts from a better baseline, so the final output is faster than either optimiser alone.
The Key Insight
Stone's performance doesn't come from a single clever trick. It comes from a compound effect: immutability lets the compiler freely reorder and eliminate computations without alias analysis. Structured iteration exposes loop structure that enables closed-form reduction, BLAS recognition, and bounds check elimination. Static types with full resolution let the compiler specialise code paths without runtime checks. And indexed arrays as primitives tell the compiler that iterations are independent, enabling parallel maps, vectorisation, and upfront allocation. Each design choice enables specific compiler transforms, and those transforms enable each other in sequence.
The result: Stone programs are written at a higher level than C, but compile to code that matches or exceeds it — the LLVM backend averages 0.87x of C across 20 benchmarks, while the WASM backend reaches 1.4x.
See the full benchmark results for measured performance data across 20 benchmarks and 6 backends.