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] Loops add backward edges, so a control-flow graph need not be acyclic.
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]
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.
Phi node 2026-11-05
A phi node supplies the value at a join in static single-assignment form by selecting among values associated with incoming edges. In LLVM, it lists a value and predecessor basic block for each incoming edge, and phi nodes occur before ordinary operations in their block.[ref]
For example, if the left branch defines x1=10 and the right defines x2=20, the join can define x3=phi(x1,left; x2,right). Arriving from the left gives ten; arriving from the right gives twenty. It does not average the arguments or evaluate both branches. At a loop header, another phi node can select an initial value on first entry and the updated value on later iterations. The node has one static definition even though its selected value can change across executions.
Static single-assignment form is an intermediate representation in which each named value has one static definition. Repeated source assignments receive different names: x=1; x=x+2 becomes definitions such as x1=1; x2=x1+2. This makes def-use relationships explicit without requiring a search backward for which assignment supplied a value.
At a join in a control-flow graph, a phi node selects the value associated with the edge actually taken. If one branch defines x1=1 and another defines x2=2, the join defines x3=phi(x1,left; x2,right). The node selects an incoming value, not their arithmetic average. Loop-carried values similarly use entry and back-edge arguments. LLVM specifies that phi instructions occur first in a basic block, with an incoming value for each predecessor.[ref] Static uniqueness concerns program definitions, not the number of times a loop instruction executes.