---
title: LLVM -O3 Optimization Pipeline
url: https://www.emergentmind.com/topics/llvm-o3-optimization-pipeline
type: topic
---

# LLVM -O3 Optimization Pipeline

LLVM’s `-O3` optimization pipeline is the default LLVM optimization level oriented toward runtime, implemented as an ordered pass pipeline over intermediate representation (IR). In the research literature it is described as hand-crafted by experts, general enough to work across many programs, and strong as a default code-generation baseline, yet not necessarily optimal for any particular program [2204.13261]. Empirical and methodological studies portray `-O3` not as a smooth monotone ascent in performance, but as a long, interacting, and objective-sensitive pipeline whose behavior depends on pass order, repeated canonicalization, downstream enabling effects, and workload characteristics [2606.31238].

## 1. Definition, scope, and structural model

LLVM is described as a modular compiler infrastructure in which optimization is expressed as sequences of passes. Within that framework, `-O3` is explicitly presented as hand-crafted by experts, designed to optimize for runtime, and general enough to work across many programs [2204.13261]. Several papers treat it as the canonical aggressive production pipeline: MLGOPerf describes `-O3` as having about 160 passes with many unique passes and repeated subsequences, while ACPO emphasizes that these passes execute at multiple scopes, including module, function, loop, and basic block [2207.08389] [2312.09982].

A recurrent analytical simplification is to study `-O3` as a linear pass list. That is sufficient for prefix-based measurement and pass-sequence search, but it is not the only valid representation. Work on the LLVM New Pass Manager argues that a valid modern pipeline is a hierarchy over `Module > CGSCC > Function > Loop`, rather than merely a flat sequence, and that the same pass sequence can behave differently under different valid nestings [2510.13184]. This broadens the meaning of an "`-O3` pipeline" from a textual pass list to a legality-constrained execution structure.

Inlining, loop transformation, scalar canonicalization, and instruction combining occupy a central place in this pipeline literature. MLGOPerf singles out inlining as a fundamental optimization because it removes call overhead and expands interprocedural optimization opportunities for later passes, while ACPO and related work treat Loop Unroll and Function Inlining as exemplars of high-impact profitability decisions inside an otherwise fixed `-O3` pipeline [2207.08389] [2312.09982]. A plausible implication is that `-O3` is best understood not as a single monolithic transformation, but as a coordination layer over many mutually enabling and sometimes mutually destructive suboptimizations.

## 2. Empirical anatomy of the production pipeline

A multi-dimensional empirical study of LLVM `-O3` decomposes the pipeline into cumulative per-pass prefixes. If the flattened pass sequence is \(p_0, p_1, \ldots, p_n\), it constructs prefixes
\[
P_i = p_0 \rightarrow p_1 \rightarrow \cdots \rightarrow p_i,
\]
applies each prefix independently to the same unoptimized input, and measures the resulting binaries across execution time, compile time, binary size, hardware counters, and RAPL package energy [2606.31238]. On LLVM 21.1.8, the flattened `-O3` pipeline contains 113 distinct pass invocations, including repeated passes such as `instcombine`, `simplifycfg`, and `early-cse`, and the study reports 84,750 measurements over 30 PolyBench/C kernels under rigorous noise mitigation.

The main quantitative result is that the pipeline is strongly back-loaded rather than front-loaded. Using the normalized cumulative gain
\[
G_b^i = \frac{S_b^i - 1}{S_b^* - 1} \in [0,1],
\]
the study finds that across the 27 benchmarks that do not regress overall, the median pipeline prefix needed to reach 80% of the final speedup contains 84.8% of the passes [2606.31238]. The speedup trajectory is typically S-shaped: early prefixes often do little, later prefixes produce a steep improvement, and the end of the pipeline saturates.

The same study shows that `-O3` is non-monotone. It reports 159 out of 1643 informative transitions, or 9.7% by the mean estimator, and 108 out of 1633, or 6.6% by the median estimator, as runtime regressions between adjacent prefixes [2606.31238]. Some intermediate states even outperform the final `-O3` endpoint. The dominant contributors are concentrated in a small core of passes—`early-cse`, `licm`, `instcombine`, `loop-vectorize`, and `loop-rotate`—while the long tail has near-zero marginal impact.

