Skip to content
Optimization — Constant Folding & Dead Code
step 1/3

Reading — step 1 of 3

Compiler Optimizations

~2 min readType System & Optimization

Optimization — Constant Folding & Dead Code

A compiler's job is not just translating code — it can also make code faster. Optimization passes transform the code (at the AST or bytecode level) to reduce instructions, eliminate waste, and improve performance.

Constant Folding

Constant folding evaluates constant expressions at compile time:

var x = 1 + 2 * 3;    // before: OP_CONST 1, OP_CONST 2, OP_CONST 3, OP_MUL, OP_ADD
                       // after:  OP_CONST 7 (computed at compile time)

If both operands of an arithmetic operation are known at compile time, we compute the result immediately and emit a single constant. This eliminates runtime work entirely.

The compiler checks: is this a Binary node where both children are Literal nodes? If so, compute the result and replace the Binary with a Literal.

Constant Propagation

If a variable is assigned a constant and never reassigned, replace all uses with the constant:

var x = 10;
var y = x + 5;    // x is known to be 10 → y = 10 + 5 → y = 15

This enables further constant folding. The two optimizations work synergistically.

Dead Code Elimination

Code that can never execute is dead code. Remove it:

fun f() {
    return 42;
    print "unreachable";   // dead code — remove
}

if (false) {
    print "never";         // dead code — remove
}

Dead code elimination makes the bytecode smaller and avoids confusing the programmer.

Strength Reduction

Replace expensive operations with cheaper ones:

x * 2      →  x + x         // multiplication → addition
x * 1      →  x             // identity
x + 0      →  x             // identity
x * 0      →  0             // zero
x / 1      →  x             // identity

These algebraic identities can save cycles, especially in tight loops.

Peephole Optimization

Examine small sequences of bytecode instructions and replace with more efficient sequences:

OP_PUSH 1, OP_ADD     →  OP_INCREMENT    // if we add such an instruction
OP_NOT, OP_NOT         →  (nothing)       // double negation cancels
OP_PUSH, OP_POP        →  (nothing)       // push then immediately discard

How V8 Optimizes JavaScript

V8's TurboFan JIT compiler applies dozens of optimization passes: inlining, escape analysis, loop-invariant code motion, register allocation, instruction selection, and more. These are far beyond what we implement, but the fundamentals (constant folding, dead code elimination) are the same.

Your Task

Implement constant folding, dead code elimination after return statements, and strength reduction for arithmetic operations. Compare bytecode size before and after optimization.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…