Lesson 5 of 7

Optimization

Optimizers rewrite a program in many small steps that keep its behavior the same but make it faster. You'll see the common passes and what they mean for how you write code.

Text
What -O2 does to your code (each pass, repeatedly):

  constant folding     3 * 60          ->  180
  constant propagation x=5; y=x+1      ->  y=6
  dead code removal    if(false){...}  ->  (gone)
  common subexpression (a*b) + (a*b)   ->  t=a*b; t+t
  function inlining    call sq(x)      ->  x*x  (no call)
  loop invariant hoist for(...){k=n*4} ->  k=n*4; for(...)
  strength reduction   i * 2           ->  i << 1
  loop unrolling       4 iterations    ->  straight-line code
  vectorization        sum loop        ->  SIMD: 8 adds/instr

Passes enable each other: inlining exposes constants,
folding kills branches, killing branches exposes more.
That's why they run in a loop until nothing changes.
C
// Try on godbolt.org — gcc -O2:
int sum_to(int n) {
    int total = 0;
    for (int i = 1; i <= n; i++)
        total += i;
    return total;
}

// The compiler recognizes the pattern and emits the
// CLOSED FORM — no loop at all:
//   n * (n + 1) / 2   (a few instructions, O(1))

// And this function:
int always_42(void) {
    int x = 6, y = 7;
    return x * y;
}
// compiles to:
//   mov eax, 42
//   ret

The contract is the 'as-if' rule: the optimizer may do anything as long as observable behavior is unchanged. This is also where behavior matters most — in C, signed overflow is UB, so the assumes it never happens and deletes your 'if (x + 1 < x)' overflow check as dead code. The optimizer is simply applying the language's rules.

Finished reading?Mark it done to track your progress.

Tip: use the ← and → keys to move between lessons.