Why a compiler needs an IR
Going straight from AST to machine code sounds attractive but is a dead end. An AST is too high-level: it has no notion of registers, instruction latency, or memory layout. Raw assembly is too low-level: optimizations written against x86 opcodes have to be rewritten for ARM.
An intermediate representation (IR) sits in the middle. It's:
- Low enough that optimizations are machine-agnostic (no registers yet, but no tree structure either).
- High enough that analysis is still easy (explicit data flow, no aliasing ambiguity in SSA).
- Retargetable: write one set of optimizations, compile to any target by swapping the back-end.
LLVM IR is the canonical example: one optimizer, dozens of targets (x86, ARM, WASM, RISC-V). GCC uses GIMPLE then RTL. The IR phase is what makes the compiler problem into .
