Repository navigation
Conversation
…pruning dead branches
The compiler emits one general template per construct, which leaves every
literal account behind a str_eq/jmp_if_false diamond and every literal amount
behind a max(amount, 0) one. This adds the peephole layer compiler-architecture.md
described, with the two passes that collapse those diamonds:
- ir.Peephole is a func([]ir.Instr) []ir.Instr returning nil when nothing
changed; ir.Optimize sweeps ir.DefaultPeepholes to a fixed point, bounded by
maxOptimizeSweeps.
- foldConstConditions turns str_eq, eq_int, lt_int and is_zero over constant
operands (a register written once, by a load) into true/false.
- pruneDeadBranches folds jumps on a constant bool, drops the instructions no
reachable path runs, jumps to the next instruction and labels no jump targets.
Optimization is opt-in: compiler.Compile is unchanged, and
compiler.CompileWithOptions(.., Options{Optimize: true}) — numscript.CompileOptions
on the public API — runs the passes and typechecks the result before assembling.
The contract is that the optimized program is behaviorally identical to the
plain one, and three checks enforce it: the spec corpus runs both on every case
and requires identical results and error structs, the verifier/encoding corpus
test runs both, and the differential sweep gets a "vm vs optimized vm" leg
compared with no tolerance at all (CompareIdentical).
Benchmarks (Apple M3 Pro, medians of 6) show the two passes alone are only a
few dispatches per send:
BenchmarkCompiledVM 692 ns/op 336 B/op 10 allocs/op
BenchmarkCompiledVMOpt 666 ns/op 336 B/op 10 allocs/op
BenchmarkCompiledVMCapped 1865 ns/op 864 B/op 23 allocs/op
BenchmarkCompiledVMCappedOpt 1836 ns/op 864 B/op 23 allocs/op
NumaryBot
previously approved these changes
Oct 20, 2026
NumaryBot
left a comment
Contributor
There was a problem hiding this comment.
The required automated review completed with no remaining findings.
ascandone
force-pushed
the
perf/ir-peepholes
branch
from
October 20, 2026 09:39
9ea2885 to
10da831
Compare
NumaryBot
previously approved these changes
Oct 20, 2026
NumaryBot
left a comment
Contributor
There was a problem hiding this comment.
The required automated review completed with no remaining findings.
…asses Three passes join pruneDeadBranches in ir.DefaultPeepholes, sharing one analysis, walkConsts: a forward walk that knows which registers hold the same constant on every path reaching an instruction. Jumps only go forward, so one pass is exact. It replaces the "written once" rule foldConstConditions and pruneDeadBranches relied on, which the typechecker does not guarantee per path. - constProp (replaces foldConstConditions) folds every pure op into a load of its result, as the VM computes it. check_enough_funds fails unless got == needed, so after it got takes needed's value: with a literal amount the whole allotment split is computed at compile time. - dropProvenAsserts removes a check that passes on every path; a check that may fail stays in place, so the first error a run hits is unchanged. Dropping assert_leftover is what frees the portion arithmetic. - deadCode removes pure instructions no path reads. Store reads, pulls and checks stay; mk_portion goes only with a denominator known not to be zero. The passes can trade one assembler capacity bound for another, so when the optimized stream hits ErrRegisterBankOverflow or ErrProgramTooLarge the compiler assembles the plain one. They can also lift a bound (unused load_vars go), so the difftest's vm vs optimized vm leg tolerates, and counts, a plain capacity error the optimized program does not hit. Benchmarks (Apple M3 Pro, medians of 6, plain -> optimized): Allotment 1/2,1/2 1830 -> 1127 ns 42 -> 20 allocs 392 -> 198 B AllotmentThirds 2499 -> 1580 ns 58 -> 27 allocs 333 -> 164 B FanIn 1/3 x3 2888 -> 1753 ns 56 -> 23 allocs 478 -> 161 B Capped 1891 -> 1832 ns 23 -> 23 allocs World 677 -> 640 ns 10 -> 10 allocs AllotmentVar ($m) 1743 -> 1740 ns 37 -> 37 allocs An amount from a var reaches no constant, so its allotment keeps its big.Rat arithmetic. Optimize costs 20-46us per script.
NumaryBot
approved these changes
Oct 28, 2026
NumaryBot
left a comment
Contributor
There was a problem hiding this comment.
The required automated review completed with no remaining findings.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.