The study also shows that the final `-O3` configuration is Pareto-dominated on \((\text{size}, \text{speedup})\) for 29 of 30 kernels, that compile time grows near-monotonically and accelerates around loop- and inlining-heavy regions, and that binary size is itself non-monotone: early simplification and dead-code elimination often reduce size, whereas later inlining and loop unrolling can inflate it [2606.31238]. Runtime improvements are driven primarily by reductions in instruction count and total cycles, not by higher IPC; indeed IPC generally falls as the pipeline advances. On these compute-bound kernels, runtime-targeted passes are also effectively energy-targeted, with package energy savings of roughly 30–60%.

A further result with broader methodological consequences is that IR instruction count is not a reliable runtime proxy. The cross-benchmark Spearman correlation between IR count and median runtime is only \(\rho = 0.31\), and within benchmarks 27 out of 30 cases show negative \(\rho\) [2606.31238]. This directly constrains cost models that treat IR size as a dominant performance signal.

## 3. Phase ordering, interference, and local non-optimality

The literature repeatedly uses `-O3` to frame the compiler phase-ordering problem. One study estimates the search space of pass sequences at approximately \(10^{167}\), using about 120 different passes and sequences of around 80 passes long, which is used to justify why exhaustive search is infeasible [2204.13261]. Another treats the action space as subsequences of the LLVM O3 sequence, individual passes, or pass/parameter choices, underscoring that the difficulty is not merely selecting useful passes but selecting them in a useful order [2008.08951].

The central technical point is that passes interact. Targeted fuzzing work gives a concrete LLVM example: fully unrolling loops early removes opportunities for the loop vectorizer [2512.04344]. IntOpt provides an analogous optimization example: LICM hoists `D[i]` from `L_3` to `L_2'`, which then prevents `LoopInterchangePass` from swapping the `i` and `j` loops, and `LoopVectorizePass` consequently fails to vectorize the innermost loop `L_4'` [2602.18511]. These examples formalize the usual claim that a locally profitable transformation can block a more profitable downstream transformation.

This interaction structure explains why outperforming `-O3` does not imply that `-O3` is weak. Genetic-improvement work states the point explicitly: `-O3` is a very strong general-purpose baseline, but it is still a compromise pipeline, and for a specific program a small number of pass-level edits can yield measurable gains [2204.13261]. The per-pass empirical study quantifies the same phenomenon from within the default order via non-monotone prefixes and a large idealized-additive upper bound on losses due to phase interference, averaging 46.35% with median 39.3% and IQR \([30.4\%, 54.2\%]\) [2606.31238].

A related misconception is that `-O3` constitutes an exhaustive harness for testing LLVM optimizations. TargetFuzz argues that optimization pipelines are heuristics-based, fixed sequences of passes, that aggressive pipelines do not schedule all optimizations, and that many interactions are therefore never exercised [2512.04344]. In its GrayC experiment, after four hours of fuzzing through `clang -O3`, 47.5% of LLVM optimization passes were entirely untested and optimization-module coverage was only 12.12%. Across 37 sampled LLVM optimizations, targeted fuzzing effectively tested all 37, while pipeline fuzzing missed 12.

## 4. Search-based specialization around the `-O3` baseline

One major research line treats `-O3` as a baseline to be locally specialized rather than discarded. Shackleton-GI begins from the baseline LLVM `-O3` pass sequence \(S_0\) and evolves patches rather than complete pipelines [2204.13261]. Each patch has three fields: a type drawn from insertion, deletion, or replacement; a relative position between 0 and 1; and an LLVM pass name as value. The resulting individual is a patch list \(P = [p_1, p_2, \dots, p_k]\), applied as
\[
S' = P(S_0),
\]
and fitness is the mean runtime over 40 executions,
\[
f(P) = \frac{1}{40}\sum_{i=1}^{40} t_i,
\]
with 40-run averaging used to reduce noise from system fluctuations, runtime inconsistency, and unusual halting behavior [2204.13261].

