8.1 Basic Blocks, Flow Graphs & Control Flow Analysis
💡 Core Intuition: The 3-Second Mental Model
🍳 The Everyday Analogy: The Train Stations and Railway Track Network
Imagine a high-speed railway transit network:
- Instruction Stream: A single continuous stretch of track.
- Basic Block (The Non-Stop Express Run): A straight segment of railway track between two stations with zero switches, zero junctions, and zero siding tracks. If a train passes the entry signal, it is physically impossible for it to derail or turn off until it reaches the final station. It executes strictly all-or-nothing.
- Leader (The Station Platform): The very first point where a train can enter the straight track.
- Control Flow Graph (CFG): The global schematic map of the entire railway network, showing every junction, switch, loop, and bypass connecting these straight express segments.
💻 Bridging to Computer Science: Leader Identification and Control Flow Graph Topology
In code optimization and target code generation:
- A flat linear stream of Three-Address Code is partitioned into maximal straight-line sequences called Basic Blocks.
- Within a basic block, execution is strictly sequential: if the first instruction executes, all subsequent instructions are guaranteed to execute in order.
- By abstracting instructions into basic blocks and representing jumps as directed edges, the compiler constructs a Control Flow Graph (CFG).
- Analyzing the CFG allows the compiler to detect loops, compute dominators, and trace live variable ranges for register allocation.
📑Table of Contents
- 🏗️ Architectural Foundations: Linear Stream vs Control Flow Graph
- 📐 Formal Foundations: Basic Blocks & Leader Identification
- 🏗️ Architecture & Execution Mechanics: Constructing the Control Flow Graph
- 👑 Dominators, Dominator Trees & Natural Loops
- 🏭 Real-World Production Context: How Industry Builds This
- 📐 Numerical Applications & Worked Examples
- 🎯 Exam & Interview Pitfall Check
🏗️ Architectural Foundations: Linear Stream vs Control Flow Graph
Linear Instruction Stream vs Control Flow Graph (CFG)
Transforming flat assembly into a structured mathematical graph
Linear Instruction Stream
- •Unstructured sequential array of instructions with arbitrary goto jumps.
- •Difficult to reason about variable lifetimes and loop boundaries.
- •High risk of instruction reordering bugs due to hidden jump targets.
- •Poor platform for automated global optimizations.
Control Flow Graph (CFG)
- •Nodes are atomic basic blocks; edges represent permissible branch transitions.
- •Clear demarcation of loop headers, preheaders, and exit blocks.
- •Enables rigorous dataflow analysis (liveness, reaching definitions).
- •Directly supports dominator tree construction and SSA form.
📐 Formal Foundations: Basic Blocks & Leader Identification
A Basic Block is a maximal sequence of consecutive three-address instructions satisfying two strict properties:
- Single Entry: Control enters the sequence only through the first instruction. There is no instruction inside the block (other than the first) that can be the target of a jump from anywhere in the program.
- Single Exit: Control leaves the sequence without halting or branching except possibly at the very last instruction of the block.
🎯 The 3 Leader Identification Rules
To partition any three-address instruction stream into basic blocks, the compiler first identifies all Leaders (the initial instruction of each basic block):
The 3 Canonical Leader Identification Rules
Determining the entry points of all atomic basic blocks
Program Origin
The very first instruction of the three-address program is ALWAYS a leader.
Branch Targets
Any instruction that is the TARGET of a conditional or unconditional jump is a leader.
Post-Branch Fallthrough
Any instruction immediately FOLLOWING a conditional or unconditional jump is a leader.
Formal Algorithm: Partitioning into Basic Blocks
- Find Leaders: Apply Rules 1, 2, and 3 across all instructions in the program.
- Form Blocks: For each leader instruction :
- Its basic block consists of and all subsequent instructions up to, but not including, the next leader (or the end of the program).
🏗️ Architecture & Execution Mechanics: Constructing the Control Flow Graph
Once basic blocks are identified, the compiler constructs a directed graph , called the Control Flow Graph (CFG):
- Vertices (): The set of basic blocks , augmented with two virtual nodes:
ENTRYandEXIT. - Directed Edges (): A directed edge exists if and only if control can pass from the last instruction of to the first instruction of .
🚦 Conditions for a Directed Edge Between Basic Blocks
An edge exists if either of the following holds:
- Explicit Branch: The last instruction of is a conditional or unconditional jump targeting the first instruction (the leader) of .
- Fallthrough: immediately follows in physical program order, and does NOT end in an unconditional jump (
goto).
👑 Dominators, Dominator Trees & Natural Loops
Control flow optimization requires identifying loops mechanically from arbitrary flow graphs.
1️⃣ The Dominator Relation (dom)
A node dominates a node (written ) if every path from the ENTRY node to in the CFG must pass through .
Mathematical Properties:
- Reflexive: Every node dominates itself ().
- Transitive: If and , then .
- Antisymmetric: If and , then .
2️⃣ Immediate Dominator (idom)
The Immediate Dominator of node (denoted ) is the unique strict dominator of that is dominated by all other strict dominators of . The tree formed by edges is the Dominator Tree.
3️⃣ Back Edges & Natural Loops
- The node is the Loop Header (the single entry point to the loop).
- Identifying back edges is the formal mechanism compilers use to find all reducible loops for loop-invariant code motion and loop unrolling.
🏭 Real-World Production Context: How Industry Builds This
In modern industrial production compilers (such as LLVM and GCC):
In the LLVM Compiler Infrastructure:
- A function (
llvm::Function) is physically stored as an ilist ofllvm::BasicBlockobjects. - Every
BasicBlockmust end with a mandatory Terminator Instruction (BranchInst,ReturnInst, orSwitchInst). - Fallthroughs are explicitly represented as unconditional branches (
br label %next_bb). - This guarantees that basic blocks cannot be malformed during optimization passes.
Engineers can inspect compiler control flow by generating Graphviz diagrams directly:
opt -dot-cfg input.ll
dot -Tpng cfg.func.dot -o cfg.png
This renders basic blocks, branch conditions, and loop headers as interactive SVG/PNG graphs.
📐 Numerical Applications & Worked Examples
Example 1: Rigorous Leader Identification & Block Partitioning
Consider the following three-address code representing dot-product calculation:
(1) prod = 0
(2) i = 1
(3) t1 = 4 * i
(4) t2 = a[t1]
(5) t3 = 4 * i
(6) t4 = b[t3]
(7) t5 = t2 * t4
(8) t6 = prod + t5
(9) prod = t6
(10) t7 = i + 1
(11) i = t7
(12) if i <= 20 goto (3)
(13) return prod
Identify:
- All leader instructions with explicit rule justifications.
- The complete set of basic blocks.
- The transition adjacency list for the Control Flow Graph.
Step-by-Step Analytical Solution:
Step 1: Leader Identification
- Instruction (1): Leader by Rule 1 (first instruction of the program).
- Instruction (3): Leader by Rule 2 (target of conditional jump at instruction 12:
goto (3)). - Instruction (13): Leader by Rule 3 (instruction immediately following conditional jump at instruction 12).
No other jump statements exist in the program. Therefore, the leaders are:
Step 2: Basic Block Partitioning
- Block (Leader 1 up to before Leader 3):
- Instructions (1) to (2):
(1) prod = 0
(2) i = 1
- Instructions (1) to (2):
- Block (Leader 3 up to before Leader 13):
- Instructions (3) to (12):
(3) t1 = 4 * i
(4) t2 = a[t1]
(5) t3 = 4 * i
(6) t4 = b[t3]
(7) t5 = t2 * t4
(8) t6 = prod + t5
(9) prod = t6
(10) t7 = i + 1
(11) i = t7
(12) if i <= 20 goto (3)
- Instructions (3) to (12):
- Block (Leader 13 to end of program):
- Instruction (13):
(13) return prod
- Instruction (13):
Step 3: CFG Adjacency Transitions
- From : Control falls through unconditionally to .
- Edge: .
- From :
- If condition is true: jumps to instruction (3) (head of ).
- If condition is false: falls through to instruction (13) (head of ).
- Edges: (self-loop) and .
- From : Program terminates.
- Edge: .
Example 2: Dominator Analysis on a Multi-Path Flow Graph
Consider a CFG with nodes and initial entry node :
- Edges:
Determine:
- The dominator set for each node.
- The Immediate Dominator for each node.
- Identify whether edge is a back edge.
Step-by-Step Analytical Trace:
Step 1: Compute Dominator Sets
| Node | Paths from Entry () to | Dominator Set |
|---|---|---|
| 1 | ||
| 2 | ||
| 3 | , | |
| 4 | , | |
| 5 | ||
| 6 | , | |
| 7 | All paths pass through 6 | |
| 8 | All paths pass through 7 |
Notice that node 4 can be reached via 2 or 3. Hence neither 2 nor 3 dominates 4. Only 1 and 4 dominate node 4.
Step 2: Immediate Dominators
Step 3: Back Edge Evaluation
- Consider edge :
- By definition, is a back edge if and only if .
- However, . Node 3 is NOT in !
- Why? Because path bypasses node 3 completely!
- Therefore, is NOT a back edge, and the cycle is an irreducible cycle.
🎯 Exam & Interview Pitfall Check
Question 1: "Why is the instruction immediately following a conditional or unconditional jump guaranteed to be a leader?"
Key Focus Points:
- Rule 3 Logic: A basic block has a single exit. Since a jump instruction represents an exit from the current block, the next instruction cannot be executed as part of that same straight-line sequence.
- It represents the fallthrough target (for conditional jumps) or the start of a new block reached by another jump, and must therefore begin a new basic block.
Question 2: "What is the exact definition of a natural loop in terms of dominators?"
Key Focus Points:
- A natural loop is defined by a back edge where .
- The natural loop consists of (the loop header) plus all nodes that can reach through a path that does not pass through .
Trap 1: Forgetting Rule 3 and merging post-jump instructions.
Answer: Critical partitioning error. Failing to apply Rule 3 erroneously combines the instruction following a jump into the preceding basic block, giving the block multiple exits or internal jump targets and corrupting subsequent optimization passes.
Trap 2: Assuming every cycle in a CFG is a natural loop.
Answer: False. A cycle is only a natural loop if it has a unique entry point (a single loop header that dominates all nodes in the cycle). Cycles with multiple entry points are irreducible flow graphs and do not possess a single back edge.