[llvm] [LoopFusion] Document LoopFusion Pass (PR #192926)
Nikita Popov via llvm-commits
llvm-commits at lists.llvm.org
Mon Apr 20 03:16:44 PDT 2026
================
@@ -0,0 +1,491 @@
+====================================================
+Loop Fusion in LLVM
+====================================================
+
+1. Introduction
+===============
+
+Loop fusion (also called loop jamming) is a compiler optimization that
+merges two adjacent loops into a single loop, provided the
+transformation preserves the program's original semantics. The
+motivation is straightforward: by executing the bodies of two loops in
+a single pass over the iteration space, we reduce loop overhead (fewer
+branch instructions, fewer induction variable updates), improve
+temporal data locality (data written by the first loop body and read
+by the second is still in cache), and create new opportunities for
+subsequent optimizations such as instruction scheduling and register
+allocation.
+
+LLVM's implementation resides in
+``llvm/lib/Transforms/Scalar/LoopFuse.cpp`` and is based on
+Christopher Barton's MSc thesis, *"Code Transformations to Augment the
+Scope of Loop Fusion in a Production Compiler"*. The pass operates one
+LLVM IR, leveraging several core analysis frameworks --
+Scalar Evolution (SCEV), Dependence Analysis
+(DA), and Dominator/Post-Dominator Trees -- to determine legality and
+perform the CFG rewiring that fuses two loops into one.
+
+2. Prerequisite Concepts
+========================
+
+Before describing the algorithm, we define the terms and LLVM IR
+concepts it relies on.
+
+2.1 Loop Canonical Form (Simplified Form)
+------------------------------------------
+
+A loop in LLVM is said to be in *simplified form*
+(``Loop::isLoopSimplifyForm()``) when it satisfies three structural
+properties:
+
+1. **Preheader**: A single basic block that is the sole predecessor
+ of the loop header from outside the loop. It serves as the "entry
+ gate" and is a convenient place to hoist loop-invariant
+ computations.
+2. **Dedicated exit blocks**: Every exit block (a block outside the
+ loop reached from inside) has all its predecessors inside the loop.
+3. **Single latch**: Exactly one back-edge targets the header. The
+ block that contains this back-edge is called the *latch*.
+
+2.2 Rotated Form
+-----------------
+
+A loop is in *rotated form* (``Loop::isRotatedForm()``) when the
+latch block is a conditional branch that decides whether to re-enter
+the header or exit the loop. In source-level terms, this corresponds
+to a do-while style loop. Loop rotation transforms a while-loop
+(guard-test-at-top) into a do-while (test-at-bottom), which is the
+form the loop fusion pass requires.
+
+2.3 Loop Guard
+--------------
+
+Some loops are preceded by a *guard branch* -- a conditional branch
+that checks whether the loop should execute at all (e.g., when the
+trip count might be zero). The guard branch sits before the preheader
+and either jumps to the preheader (entering the loop) or to a
+*non-loop block* that bypasses the loop entirely. The pass must handle
+both guarded and unguarded loops.
+
+2.4 Dominator and Post-Dominator Trees
+---------------------------------------
+
+The *dominator tree* (DT) encodes the dominance relation: basic block
+A *dominates* B if every path from the function entry to B must pass
+through A. The *post-dominator tree* (PDT) is the dual: A
+*post-dominates* B if every path from B to the function exit must pass
+through A.
+
+Two blocks are *control-flow equivalent* if each dominates and
+post-dominates the other. If loop L0 dominates loop L1 and L1
+post-dominates L0, then whenever one executes, the other is guaranteed
+to execute as well. This is a necessary condition for fusion.
+
+2.5 Scalar Evolution (SCEV)
+----------------------------
+
+SCEV is LLVM's framework for symbolically analyzing how scalar
+expressions evolve across loop iterations. It can express induction
+variables, trip counts, and pointer access functions as closed-form
+recurrences. The fusion pass uses SCEV to:
+
+- Compute and compare loop trip counts (backedge-taken counts).
+- Rewrite access functions from one loop into the iteration space of
+ another to compare memory addresses.
+
+2.6 Dependence Analysis (DA)
+-----------------------------
+
+DA determines the dependence relation between pairs of memory
+accesses. A dependence from instruction S1 to S2 is characterized by:
+
+- **Flow (true) dependence**: S1 writes, S2 reads the same location
+ (read-after-write).
+- **Anti dependence**: S1 reads, S2 writes (write-after-read).
+- **Output dependence**: Both S1 and S2 write (write-after-write).
+
+Each dependence carries a *direction vector* at each loop nesting
+level, indicating whether the source iteration is less than (``<``),
+equal to (``=``), or greater than (``>``) the sink iteration at that
+level. A dependence with a ``>`` component at the current loop level
+represents a *backward loop-carried dependence* (also called a
+negative-distance dependence). Such dependences are the critical
+hazard that loop fusion must respect.
+
+2.7 Trip Count and Peeling
+---------------------------
+
+The *trip count* is the number of times the loop body executes. Two
+loops can only be fused if they iterate the same number of times. When
+trip counts differ by a small constant, the pass can *peel* iterations
+from the first loop -- extracting leading iterations into
+straight-line code before the loop -- to equalize the counts.
+
+
+3. High-Level Algorithm
+=======================
+
+The pass operates in a top-down, level-by-level fashion over the loop
+nest tree. At each nesting depth, it:
+
+1. **Collects fusion candidates**: Wraps each eligible loop in a
+ ``FusionCandidate`` structure, then groups candidates into lists of
+ *control-flow equivalent, strictly adjacent* loops sorted in
+ dominance order.
+2. **Attempts pairwise fusion**: Walks each candidate list linearly,
+ testing every consecutive pair ``(FC0, FC1)`` against the four
+ legality conditions. If all conditions hold, the pair is fused and
+ replaced by a single new candidate in the list, which is then
+ considered for further fusion with its neighbor.
+3. **Descends to inner loops**: After processing all sibling groups at
+ the current depth, the pass descends one level and repeats.
+
+This strategy means outermost loops are fused first. Fusing inner
+loops is handled in subsequent iterations of the outer while-loop.
+
+
+4. Data Structures
+==================
+
+4.1 FusionCandidate
+--------------------
+
+This is the central abstraction. It caches loop components that are
+queried repeatedly:
+
+.. list-table::
+ :header-rows: 1
+ :widths: 25 75
+
+ * - Field
+ - Description
+ * - ``Preheader``
----------------
nikic wrote:
FWIW, this kind of detailed member listing tends to get outdated quickly. I'd give a more high level description like "metadata related to the loop, as well as memory accessing instructions in the loop, and loop peeling information" or something.
https://github.com/llvm/llvm-project/pull/192926
More information about the llvm-commits
mailing list