[llvm] Disable pre-link LTO vectorisation and tweak LTO pipeline (PR #192068)
Momchil Velikov via llvm-commits
llvm-commits at lists.llvm.org
Tue Apr 14 07:35:25 PDT 2026
https://github.com/momchil-velikov created https://github.com/llvm/llvm-project/pull/192068
None
>From bee53014aec0dacd1339aaf6238d837a8dd7b5ea Mon Sep 17 00:00:00 2001
From: Momchil Velikov <momchil.velikov at arm.com>
Date: Mon, 9 Feb 2026 12:01:36 +0000
Subject: [PATCH] Disable pre-link LTO vectorisation and tweak LTO pipeline
---
llvm/include/llvm/Transforms/IPO/Inliner.h | 1 +
llvm/lib/Passes/PassBuilderPipelines.cpp | 92 ++++++++++---------
.../Transforms/IPO/FunctionSpecialization.cpp | 2 +-
3 files changed, 50 insertions(+), 45 deletions(-)
diff --git a/llvm/include/llvm/Transforms/IPO/Inliner.h b/llvm/include/llvm/Transforms/IPO/Inliner.h
index dd877b5cdc724..e4cb2b4f573d7 100644
--- a/llvm/include/llvm/Transforms/IPO/Inliner.h
+++ b/llvm/include/llvm/Transforms/IPO/Inliner.h
@@ -16,6 +16,7 @@
#include "llvm/Analysis/Utils/ImportedFunctionsInliningStatistics.h"
#include "llvm/IR/PassManager.h"
#include "llvm/Support/Compiler.h"
+#include "llvm/Transforms/Utils/ExtraPassManager.h"
namespace llvm {
diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp
index f017419791a85..2b443b9ebb24c 100644
--- a/llvm/lib/Passes/PassBuilderPipelines.cpp
+++ b/llvm/lib/Passes/PassBuilderPipelines.cpp
@@ -1321,16 +1321,29 @@ void PassBuilder::addVectorPasses(OptimizationLevel Level,
ThinOrFullLTOPhase LTOPhase) {
const bool IsFullLTO = LTOPhase == ThinOrFullLTOPhase::FullLTOPostLink;
- FPM.addPass(LoopVectorizePass(
- LoopVectorizeOptions(!PTO.LoopInterleaving, !PTO.LoopVectorization)));
+ if (!isLTOPreLink(LTOPhase)) {
+ FPM.addPass(LoopVectorizePass(
+ LoopVectorizeOptions(!PTO.LoopInterleaving, !PTO.LoopVectorization)));
- // Drop dereferenceable assumes after vectorization, as they are no longer
- // needed and can inhibit further optimization.
- if (!isLTOPreLink(LTOPhase))
+ // Drop dereferenceable assumes after vectorization, as they are no longer
+ // needed and can inhibit further optimization.
FPM.addPass(DropUnnecessaryAssumesPass(/*DropDereferenceable=*/true));
+ }
FPM.addPass(InferAlignmentPass());
+
+ // Eliminate loads by forwarding stores from the previous iteration to loads
+ // of the current iteration.
+ FPM.addPass(LoopLoadEliminationPass());
+
if (IsFullLTO) {
+ LoopPassManager LPM;
+
+ // Unroll small loops and perform peeling.
+ LPM.addPass(LoopFullUnrollPass(Level.getSpeedupLevel(),
+ /* OnlyWhenForced= */ !PTO.LoopUnrolling,
+ PTO.ForgetAllSCEVInLoopUnroll));
+
// The vectorizer may have significantly shortened a loop body; unroll
// again. Unroll small loops to hide loop backedge latency and saturate any
// parallel execution resources of an out-of-order processor. We also then
@@ -1340,8 +1353,11 @@ void PassBuilder::addVectorPasses(OptimizationLevel Level,
// across the loop nests.
// We do UnrollAndJam in a separate LPM to ensure it happens before unroll
if (EnableUnrollAndJam && PTO.LoopUnrolling)
- FPM.addPass(createFunctionToLoopPassAdaptor(
- LoopUnrollAndJamPass(Level.getSpeedupLevel())));
+ LPM.addPass(LoopUnrollAndJamPass(Level.getSpeedupLevel()));
+
+ FPM.addPass(createFunctionToLoopPassAdaptor(std::move(LPM),
+ /*UseMemorySSA=*/false));
+
FPM.addPass(LoopUnrollPass(LoopUnrollOptions(
Level.getSpeedupLevel(), /*OnlyWhenForced=*/!PTO.LoopUnrolling,
PTO.ForgetAllSCEVInLoopUnroll)));
@@ -1352,14 +1368,9 @@ void PassBuilder::addVectorPasses(OptimizationLevel Level,
// NOTE: we are very late in the pipeline, and we don't have any LICM
// or SimplifyCFG passes scheduled after us, that would cleanup
// the CFG mess this may created if allowed to modify CFG, so forbid that.
+ // TODO: Allow that
FPM.addPass(SROAPass(SROAOptions::PreserveCFG));
}
-
- if (!IsFullLTO) {
- // Eliminate loads by forwarding stores from the previous iteration to loads
- // of the current iteration.
- FPM.addPass(LoopLoadEliminationPass());
- }
// Cleanup after the loop optimization passes.
FPM.addPass(InstCombinePass());
@@ -1412,7 +1423,7 @@ void PassBuilder::addVectorPasses(OptimizationLevel Level,
}
// Optimize parallel scalar instruction chains into SIMD instructions.
- if (PTO.SLPVectorization) {
+ if (PTO.SLPVectorization && !isLTOPreLink(LTOPhase)) {
FPM.addPass(SLPVectorizerPass());
if (Level.getSpeedupLevel() > 1 && ExtraVectorizerPasses) {
FPM.addPass(EarlyCSEPass());
@@ -1421,32 +1432,6 @@ void PassBuilder::addVectorPasses(OptimizationLevel Level,
// Enhance/cleanup vector code.
FPM.addPass(VectorCombinePass());
- if (!IsFullLTO) {
- FPM.addPass(InstCombinePass());
- // Unroll small loops to hide loop backedge latency and saturate any
- // parallel execution resources of an out-of-order processor. We also then
- // need to clean up redundancies and loop invariant code.
- // FIXME: It would be really good to use a loop-integrated instruction
- // combiner for cleanup here so that the unrolling and LICM can be pipelined
- // across the loop nests.
- // We do UnrollAndJam in a separate LPM to ensure it happens before unroll
- if (EnableUnrollAndJam && PTO.LoopUnrolling) {
- FPM.addPass(createFunctionToLoopPassAdaptor(
- LoopUnrollAndJamPass(Level.getSpeedupLevel())));
- }
- FPM.addPass(LoopUnrollPass(LoopUnrollOptions(
- Level.getSpeedupLevel(), /*OnlyWhenForced=*/!PTO.LoopUnrolling,
- PTO.ForgetAllSCEVInLoopUnroll)));
- FPM.addPass(WarnMissedTransformationsPass());
- // Now that we are done with loop unrolling, be it either by LoopVectorizer,
- // or LoopUnroll passes, some variable-offset GEP's into alloca's could have
- // become constant-offset, thus enabling SROA and alloca promotion. Do so.
- // NOTE: we are very late in the pipeline, and we don't have any LICM
- // or SimplifyCFG passes scheduled after us, that would cleanup
- // the CFG mess this may created if allowed to modify CFG, so forbid that.
- FPM.addPass(SROAPass(SROAOptions::PreserveCFG));
- }
-
FPM.addPass(InferAlignmentPass());
FPM.addPass(InstCombinePass());
@@ -1461,6 +1446,12 @@ void PassBuilder::addVectorPasses(OptimizationLevel Level,
/*AllowSpeculation=*/true),
/*UseMemorySSA=*/true));
+ if (!isLTOPreLink(LTOPhase))
+ FPM.addPass(createFunctionToLoopPassAdaptor(
+ LoopFullUnrollPass(Level.getSpeedupLevel(),
+ /* OnlyWhenForced= */ !PTO.LoopUnrolling,
+ PTO.ForgetAllSCEVInLoopUnroll)));
+
// Now that we've vectorized and unrolled loops, we may have more refined
// alignment information, try to re-derive it here.
FPM.addPass(AlignmentFromAssumptionsPass());
@@ -2249,12 +2240,9 @@ PassBuilder::buildLTODefaultPipeline(OptimizationLevel Level,
LPM.addPass(LoopDeletionPass());
// FIXME: Add loop interchange.
- // Unroll small loops and perform peeling.
- LPM.addPass(LoopFullUnrollPass(Level.getSpeedupLevel(),
- /* OnlyWhenForced= */ !PTO.LoopUnrolling,
- PTO.ForgetAllSCEVInLoopUnroll));
// The loop passes in LPM (LoopFullUnrollPass) do not preserve MemorySSA.
// *All* loop passes must preserve it, in order to be able to use it.
+ // TODO: Enable MemorySSA for loop passes after we remove the LoopFullUnrollPass.
MainFPM.addPass(
createFunctionToLoopPassAdaptor(std::move(LPM), /*UseMemorySSA=*/false));
@@ -2307,6 +2295,22 @@ PassBuilder::buildLTODefaultPipeline(OptimizationLevel Level,
.convertSwitchToArithmetic(true)
.hoistCommonInsts(true)
.speculateUnpredictables(true)));
+
+ LateFPM.addPass(createFunctionToLoopPassAdaptor(
+ LICMPass(PTO.LicmMssaOptCap, PTO.LicmMssaNoAccForPromotionCap,
+ /*AllowSpeculation=*/true),
+ /*USeMemorySSA=*/true));
+
+ // Catch trivial redundancies
+ LateFPM.addPass(EarlyCSEPass(true /* Enable mem-ssa. */));
+
+ // Delete basic blocks, which optimization passes may have killed.
+ LateFPM.addPass(SimplifyCFGPass(SimplifyCFGOptions()
+ .convertSwitchRangeToICmp(true)
+ .convertSwitchToArithmetic(true)
+ .hoistCommonInsts(true)
+ .speculateUnpredictables(true)));
+
MPM.addPass(createModuleToFunctionPassAdaptor(std::move(LateFPM)));
// Drop bodies of available eternally objects to improve GlobalDCE.
diff --git a/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp b/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp
index 1367940ad8ef8..0d1a1d7d8072b 100644
--- a/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp
+++ b/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp
@@ -64,7 +64,7 @@ static cl::opt<unsigned> MinFunctionSize(
"instructions"));
static cl::opt<unsigned> MaxCodeSizeGrowth(
- "funcspec-max-codesize-growth", cl::init(3), cl::Hidden, cl::desc(
+ "funcspec-max-codesize-growth", cl::init(4), cl::Hidden, cl::desc(
"Maximum codesize growth allowed per function"));
static cl::opt<unsigned> MinCodeSizeSavings(
More information about the llvm-commits
mailing list