On the reported target benchmark, the evolved patch-based sequences achieve a mean runtime improvement of 3.7% compared to LLVM `-O3`, with standard deviation 0.8768 and left-tail p-value against zero mean improvement of 0.000012% [2204.13261]. The paper emphasizes that one evolutionary trajectory begins with a poor individual and improves substantially over generations, while another starts closer to a good solution and stays near that quality. This suggests search as local refinement around a strong baseline rather than discovery of a radically different compiler strategy.

Deep reinforcement learning has been used to search a larger `-O3`-derived decision space. CORL defines actions as high-level O3 sub-sequences, single LLVM passes, or pass/parameter choices; in the high-level action space it partitions LLVM 3.8’s O3 sequence into 8 actions, while the middle-level space contains 42 unique passes, and the maximum number of consecutive actions is capped by \(\mu = 16\) [2008.08951]. On the training set in action space H, the agent achieves 2.24× speedup over the unoptimized baseline versus 2.17× for O3; on the validation set, O3 remains better on average at 2.67× versus 2.38×, but the learned policy still reports up to 1.32× speedup over O3 on previously unseen programs [2008.08951].

Protean generalizes this search perspective from whole-program fixed pipelines to fine-grain phase ordering inside LLVM itself. It introduces a new optimization level `-OP`, a new compilation phase `ProteanOpt`, and a modified `opt`-like tool called `protean`, replacing the fixed optimization step with an iterative agile optimization loop over module, call graph, function, or loop scopes [2602.06142]. On CBench, the paper reports average speedup gains of up to 4.1% and up to 15.7% on select applications with respect to LLVM’s O3, at the cost of extra build time measured in seconds to hundreds or thousands of seconds depending on workload and iteration budget [2602.06142]. This indicates that `-O3` can serve as a practical baseline for search-driven specialization even when the search is tightly integrated into the compiler.

## 5. Learned decisions inside an unchanged `-O3` pipeline

A second major line of work keeps the `-O3` pass order unchanged and replaces profitability decisions inside selected passes. MLGOPerf is the clearest example: it keeps the `-O3` pass sequence broadly intact, but retargets LLVM’s existing MLGO-style inliner from code-size reduction to performance optimization [2207.08389]. Its architecture combines a secondary speedup predictor, IR2Perf, with a PPO-based RL inliner. IR2Perf is a feedforward regression network with 4 fully connected linear layers, LeakyReLU activations, and layer sizes 128, 256, 32, and 1; the RL agent uses total reward as the sum of rewards generated by IR2Perf, with state as the current visiting call site and action as a Boolean inline-or-not decision [2207.08389]. Against LLVM `-O3`, MLGOPerf reports geometric means of 1.018× on SPEC CPU2006 and 1.022× on Cbench, together with code size increases of 17.8% and 12%, and up to 26% increased opportunities to autotune code regions that can be translated into an additional 3.7% speedup value [2207.08389].

ACPO makes the same architectural point in a more general compiler framework. It explicitly states that it keeps the pipeline unchanged and treats changes to pipeline ordering and optimization selection as orthogonal and outside scope [2312.09982]. Instead, it ML-enables existing `-O3` passes by intercepting profitability decision points. In Loop Unroll, LLVM legality checks remain intact while `ACPOLUModel` predicts `LU-Type` and `LU-Count`; in Function Inlining, `ACPOFIModel` predicts `FI-ShouldInline`, after legality checks and high-priority overrides [2312.09982]. The loop-unroll model is a 5-layer neural net with ReLU activations and final Softmax over unrolling counts, using 30 handcrafted LLVM-IR features. ACPO reports an average speedup of 4.07% on Polybench, a best case of 49.3% on Floyd-Warshall, and improvements on 15 of 24 benchmarks; with both Function Inlining and Loop Unroll enabled, the combined speedup reaches 4.5% on Polybench and 2.4% on Cbench versus LLVM’s O3 [2312.09982].

