[llvm] [BFI] Solve irreducible SCCs instead of splitting their headers (PR #215170)
Fangrui Song via llvm-commits
llvm-commits at lists.llvm.org
Sat Aug 15 13:30:16 PDT 2026
MaskRay wrote:
Measured it. Dropping `hasProfileData()` and defaulting the flag on, keeping the
irreducible-CFG condition ([branch](https://llvm-compile-time-tracker.com/compare.php?from=0c2e521f8b587b0c3fb5825fb157c3938fef4ff6&to=cb1f9afc556bd732278a6d937511c3a0a03e8241&stat=instructions:u),
[same on top of this PR](https://llvm-compile-time-tracker.com/compare.php?from=0c2e521f8b587b0c3fb5825fb157c3938fef4ff6&to=90e51b02faad113603907702e5e4d1be86e75d32&stat=instructions:u)),
`instructions:u` geomean against 0c2e521f8b58:
```
inference on + this patch
stage1-O3 +3.09% +3.35%
stage1-ReleaseThinLTO +3.03% +3.55%
stage1-ReleaseLTO-g +3.65% +5.45%
stage1-aarch64-O3 +2.88% +2.99%
stage2-O3 +3.16% +3.43%
stage1-O0-g +0.00% -0.00%
clang build +0.54% +0.69%
```
sqlite3 +19.42%, ClamAV +7.69%, SPASS +4.74% at stage1-O3; SPASS reaches +23.81% at ReleaseLTO-g.
**Iterative inference costs far more than what I expected**. Rarity does not help because the cost scales with the whole function's block count, not the SCC's -- one irreducible SCC anywhere relaxes every reachable block, bounded by `1000 * block_count`, and the functions that have irreducible CFGs are the large computed-goto dispatches. On sqlite3
the only significant one is `sqlite3VdbeExec`, at 1083-2276 blocks over 7 BFI rebuilds at
IR level and 2239-2740 at MIR.
In contrast, **this patch's cost is bounded by the size of the irreducible SCC rather than by the function**. It can never be as accurate, though: the solve recovers only the SCC's stationary direction and does not model the mass arriving at each of its entries.
I also expected a better initial estimate to save inference iterations. It does not.
**The end state I am proposing is this PR (#215170) alone** at least for non-profile builds. I would also note that this is a **net decrease of number
of lines of code** and drops several bandaids (e.g.
https://reviews.llvm.org/D10348) on the initial irreducible loop handling code.
The solve is unconditional and free; inference is a 3% geomean tax that cannot
be enabled broadly without work on its cost.
On the motivation behind this work: I was learning BFI and wanted to simplify the code.
Irreducible CFGs barely exist in IR (3 of 64391
functions I sampled) and are manufactured by CodeGen -- tail duplication of computed-goto
dispatch, 22 of 221703 at MIR.
On `findReachableBlocks`: agreed, and your framing is better than mine. A reachable closed
SCC has unbounded expected counts, so `f = e + f*P` has no finite solution and declining
is correct. BFI's own path cannot decline -- it must hand placement a number for that
shape regardless -- so the two are answering different questions rather than the same one
twice. I will drop the "declines one CFG shape" wording.
On accuracy where inference runs: agreed, it is a wash (within-10% 22 -> 22, better on 60
and worse on 41). I am not claiming this improves on inference. The claim is narrower --
it improves the unconditional path, which is what every non-PGO compile uses and what
inference itself starts from.
https://github.com/llvm/llvm-project/pull/215170
More information about the llvm-commits
mailing list