MIR optimization
Luce removes unused functions and obviously dead MIR. LLVM then does the machine-oriented work: inlining clamp_double, turning * 2 into a shift, and replacing a small branch with csel.
Two optimizers, two jobs. Luce knows which language operations have effects and which declarations are unreachable. LLVM knows instruction costs, registers, and the target processor. The boundary keeps each decision with the system that has the facts to make it.
Three passes
Reachability is more than a call graph
Calls and selected entry points.
Function values, bound methods, closure bodies, and interface witness slots.
Class deinit functions and layouts referenced by live values.
An imported standard module arrives as source, so the initial program may contain many declarations the entry never reaches. Pruning is what makes an unused hosted helper free: its Builtin effect never survives into the artifact.
Dead does not mean unread
A result register may be unread while its instruction still matters. A host call can print. A container mutation can change a shared object. A release can run deinit, close a file, or join a task. The effects table classifies what can disappear and what must stay.
Optimization cannot change destruction order, resource behavior, traps, or host effects. A retain/release pair is removable only when none of those observations can change.
Why the optimizer stops here
Constant folding, inlining, loop transforms, vectorization, instruction selection, register allocation, and target scheduling are LLVM's work. Reimplementing them over MIR would create a second optimizer to maintain and a second place for target-sensitive bugs.
Luce MIR owns
Language reachability, explicit runtime effects, cleanup semantics, and compact protocol.
LLVM owns
General scalar and loop optimization, target instructions, physical registers, and object emission.
Verify, transform, verify
The input must already pass the MIR verifier. After passes delete blocks and renumber registers, the whole result passes again. This makes each optimizer bug a compiler diagnostic in the build path rather than malformed native code downstream.