Instruction combining has likewise been recast as a learned component inside the standard pipeline. The Neural Instruction Combiner (NIC) replaces or augments the basic-block-level InstCombine stage with a Seq2Seq model that translates encoded unoptimized IR sequences to optimized ones, then reconstructs LLVM IR and passes it onward to downstream optimization passes [2202.12379]. Its best reported model, a 4-layer transformer with compiler-guided attention, achieves BLEU 0.94 and exact match on optimized sequences of 72%, demonstrating feasibility rather than complete replacement [2202.12379]. The significance is less a new global pipeline than a new internal decision mechanism at a critical canonicalization point.

Minotaur occupies a different position in the same ecosystem. It is loaded into LLVM as a shared library and runs as an optimization pass at the end of LLVM’s optimization pipeline; after Minotaur rewrites a fragment, LLVM’s InstCombine and Dead Code Elimination run again [2306.00229]. It is therefore not a replacement for `-O3`, but a synthesis-based post-pass intended to find opportunities missed by the standard pipeline. On SPEC CPU 2017 it reports an average speedup of 1.5% with a maximum speedup of 4.5% for `638.imagick`, and on GMP it reports an average speedup of 7.3% with a maximum speedup of 13% [2306.00229]. This illustrates a broader pattern: even after the default runtime pipeline has run, additional verified local improvements can remain.

## 6. Alternative objectives, critiques, and post-pass paradigms

Although `-O3` is designed to optimize runtime, several studies show that the pipeline is not uniquely aligned with other objectives. Compiler phase-ordering work on energy treats pass specialization as orthogonal to the standard optimization levels `-O1`, `-O2`, and `-O3`, and reports up to 24% energy reduction beyond the best standard optimization results [1807.00638]. It also emphasizes that some improvements can only be partially explained by execution-time changes and presents explicit cases where applications that run faster consume more energy. On the Xeon platform, standard optimization can reduce energy by as much as 87% versus no optimization; on ODROID, `seidel-2d` without OpenMP can use up to 13% less energy under standard optimization levels while improving performance by less than 1% [1807.00638]. The formula
\[
P = \frac{E}{\Delta t}
\]
is used to make precise that energy and average power are distinct, and that faster is not a synonym for more energy-efficient compilation.

The testing literature makes an analogous point about coverage. Pipeline-based fuzzing through `clang -O3` is convenient and end-to-end, but it is a poor surrogate for systematic testing of optimization logic because it inherits the phase-ordering problem and omits passes not scheduled in the default order [2512.04344]. Targeted fuzzing therefore complements, rather than replaces, pipeline-based testing. This suggests that the correctness surface of `-O3` extends well beyond the transformations it actually schedules.

A more radical critique rejects the pass-by-pass paradigm altogether. IntOpt characterizes LLVM-style optimization, including `-O3`, as a fixed sequence of modular passes with optimization intent implicit and fragmented across passes, and introduces an intent-driven alternative with three stages: intent formulation, intent refinement, and intent realization [2602.18511]. On a 200-program test set it reports 90.5% verified correctness and 2.660× average speedup over unoptimized IR, and it surpasses modern compiler `-O3` on 37 benchmarks with speedups of up to 272.60× [2602.18511]. The paper’s case studies—closed-form loop elimination in `chocolateFeast`, replacement of a bit-reversal loop by `llvm.bitreverse.i32` and `llvm.ctlz.i32` in `reverse_bits`, and replacement of `log10`-based digit counting with integer comparisons in `_Z3conii`—are presented as optimizations that a local pass pipeline does not infer.

Taken together, these results define the present encyclopedic understanding of LLVM `-O3`: it is a strong, carefully engineered, and widely useful default runtime pipeline; it is also a heuristic compromise with measurable non-monotonicity, phase interference, and objective-specific limitations. Research around it divides into four broad responses: per-pass empirical characterization, program-specific pass-sequence search, learned profitability decisions inside an unchanged pipeline, and post-pass or intent-driven methods that bypass classical phase ordering. The persistence of all four lines of work indicates that `-O3` remains both a baseline and a moving target in compiler research.

Source: https://www.emergentmind.com/topics/llvm-o3-optimization-pipeline