[Passes] Replace OptimizationLevel with an enum (#209424)

Now that OptimizationLevel no longer has a size dimension, replace it
with a simple enum class.
This commit is contained in:
Alexis Engelke 2026-07-14 13:24:29 +02:00 committed by GitHub
parent b4b19c8f0c
commit 5d5dd83a54
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 43 additions and 82 deletions

View file

@ -68,7 +68,7 @@ void addCfgConversionPass(mlir::PassManager &pm,
void addAVC(mlir::PassManager &pm, const llvm::OptimizationLevel &optLevel) {
ArrayValueCopyOptions options;
options.optimizeConflicts = optLevel.isOptimizingForSpeed();
options.optimizeConflicts = optLevel != llvm::OptimizationLevel::O0;
addNestedPassConditionally<mlir::func::FuncOp>(
pm, disableFirAvc, [&]() { return createArrayValueCopyPass(options); });
}
@ -210,7 +210,7 @@ void createDefaultFIROptimizerPassPipeline(mlir::PassManager &pm,
pm, fir::createCharacterConversion);
pm.addPass(mlir::createCanonicalizerPass(config));
pm.addPass(fir::createSimplifyRegionLite());
if (pc.OptLevel.isOptimizingForSpeed()) {
if (pc.OptLevel != llvm::OptimizationLevel::O0) {
// These passes may increase code size.
pm.addPass(fir::createSimplifyIntrinsics());
pm.addPass(fir::createAlgebraicSimplificationPass(config));
@ -235,7 +235,7 @@ void createDefaultFIROptimizerPassPipeline(mlir::PassManager &pm,
pm.addPass(mlir::createCSEPass());
// Run LICM after CSE, which may reduce the number of operations to hoist.
if (enableFirLICM && pc.OptLevel.isOptimizingForSpeed())
if (enableFirLICM && pc.OptLevel != llvm::OptimizationLevel::O0)
pm.addPass(fir::createLoopInvariantCodeMotion());
// Polymorphic types
@ -244,13 +244,14 @@ void createDefaultFIROptimizerPassPipeline(mlir::PassManager &pm,
// Optimize redundant array repacking operations,
// if the source is known to be contiguous.
if (pc.OptLevel.isOptimizingForSpeed())
if (pc.OptLevel != llvm::OptimizationLevel::O0)
pm.addPass(fir::createOptimizeArrayRepacking());
pm.addPass(fir::createLowerRepackArraysPass());
// Expand FIR operations that may use SCF dialect for their
// implementation. This is a mandatory pass.
pm.addPass(fir::createSimplifyFIROperations(
{/*preferInlineImplementation=*/pc.OptLevel.isOptimizingForSpeed()}));
{/*preferInlineImplementation=*/pc.OptLevel !=
llvm::OptimizationLevel::O0}));
addNestedPassToAllTopLevelOperations<PassConstructor>(
pm, fir::createStackReclaim);
@ -264,7 +265,7 @@ void createDefaultFIROptimizerPassPipeline(mlir::PassManager &pm,
pm.addPass(fir::createConvertComplexPow());
pm.addPass(mlir::createCSEPass());
if (pc.OptLevel.isOptimizingForSpeed())
if (pc.OptLevel != llvm::OptimizationLevel::O0)
pm.addPass(fir::createSetRuntimeCallAttributes());
// Last Optimizer EP Callback
@ -280,11 +281,9 @@ void createHLFIRToFIRPassPipeline(mlir::PassManager &pm,
EnableOpenMP enableOpenMP,
const MLIRToLLVMPassPipelineConfig &config) {
llvm::OptimizationLevel optLevel = config.OptLevel;
if (optLevel.getSpeedupLevel() > 0) {
if (optLevel != llvm::OptimizationLevel::O0) {
addNestedPassToAllTopLevelOperations<PassConstructor>(
pm, hlfir::createExpressionSimplification);
}
if (optLevel.isOptimizingForSpeed()) {
addCanonicalizerPassWithoutRegionSimplification(pm);
addNestedPassToAllTopLevelOperations(pm, [&]() {
return hlfir::createSimplifyHLFIRIntrinsics(
@ -295,7 +294,7 @@ void createHLFIRToFIRPassPipeline(mlir::PassManager &pm,
pm, hlfir::createInlineElementals);
addNestedPassToAllTopLevelOperations<PassConstructor>(
pm, hlfir::createSeparateAllocatableAssign);
if (optLevel.isOptimizingForSpeed()) {
if (optLevel != llvm::OptimizationLevel::O0) {
addCanonicalizerPassWithoutRegionSimplification(pm);
pm.addPass(mlir::createCSEPass());
// Run SimplifyHLFIRIntrinsics pass late after CSE,
@ -328,7 +327,7 @@ void createHLFIRToFIRPassPipeline(mlir::PassManager &pm,
});
}
pm.addPass(hlfir::createLowerHLFIROrderedAssignments(
{/*tryFusingAssignments=*/optLevel.isOptimizingForSpeed()}));
{/*tryFusingAssignments=*/optLevel != llvm::OptimizationLevel::O0}));
pm.addPass(hlfir::createLowerHLFIRIntrinsics());
hlfir::BufferizeHLFIROptions bufferizeOptions;
@ -336,7 +335,7 @@ void createHLFIRToFIRPassPipeline(mlir::PassManager &pm,
// from hlfir.elemental lowering, if the result is an empty array.
// This helps to avoid long running loops for elementals with
// shapes like (0, HUGE).
if (optLevel.isOptimizingForSpeed())
if (optLevel != llvm::OptimizationLevel::O0)
bufferizeOptions.optimizeEmptyElementals = true;
pm.addPass(hlfir::createBufferizeHLFIR(bufferizeOptions));
// Run hlfir.assign inlining again after BufferizeHLFIR,
@ -346,7 +345,7 @@ void createHLFIRToFIRPassPipeline(mlir::PassManager &pm,
// TODO: we can remove the previous InlineHLFIRAssign, when
// FIR AliasAnalysis is good enough to say that a temporary
// array does not alias with any user object.
if (optLevel.isOptimizingForSpeed())
if (optLevel != llvm::OptimizationLevel::O0)
addNestedPassToAllTopLevelOperations<PassConstructor>(
pm, hlfir::createInlineHLFIRAssign);
pm.addPass(hlfir::createConvertHLFIRtoFIR());
@ -406,7 +405,7 @@ void createDefaultFIRCodeGenPassPipeline(mlir::PassManager &pm,
llvm::StringRef inputFilename) {
pm.addPass(fir::createMIFOpConversion());
fir::addBoxedProcedurePass(pm, config.EnableSafeTrampoline);
if (config.OptLevel.isOptimizingForSpeed() && config.AliasAnalysis &&
if (config.OptLevel != llvm::OptimizationLevel::O0 && config.AliasAnalysis &&
!disableFirAliasTags && !useOldAliasTags)
pm.addPass(fir::createAddAliasTags());
addNestedPassToAllTopLevelOperations<PassConstructor>(
@ -446,8 +445,8 @@ void createDefaultFIRCodeGenPassPipeline(mlir::PassManager &pm,
// TODO: re-enable setNoAlias by default (when optimizing for speed) once
// function specialization is fixed.
bool setNoAlias = forceNoAlias;
bool setNoCapture = config.OptLevel.isOptimizingForSpeed();
bool setReadOnly = config.OptLevel.isOptimizingForSpeed();
bool setNoCapture = config.OptLevel != llvm::OptimizationLevel::O0;
bool setReadOnly = config.OptLevel != llvm::OptimizationLevel::O0;
pm.addPass(fir::createFunctionAttr(
{framePointerKind, config.InstrumentFunctionEntry,

View file

@ -20,20 +20,11 @@
namespace llvm {
class OptimizationLevel final {
unsigned SpeedLevel = 2;
OptimizationLevel(unsigned SpeedLevel) : SpeedLevel(SpeedLevel) {
// Check that only valid values are passed.
assert(SpeedLevel <= 3 &&
"Optimization level for speed should be 0, 1, 2, or 3");
}
public:
OptimizationLevel() = default;
enum class OptimizationLevel {
/// Disable as many optimizations as possible. This doesn't completely
/// disable the optimizer in all cases, for example always_inline functions
/// can be required to be inlined for correctness.
LLVM_ABI static const OptimizationLevel O0;
O0 = 0,
/// Optimize quickly without destroying debuggability.
///
@ -49,7 +40,8 @@ public:
/// vectorization, or fusion don't make sense here due to the degree to
/// which the executed code differs from the source code, and the compile
/// time cost.
LLVM_ABI static const OptimizationLevel O1;
O1 = 1,
/// Optimize for fast execution as much as possible without triggering
/// significant incremental compile time or code size growth.
///
@ -66,7 +58,7 @@ public:
///
/// This is expected to be a good default optimization level for the vast
/// majority of users.
LLVM_ABI static const OptimizationLevel O2;
O2 = 2,
/// Optimize for fast execution as much as possible.
///
/// This mode is significantly more aggressive in trading off compile time
@ -81,18 +73,7 @@ public:
/// order to make even significantly slower compile times at least scale
/// reasonably. This does not preclude very substantial constant factor
/// costs though.
LLVM_ABI static const OptimizationLevel O3;
bool isOptimizingForSpeed() const { return SpeedLevel > 0; }
bool operator==(const OptimizationLevel &Other) const {
return SpeedLevel == Other.SpeedLevel;
}
bool operator!=(const OptimizationLevel &Other) const {
return SpeedLevel != Other.SpeedLevel;
}
unsigned getSpeedupLevel() const { return SpeedLevel; }
O3 = 3,
};
} // namespace llvm

View file

@ -14,7 +14,6 @@ namespace llvm {
class Module;
class ModulePass;
class OptimizationLevel;
enum class ExpandVariadicsMode {
Unspecified, // Use the implementation defaults

View file

@ -1,6 +1,5 @@
add_llvm_component_library(LLVMPasses
CodeGenPassBuilder.cpp
OptimizationLevel.cpp
PassBuilder.cpp
PassBuilderBindings.cpp
PassBuilderPipelines.cpp

View file

@ -1,16 +0,0 @@
//===- OptimizationLevel.cpp ----------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "llvm/Passes/OptimizationLevel.h"
using namespace llvm;
const OptimizationLevel OptimizationLevel::O0 = {0};
const OptimizationLevel OptimizationLevel::O1 = {1};
const OptimizationLevel OptimizationLevel::O2 = {2};
const OptimizationLevel OptimizationLevel::O3 = {3};

View file

@ -892,7 +892,7 @@ Expected<LoopUnrollOptions> parseLoopUnrollOptions(StringRef Params) {
std::tie(ParamName, Params) = Params.split(';');
std::optional<OptimizationLevel> OptLevel = parseOptLevel(ParamName);
if (OptLevel) {
UnrollOpts.setOptLevel(OptLevel->getSpeedupLevel());
UnrollOpts.setOptLevel(static_cast<int>(*OptLevel));
continue;
}
if (ParamName.consume_front("full-unroll-max=")) {
@ -2064,8 +2064,8 @@ PassBuilder::parsePipelineText(StringRef Text) {
static void setupOptionsForPipelineAlias(PipelineTuningOptions &PTO,
OptimizationLevel L) {
PTO.LoopVectorization = L.getSpeedupLevel() > 1;
PTO.SLPVectorization = L.getSpeedupLevel() > 1;
PTO.LoopVectorization = L >= OptimizationLevel::O2;
PTO.SLPVectorization = L >= OptimizationLevel::O2;
}
Error PassBuilder::parseModulePass(ModulePassManager &MPM,

View file

@ -570,7 +570,7 @@ PassBuilder::buildO1FunctionSimplificationPipeline(OptimizationLevel Level,
// attention to it.
if (!isThinLTOPreLink(Phase) || !PGOOpt ||
PGOOpt->Action != PGOOptions::SampleUse)
LPM2.addPass(LoopFullUnrollPass(Level.getSpeedupLevel(),
LPM2.addPass(LoopFullUnrollPass(static_cast<int>(Level),
/* OnlyWhenForced= */ !PTO.LoopUnrolling,
PTO.ForgetAllSCEVInLoopUnroll));
@ -630,7 +630,7 @@ PassBuilder::buildFunctionSimplificationPipeline(OptimizationLevel Level,
// The O1 pipeline has a separate pipeline creation function to simplify
// construction readability.
if (Level.getSpeedupLevel() == 1)
if (Level == OptimizationLevel::O1)
return buildO1FunctionSimplificationPipeline(Level, Phase);
FunctionPassManager FPM;
@ -752,7 +752,7 @@ PassBuilder::buildFunctionSimplificationPipeline(OptimizationLevel Level,
// attention to it.
if (!isThinLTOPreLink(Phase) || !PGOOpt ||
PGOOpt->Action != PGOOptions::SampleUse)
LPM2.addPass(LoopFullUnrollPass(Level.getSpeedupLevel(),
LPM2.addPass(LoopFullUnrollPass(static_cast<int>(Level),
/* OnlyWhenForced= */ !PTO.LoopUnrolling,
PTO.ForgetAllSCEVInLoopUnroll));
@ -963,7 +963,7 @@ void PassBuilder::addPGOInstrPassesForO0(ModulePassManager &MPM,
}
static InlineParams getInlineParamsFromOptLevel(OptimizationLevel Level) {
return getInlineParamsFromOptLevel(Level.getSpeedupLevel());
return getInlineParamsFromOptLevel(static_cast<unsigned>(Level));
}
ModuleInlinerWrapperPass
@ -1368,9 +1368,9 @@ void PassBuilder::addVectorPasses(OptimizationLevel Level,
// We do UnrollAndJam in a separate LPM to ensure it happens before unroll
if (EnableUnrollAndJam && PTO.LoopUnrolling)
FPM.addPass(createFunctionToLoopPassAdaptor(
LoopUnrollAndJamPass(Level.getSpeedupLevel())));
LoopUnrollAndJamPass(static_cast<int>(Level))));
FPM.addPass(LoopUnrollPass(LoopUnrollOptions(
Level.getSpeedupLevel(), /*OnlyWhenForced=*/!PTO.LoopUnrolling,
static_cast<int>(Level), /*OnlyWhenForced=*/!PTO.LoopUnrolling,
PTO.ForgetAllSCEVInLoopUnroll)));
FPM.addPass(WarnMissedTransformationsPass());
// Now that we are done with loop unrolling, be it either by LoopVectorizer,
@ -1399,7 +1399,7 @@ void PassBuilder::addVectorPasses(OptimizationLevel Level,
// Cleanup after the loop optimization passes.
FPM.addPass(InstCombinePass());
if (Level.getSpeedupLevel() > 1 && ExtraVectorizerPasses) {
if (Level > OptimizationLevel::O1 && ExtraVectorizerPasses) {
ExtraFunctionPassManager<ShouldRunExtraVectorPasses> ExtraPasses;
// At higher optimization levels, try to clean up any runtime overlap and
// alignment checks inserted by the vectorizer. We want to track correlated
@ -1450,7 +1450,7 @@ void PassBuilder::addVectorPasses(OptimizationLevel Level,
// Optimize parallel scalar instruction chains into SIMD instructions.
if (PTO.SLPVectorization) {
FPM.addPass(SLPVectorizerPass());
if (Level.getSpeedupLevel() > 1 && ExtraVectorizerPasses) {
if (Level >= OptimizationLevel::O2 && ExtraVectorizerPasses) {
FPM.addPass(EarlyCSEPass());
}
}
@ -1468,10 +1468,10 @@ void PassBuilder::addVectorPasses(OptimizationLevel Level,
// We do UnrollAndJam in a separate LPM to ensure it happens before unroll
if (EnableUnrollAndJam && PTO.LoopUnrolling) {
FPM.addPass(createFunctionToLoopPassAdaptor(
LoopUnrollAndJamPass(Level.getSpeedupLevel())));
LoopUnrollAndJamPass(static_cast<int>(Level))));
}
FPM.addPass(LoopUnrollPass(LoopUnrollOptions(
Level.getSpeedupLevel(), /*OnlyWhenForced=*/!PTO.LoopUnrolling,
static_cast<int>(Level), /*OnlyWhenForced=*/!PTO.LoopUnrolling,
PTO.ForgetAllSCEVInLoopUnroll)));
FPM.addPass(WarnMissedTransformationsPass());
// Now that we are done with loop unrolling, be it either by LoopVectorizer,
@ -2091,7 +2091,7 @@ PassBuilder::buildLTODefaultPipeline(OptimizationLevel Level,
// libraries and other oracles.
MPM.addPass(InferFunctionAttrsPass());
if (Level.getSpeedupLevel() > 1) {
if (Level >= OptimizationLevel::O2) {
MPM.addPass(createModuleToFunctionPassAdaptor(
CallSiteSplittingPass(), PTO.EagerlyInvalidateAnalyses));
@ -2182,7 +2182,7 @@ PassBuilder::buildLTODefaultPipeline(OptimizationLevel Level,
// calls, etc, so let instcombine do this.
FunctionPassManager PeepholeFPM;
PeepholeFPM.addPass(InstCombinePass());
if (Level.getSpeedupLevel() > 1)
if (Level >= OptimizationLevel::O2)
PeepholeFPM.addPass(AggressiveInstCombinePass());
invokePeepholeEPCallbacks(PeepholeFPM, Level);
@ -2305,14 +2305,14 @@ PassBuilder::buildLTODefaultPipeline(OptimizationLevel Level,
invokeVectorizerStartEPCallbacks(MainFPM, Level);
LoopPassManager LPM;
if (EnableLoopFlatten && Level.getSpeedupLevel() > 1)
if (EnableLoopFlatten && Level >= OptimizationLevel::O2)
LPM.addPass(LoopFlattenPass());
LPM.addPass(IndVarSimplifyPass());
LPM.addPass(LoopDeletionPass());
// FIXME: Add loop interchange.
// Unroll small loops and perform peeling.
LPM.addPass(LoopFullUnrollPass(Level.getSpeedupLevel(),
LPM.addPass(LoopFullUnrollPass(static_cast<int>(Level),
/* OnlyWhenForced= */ !PTO.LoopUnrolling,
PTO.ForgetAllSCEVInLoopUnroll));
// The loop passes in LPM (LoopFullUnrollPass) do not preserve MemorySSA.

View file

@ -1076,8 +1076,7 @@ void AMDGPUTargetMachine::registerPassBuilderCallbacks(PassBuilder &PB) {
// Add promote kernel arguments pass to the opt pipeline right before
// infer address spaces which is needed to do actual address space
// rewriting.
if (Level.getSpeedupLevel() > OptimizationLevel::O1.getSpeedupLevel() &&
EnablePromoteKernelArguments)
if (Level > OptimizationLevel::O1 && EnablePromoteKernelArguments)
FPM.addPass(AMDGPUPromoteKernelArgumentsPass());
// Add infer address spaces pass to the opt pipeline after inlining

View file

@ -295,12 +295,12 @@ void HexagonTargetMachine::registerPassBuilderCallbacks(PassBuilder &PB) {
PB.registerLateLoopOptimizationsEPCallback(
[=](LoopPassManager &LPM, OptimizationLevel Level) {
if (Level.getSpeedupLevel() > 0)
if (Level != OptimizationLevel::O0)
LPM.addPass(HexagonLoopIdiomRecognitionPass());
});
PB.registerLoopOptimizerEndEPCallback(
[=](LoopPassManager &LPM, OptimizationLevel Level) {
if (Level.getSpeedupLevel() > 0)
if (Level != OptimizationLevel::O0)
LPM.addPass(HexagonVectorLoopCarriedReusePass());
});
}

View file

@ -483,7 +483,7 @@ static void buildEarlyPollyPipeline(llvm::ModulePassManager &MPM,
llvm::OptimizationLevel Level,
IntrusiveRefCntPtr<vfs::FileSystem> FS) {
bool EnableForOpt =
shouldEnablePollyForOptimization() && Level.isOptimizingForSpeed();
shouldEnablePollyForOptimization() && Level != OptimizationLevel::O0;
if (!shouldEnablePollyForDiagnostic() && !EnableForOpt)
return;
@ -513,7 +513,7 @@ static void buildLatePollyPipeline(FunctionPassManager &PM,
llvm::OptimizationLevel Level,
IntrusiveRefCntPtr<vfs::FileSystem> FS) {
bool EnableForOpt =
shouldEnablePollyForOptimization() && Level.isOptimizingForSpeed();
shouldEnablePollyForOptimization() && Level != OptimizationLevel::O0;
if (!shouldEnablePollyForDiagnostic() && !EnableForOpt)
return;