Compiler optimization 2026-11-05
Compiler optimization transforms a program representation to improve a chosen resource objective while preserving the behavior required by its programming language semantics. Objectives include execution time, code size and memory traffic. A transformation need not find a globally best program, and improving one objective can worsen another.
For example, constant folding replaces
2+3 by 5, while common subexpression elimination may compute a repeated expression once. Reusing a load across a store is valid only if the store cannot change the loaded location; alias analysis helps establish that condition. Similarly, replacing floating-point (a+b)+c by a+(b+c) can change rounding, so an optimizer needs an applicable permission or proof. Data-flow analysis supplies facts used by transformations, and undefined behavior affects which executions the language requires an implementation to preserve. Control-flow graph 2026-11-05
A control-flow graph is a directed graph whose vertices represent program regions, commonly basic blocks, and whose edges represent possible immediate control transfers. It describes which execution paths the representation permits, rather than which path one particular run takes. Compiler optimization and data-flow analysis use this structure.
For
if c then x=1 else x=2; return x, use an entry vertex with edges to separate true and false basic blocks, each leading to one join basic block. The graph has a diamond shape. The join needs the incoming value selected by the executed path; static single-assignment form represents that choice using a phi node. LLVM's tutorial constructs precisely this branch-and-join structure.[ref]Kaleidoscope: Extending the Language: Control Flow in the LLVM documentation. §5.2.4, LLVM IR for If/Then/Else and control-flow graph
Loops add backward edges, so a control-flow graph need not be acyclic. Data-flow analysis 2026-11-05
Data-flow analysis propagates facts about values or variable uses through a control-flow graph. Each program operation transforms incoming facts, and a join combines information from possible predecessor paths. A compiler can use the result to justify compiler optimization or issue warnings. Clang's introduction develops this method using sets of possible values and iteration to a fixed point.[ref]
For example, live-variable analysis asks which current values might be read later before being overwritten. For a basic block , with uses before any local definition in and definitions in , the backward equations areA use requires the incoming value; an intervening definition removes that requirement. Iterating from empty sets terminates for a finite graph and finite variable set because these equations only add facts. The result guides register allocation.
LLVM Created 2026-10-14 Updated 2026-11-05
LLVM is a collection of reusable compiler infrastructure built around a typed intermediate representation. Its static single-assignment form gives each register-like value one definition, making data dependencies explicit for compiler optimization. The same intermediate representation has an in-memory form, a compact bitcode form and a readable textual form.[ref]
LLVM Language Reference Manual. Abstract, Introduction and Well-Formedness
A compiler front end translates a source programming language into the intermediate representation; optimization passes transform it while preserving the required semantics; a compiler back end produces code for a target computer architecture. Sharing the middle stages lets several source programming languages reuse the same analyses and target support. For a small textual example,
%y = add i32 %x, 1 defines a new 32-bit integer value from an earlier one. The value %y is defined once even if the source program repeatedly assigns to a source variable.