Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Add umbrella optimization flags #20047

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions compiler/bindings/python/test/api/api_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,19 @@ def testFlagError(self):
with self.assertRaises(ValueError):
session.set_flags("--does-not-exist=1")

def testOptFlags(self):
session = Session()
flags = session.get_flags()
self.assertIn("--iree-opt-level=O0", flags)
self.assertIn("--iree-global-optimization-opt-level=O0", flags)
self.assertIn("--iree-opt-strip-assertions=false", flags)

session.set_flags("--iree-opt-level=O2")
flags = session.get_flags()
self.assertIn("--iree-opt-level=O2", flags)
self.assertIn("--iree-global-optimization-opt-level=O0", flags)
self.assertIn("--iree-opt-strip-assertions=false", flags)

class DlInvocationTest(unittest.TestCase):
def testCreate(self):
session = Session()
Expand Down
21 changes: 19 additions & 2 deletions compiler/src/iree/compiler/API/Internal/CompilerDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ struct GlobalInit {
// Our session options can optionally be bound to the global command-line
// environment. If that is not the case, then these will be nullptr, and
// they should be default initialized at the session level.
GlobalPipelineOptions *clGlobalPipelineOptions = nullptr;
PluginManagerOptions *clPluginManagerOptions = nullptr;
BindingOptions *clBindingOptions = nullptr;
InputDialectOptions *clInputOptions = nullptr;
Expand Down Expand Up @@ -278,6 +279,7 @@ void GlobalInit::registerCommandLineOptions() {
mlir::tracing::DebugConfig::registerCLOptions();

// Bind session options to the command line environment.
clGlobalPipelineOptions = &GlobalPipelineOptions::FromFlags::get();
clPluginManagerOptions = &PluginManagerOptions::FromFlags::get();
clBindingOptions = &BindingOptions::FromFlags::get();
clInputOptions = &InputDialectOptions::FromFlags::get();
Expand Down Expand Up @@ -323,6 +325,7 @@ struct Session {
if (failed(binder.parseArguments(argc, argv, callback))) {
return new Error(std::move(errorMessage));
}

return nullptr;
}

Expand Down Expand Up @@ -387,6 +390,7 @@ struct Session {
bool pluginsActivated = false;
LogicalResult pluginActivationStatus{failure()};

GlobalPipelineOptions pipelineOptions;
BindingOptions bindingOptions;
InputDialectOptions inputOptions;
PreprocessingOptions preprocessingOptions;
Expand All @@ -410,6 +414,7 @@ Session::Session(GlobalInit &globalInit)
// Bootstrap session options from the cl environment, if enabled.
if (globalInit.usesCommandLine) {
debugConfig = mlir::tracing::DebugConfig::createFromCLOptions();
pipelineOptions = *globalInit.clGlobalPipelineOptions;
pluginManagerOptions = *globalInit.clPluginManagerOptions;
bindingOptions = *globalInit.clBindingOptions;
inputOptions = *globalInit.clInputOptions;
Expand All @@ -430,6 +435,7 @@ Session::Session(GlobalInit &globalInit)

// Register each options struct with the binder so we can manipulate
// mnemonically via the API.
pipelineOptions.bindOptions(binder);
bindingOptions.bindOptions(binder);
preprocessingOptions.bindOptions(binder);
inputOptions.bindOptions(binder);
Expand Down Expand Up @@ -938,6 +944,17 @@ void Invocation::dumpCompilationPhase(IREEVMPipelinePhase phase,

bool Invocation::runPipeline(enum iree_compiler_pipeline_t pipeline) {
auto passManager = createPassManager();

auto globalBinder = OptionsBinder::global();
auto &binder =
session.globalInit.usesCommandLine ? globalBinder : session.binder;
GlobalOptimizationOptions highLevelOptimizationOptions =
session.highLevelOptimizationOptions;

// Set optimization options on a copy of the sessions options.
highLevelOptimizationOptions.applyOptimization(binder,
session.pipelineOptions);

switch (pipeline) {
case IREE_COMPILER_PIPELINE_STD: {
IREEVMPipelinePhase compileFrom;
Expand All @@ -962,7 +979,7 @@ bool Invocation::runPipeline(enum iree_compiler_pipeline_t pipeline) {

buildIREEVMTransformPassPipeline(
session.targetRegistry, session.bindingOptions, session.inputOptions,
session.preprocessingOptions, session.highLevelOptimizationOptions,
session.preprocessingOptions, highLevelOptimizationOptions,
session.schedulingOptions, session.halTargetOptions,
session.vmTargetOptions, pipelineHooks, *passManager, compileFrom,
compileTo);
Expand Down Expand Up @@ -995,7 +1012,7 @@ bool Invocation::runPipeline(enum iree_compiler_pipeline_t pipeline) {
}
buildIREEPrecompileTransformPassPipeline(
session.targetRegistry, session.bindingOptions, session.inputOptions,
session.preprocessingOptions, session.highLevelOptimizationOptions,
session.preprocessingOptions, highLevelOptimizationOptions,
session.schedulingOptions, session.halTargetOptions, pipelineHooks,
*passManager, compileFrom, compileTo);
break;
Expand Down
26 changes: 26 additions & 0 deletions compiler/src/iree/compiler/Pipelines/Options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,29 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include "iree/compiler/Pipelines/Options.h"
#include "llvm/Passes/OptimizationLevel.h"

IREE_DEFINE_COMPILER_OPTION_FLAGS(mlir::iree_compiler::BindingOptions);
IREE_DEFINE_COMPILER_OPTION_FLAGS(mlir::iree_compiler::InputDialectOptions);
IREE_DEFINE_COMPILER_OPTION_FLAGS(
mlir::iree_compiler::GlobalOptimizationOptions);
IREE_DEFINE_COMPILER_OPTION_FLAGS(mlir::iree_compiler::SchedulingOptions);
IREE_DEFINE_COMPILER_OPTION_FLAGS(mlir::iree_compiler::PreprocessingOptions);
IREE_DEFINE_COMPILER_OPTION_FLAGS(mlir::iree_compiler::GlobalPipelineOptions);

namespace mlir::iree_compiler {

void GlobalPipelineOptions::bindOptions(OptionsBinder &binder) {
static llvm::cl::OptionCategory category(
"IREE global pipeline options controlling the entire compilation flow.");

binder.opt<llvm::OptimizationLevel>(
"iree-opt-level", optLevel,
llvm::cl::desc("Global optimization level to apply to the entire "
"compilation flow."),
llvm::cl::cat(category));
}
Comment on lines +20 to +29
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just dropping a reminder here: we have some existing docs for "optimization options" that are due to a rework, especially after these changes land: https://iree.dev/reference/optimization-options/

We could even add a snippet that we include on each page like https://iree.dev/guides/deployment-configurations/cpu/#compile-and-run-a-program and https://iree.dev/guides/deployment-configurations/gpu-vulkan/#compile-and-run-a-program that explains what to expect out of the box and how to optimize / tune / configure from there (linking to the optimization options reference page).


void BindingOptions::bindOptions(OptionsBinder &binder) {
static llvm::cl::OptionCategory category(
"IREE translation binding support options.");
Expand Down Expand Up @@ -119,9 +132,21 @@ void PreprocessingOptions::bindOptions(OptionsBinder &binder) {
llvm::cl::cat(category));
}

void GlobalOptimizationOptions::applyOptimization(
const OptionsBinder &binder, const GlobalPipelineOptions &globalLevel) {
binder.overrideDefault("iree-global-optimization-opt-level", optLevel,
globalLevel.optLevel);
binder.applyOptimization("iree-opt-strip-assertions", stripAssertions,
optLevel);
};

void GlobalOptimizationOptions::bindOptions(OptionsBinder &binder) {
static llvm::cl::OptionCategory category(
"IREE options for controlling global optimizations.");
binder.optimizationLevel(
"iree-global-optimization-opt-level", optLevel,
llvm::cl::desc("Optimization level for the this pipeline"),
llvm::cl::cat(category));
binder.opt<bool>(
"iree-opt-aggressively-propagate-transposes",
aggressiveTransposePropagation,
Expand Down Expand Up @@ -159,6 +184,7 @@ void GlobalOptimizationOptions::bindOptions(OptionsBinder &binder) {
"Reduces numeric precision to lower bit depths where possible."),
llvm::cl::cat(category));
binder.opt<bool>("iree-opt-strip-assertions", stripAssertions,
init_at_opt(llvm::OptimizationLevel::O1, true),
llvm::cl::desc("Strips debug assertions after any useful "
"information has been extracted."),
llvm::cl::cat(category));
Expand Down
10 changes: 10 additions & 0 deletions compiler/src/iree/compiler/Pipelines/Options.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@

namespace mlir::iree_compiler {

struct GlobalPipelineOptions {
llvm::OptimizationLevel optLevel = llvm::OptimizationLevel::O0;
void bindOptions(OptionsBinder &binder);
using FromFlags = OptionsFromFlags<GlobalPipelineOptions>;
};

struct BindingOptions {
// Whether to include runtime support functions for the IREE native ABI.
bool native = true;
Expand Down Expand Up @@ -72,6 +78,7 @@ struct InputDialectOptions {
// 2. Through a Transform dialect spec file.
// 3. Through a PDL spec file.
struct PreprocessingOptions {
llvm::OptimizationLevel optLevel = llvm::OptimizationLevel::O0;
std::string preprocessingPassPipeline;
std::string preprocessingTransformSpecFilename;
std::string preprocessingPDLSpecFilename;
Expand All @@ -82,6 +89,7 @@ struct PreprocessingOptions {

// Options controlling high level optimizations.
struct GlobalOptimizationOptions {
llvm::OptimizationLevel optLevel = llvm::OptimizationLevel::O0;
// Maximum byte size increase allowed for constant expr hoisting policy to
// allow hoisting. The threshold is 1MB by default.
int64_t constExprMaxSizeIncreaseThreshold = 1024 * 1024;
Expand Down Expand Up @@ -131,6 +139,8 @@ struct GlobalOptimizationOptions {
// Converts linalg named matmul ops to linalg generic ops.
bool generalizeMatmul = false;

void applyOptimization(const OptionsBinder &binder,
const GlobalPipelineOptions &globalLevel);
void bindOptions(OptionsBinder &binder);
using FromFlags = OptionsFromFlags<GlobalOptimizationOptions>;
};
Expand Down
70 changes: 63 additions & 7 deletions compiler/src/iree/compiler/Utils/OptionUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,14 @@

#include "iree/compiler/Utils/OptionUtils.h"

#include "llvm/ADT/StringSwitch.h"
#include "llvm/Passes/OptimizationLevel.h"
#include "llvm/Support/ManagedStatic.h"

namespace mlir::iree_compiler {

void OptionsBinder::addGlobalOption(std::unique_ptr<llvm::cl::Option> option) {
static llvm::ManagedStatic<std::vector<std::unique_ptr<llvm::cl::Option>>>
globalOptions;
globalOptions->push_back(std::move(option));
}
llvm::ManagedStatic<llvm::DenseMap<llvm::StringRef, OptionsBinder::OptionInfo>>
OptionsBinder::globalOptions;

LogicalResult OptionsBinder::parseArguments(int argc, const char *const *argv,
ErrorCallback onError) {
Expand Down Expand Up @@ -76,10 +75,10 @@ LogicalResult OptionsBinder::parseArguments(int argc, const char *const *argv,
llvm::SmallVector<std::string>
OptionsBinder::printArguments(bool nonDefaultOnly) {
llvm::SmallVector<std::string> values;
for (auto &info : localOptions) {
for (auto &[flag, info] : getOptionsStorage()) {
if (!info.print)
continue;
if (nonDefaultOnly && !info.isChanged())
if (nonDefaultOnly && !info.isDefault())
continue;

std::string s;
Expand All @@ -91,6 +90,22 @@ OptionsBinder::printArguments(bool nonDefaultOnly) {
return values;
}

OptionsBinder::OptionsStorage &OptionsBinder::getOptionsStorage() {
if (!scope) {
return *globalOptions;
} else {
return localOptions;
}
}

const OptionsBinder::OptionsStorage &OptionsBinder::getOptionsStorage() const {
if (!scope) {
return *globalOptions;
} else {
return localOptions;
}
}

} // namespace mlir::iree_compiler
//
// Examples:
Expand Down Expand Up @@ -191,3 +206,44 @@ void llvm::cl::parser<PowerOf2ByteSize>::printOptionDiff(
}

void llvm::cl::parser<PowerOf2ByteSize>::anchor() {}

bool llvm::cl::parser<llvm::OptimizationLevel>::parse(
Option &O, StringRef ArgName, StringRef Arg, llvm::OptimizationLevel &Val) {
auto val = StringSwitch<std::optional<OptimizationLevel>>(Arg)
.Case("O0", OptimizationLevel::O0)
.Case("O1", OptimizationLevel::O1)
.Case("O2", OptimizationLevel::O2)
.Case("O3", OptimizationLevel::O3)
// .Case("Os", OptimizationLevel::Os)
// .Case("Oz", OptimizationLevel::Oz)
.Default(std::nullopt);
if (!val) {
return O.error("'" + Arg +
"' value not a valid optimization level, use "
"O0/O1/O2/O3");
}
Val = *val;
return false;
}

void llvm::cl::parser<llvm::OptimizationLevel>::printOptionDiff(
const Option &O, llvm::OptimizationLevel V, const OptVal &Default,
size_t GlobalWidth) const {
printOptionName(O, GlobalWidth);
std::string Str;
{
llvm::raw_string_ostream SS(Str);
SS << V.getSpeedupLevel() << "/" << V.getSizeLevel();
}
outs() << "= " << Str;
outs().indent(2) << " (default: ";
if (Default.hasValue()) {
auto defaultVal = Default.getValue();
outs() << defaultVal.getSpeedupLevel() << "/" << defaultVal.getSizeLevel();
} else {
outs() << "*no default*";
}
outs() << ")\n";
}

void llvm::cl::parser<llvm::OptimizationLevel>::anchor() {}
Loading
Loading