Optimizer Guide
The optimizer must preserve source behavior while improving generated output.
It is not complete until optimized compiler output can self-host and pass the
same gates as unoptimized output.
Command Line
Optimization is selected by an explicit level:
zero-native build-elf source.0x0 -o output --opt 1
zero-native build-obj source.0x0 -o output.o --opt 1
zero-native oisa source.0x0 --out output.oisa --opt 1
Level 0 is the current unoptimized behavior. Level 1 enables only passes
that have verifier coverage. Any other level is rejected with
unknown optimizer level: <level> rather than silently selecting a different
pass set.
The current implemented compiler-source entry points are:
compile-file-optimized(path, level)
compile-module-optimized(source, level)
optimizer-dump-file(path, level)
compile-file-optimized-passes(path, pass-list)
compile-module-optimized-passes(source, pass-list)
optimizer-dump-file-passes(path, pass-list)
The native command-line --opt flow remains the release integration target; the
current narrow gate exercises the optimizer through compiler source APIs to
avoid running the heavy native/release compiler builds during incremental work.
Required Pass Interface
Each pass must have:
- a stable pass name;
- deterministic input and output;
- an enable/disable switch;
- a verifier run after the pass;
- a dumpable before/after representation for debugging.
Current pass registry:
level 0: none
level 1: constant-fold,branch-prune,string-dedup,dead-bindings
custom-only: inline-small
The explicit pass-list entry points accept the same stable pass names and run
them in the provided deterministic order. Unknown pass names are rejected with
unknown optimizer pass: <name>.
The current IR is the parsed AST normalized through the existing node accessors.
optimizer-verify-forms runs before pass dispatch and after every enabled pass.
First Passes
The current accepted passes are:
constant-fold: folds pure integer arithmetic and comparisons, integer
identity forms such as (+ 0 x), (- x 0), (* 1 x), and (/ x 1),
boolean not and known-condition if, text-len for literal text, literal
text-cat, text-cat empty literal forms such as (text-cat "" x ""), and
literal text-eq?.
branch-prune: removesifbranches when the condition is a known boolean
after earlier passes or in the original source.
string-dedup: hoists repeated string literals in a function body into one
generated local binding when doing so avoids embedding the same literal more
than once in that function.
dead-bindings: removes local bindings whose folded values are side-effect
free literals and whose names are unused by later bindings and the body.
inline-small: inlines pure, non-recursive, single-expression helpers when
the helper body is below the current AST node budget and contains no local
binding that could capture substituted arguments. It is custom-only until the
heavier optimized-binary behavior gate promotes it into a release level.
The constant-fold pass includes integer identity forms and text-cat empty
literal forms as part of its stable level-1 behavior.
Planned next passes are:
- tail-call lowering where ABI rules allow it;
- direct ELF and object-output peepholes.
Correctness Rule
An optimized binary and an unoptimized binary must produce identical output for
the same source and runtime inputs. Invalid programs must remain invalid, with
diagnostics in the same documented class.
make optimizer-core-check is the low-memory structural guard. It verifies the
registered pass order, dispatch coverage, verifier-after-pass wiring, pass
implementation entry points, fixtures, and pass-registry rejection path without
importing compiler/main.0x0 through the source runner.
make optimizer-source-smoke-check runs the source-level optimizer dump smokes
that import compiler/main.0x0. That target is the behavioral source-API gate,
but it is intentionally explicit because the current source-runner import path
can exceed the incremental RAM budget before the RAM architecture milestone is
finished. The target runs through tools/rss-limit.sh and writes
build/optimizer-core/source-smoke-rss.txt; the default cap is read from
optimizer.source_smoke.max_rss_kib in perf/memory-budgets.txt and can be
overridden with OPTIMIZER_SOURCE_SMOKE_MAX_RSS_KIB.
make optimizer-check is the heavier release-path gate. It enforces behavior
comparison for native optimized/unoptimized binaries. Optimizer implementation
must also keep stage2 == stage3 true when optimization is enabled for the
release compiler path.