kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

commit 5124ada6d86bf9fec1298bc85bc6df6ad191323d
parent e8f7a220cb0fa548b419b4264542ba463949616f
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Sat, 13 Jun 2026 17:19:22 -0700

doc(perf): refresh PERF.md standings after o0-codesize Lever 2 + follow-ons

Re-measured on arm64-macOS (best-of-7, build/release/kit): sqlite -c object
1.99 -> 1.79 MB (emitting ~6.8% fewer .text insns writes a smaller object);
-c compile instructions ~flat at 1.91 B (the emit + smaller-objwrite savings
are offset by Lever 2's per-op api_temp_dead deadness checks, which also lift
-fsyntax-only 1.63 -> 1.64 B); tcc bar (0.66 B) and -E (0.93 B) unchanged.
o0-codesize .text now 1.33x -> 1.084x tcc (was 1.16x). Update standings table,
object-size line, and the phase-decomposition prose.

Diffstat:
Mdoc/plan/PERF.md | 39+++++++++++++++++++++++----------------
1 file changed, 23 insertions(+), 16 deletions(-)

diff --git a/doc/plan/PERF.md b/doc/plan/PERF.md @@ -35,7 +35,7 @@ recent low-load reading. | compiler | instructions | cycles † | wall † | object | |---|--:|--:|--:|--:| | **tcc 0.9.28** | 0.66 B | 0.22 B | 0.06 s | 2.11 MB | -| **kit (current)** | 1.91 B | — | — | **1.99 MB** | +| **kit (current)** | 1.91 B | — | — | **1.79 MB** | | clang 22 | 8.73 B | 2.57 B | 0.81 s | 1.50 MB | † low-load reading; re-confirm on a quiet machine (`instructions` is @@ -43,22 +43,27 @@ load-independent and the figure to trust; cycles/wall are pending a quiet-machin re-read). kit beats clang on compile speed and is the fastest *general* backend here, but -**tcc is the bar**: ~2.88× instructions ahead. Closing that is the whole game. +**tcc is the bar**: ~2.87× instructions ahead. Closing that is the whole game. The gap was 3.23× when this table was last read; two campaigns since closed it to -2.88×: the frontend instruction-slimming work on main (Sym-keyed binding cache, +2.87×: the frontend instruction-slimming work on main (Sym-keyed binding cache, per-id type decode, single-pass symtab/strtab — `-fsyntax-only` 1.84 → 1.63 B) -and the **`o0-codesize` track** (next paragraph). kit's **object is now 1.99 MB -— below tcc's 2.11 MB** (was 2.29 MB), because emitting less machine code also -writes a smaller object. +and the **`o0-codesize` track** (next paragraph). kit's **object is now 1.79 MB +— well below tcc's 2.11 MB** (was 1.99 MB, 2.29 MB before), because emitting less +machine code also writes a smaller object. -The `o0-codesize` track cut emitted `-O0` `.text` from **1.33× → 1.16× tcc** -(455,546 → 398,433 insns) via five landed levers — far-slot positive-scaled +The `o0-codesize` track cut emitted `-O0` `.text` from **1.33× → 1.084× tcc** +(455,546 → 371,537 insns): five early levers (far-slot positive-scaled addressing, a 2-insn epilogue, call-result-in-result-register, copy-into-dest -materialization, and narrow-load zero-extend elision. Three are arch-neutral -(also −3.18 % on x86-64). Smaller output is also fewer instructions to emit and -write, so it shrinks the emit+objwrite slice here too. Full standings, diagnosis, -and the remaining levers (args-into-arg-regs, spill reduction): **`doc/plan/ -PERF-O0-CODESIZE.md`**. +materialization, narrow-load zero-extend elision), then **Lever 2** (spill +reduction — eager dead-operand drop + a branch materialize-before-flush reorder, +−24,581) and three single-pass follow-ons (switch-selector residency, signed +load-with-extend, byte/half far slots; −2,315). Several are arch-neutral (the +shared-NDT levers also help x86-64/rv64). Smaller output is fewer instructions to +emit and write, so it shrinks the emit+objwrite slice — though Lever 2's +producer-side `api_temp_dead` checks add a small offsetting CG-layer cost, so the +`-c` compile-instruction total is ~flat (the win shows in the 10 %-smaller +object). Full standings, diagnosis, and the remaining levers (args-into-arg-regs +is now the dominant one): **`doc/plan/PERF-O0-CODESIZE.md`**. ### Reproducing the detailed measurements @@ -111,9 +116,11 @@ m build/release/kit cc -c -o /tmp/k.o sqlite3.c --sysroot "$SDK" # + codegen `-fsyntax-only` still drives the full CG value-stack and type lowering (routed to the no-op check backend), so `(-c) − (-fsyntax-only)` isolates **native emit + -object write** only. Current binary: `-E` 0.93 B, `-fsyntax-only` 1.63 B, `-c` -1.91 B → that delta is ~0.28 B / ~15 % — i.e. **codegen+emit is a small slice; -the frontend is the rest.** Within that frontend, `-E` alone (0.93 B) is just +object write** only. Current binary: `-E` 0.93 B, `-fsyntax-only` 1.64 B, `-c` +1.91 B → that delta is ~0.27 B / ~14 % — i.e. **codegen+emit is a small slice; +the frontend is the rest.** (The `o0-codesize` spill-reduction levers nudged +`-fsyntax-only` up ~0.01 B via their per-op `api_temp_dead` checks while shrinking +the emit slice, so the `-c` total held ~flat as the object shrank 10 %.) Within that frontend, `-E` alone (0.93 B) is just under half, and the scanner (`lex_next`) is the bulk of it — see *Where the time goes*. (Landings that shrank these: the scanner rewrite cut a flat ~84 M off every phase — `-E` 1.06 → 0.93 B — the -O0 value-stack residency work took