-
Notifications
You must be signed in to change notification settings - Fork 668
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
base: main
Are you sure you want to change the base?
Conversation
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)); | ||
} |
There was a problem hiding this comment.
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 GlobalOptimizationOptions::applyOptimization( | ||
const OptionsBinder &binder, const GlobalPipelineOptions &globalLevel) { | ||
binder.overrideDefault("iree-global-optimization-opt-level", optLevel, | ||
globalLevel.optLevel); | ||
|
||
if (optLevel != llvm::OptimizationLevel::O0) { | ||
binder.overrideDefault("iree-opt-strip-assertions", stripAssertions, true); | ||
llvm::dbgs() << "stripAssertions " << stripAssertions << '\n'; | ||
} | ||
}; | ||
|
||
void GlobalOptimizationOptions::bindOptions(OptionsBinder &binder) { | ||
static llvm::cl::OptionCategory category( | ||
"IREE options for controlling global optimizations."); | ||
binder.opt<llvm::OptimizationLevel>( | ||
"iree-global-optimization-opt-level", optLevel, | ||
llvm::cl::desc("Optimization level for the this pipeline"), | ||
llvm::cl::cat(category)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@benvanik I attempted to do similar to what you suggested but I've run into some problems.
As an example init_at_opt_level
would be the function used to tell the binder to set stripAssertions
to true when at O3
(and there wouldn't be a need for the manual applyOptimization
):
binder.opt<bool>(
"iree-opt-strip-assertions",
stripAssertions,
init_at_opt_level(O3, true));
The problem I'm having is that iree-opt-strip-assertions
should be set based upon the value iree-global-optimization-opt-level
and I don't have a good way to let the binder know that.
There is a secondary problem, too. As you mentioned, the options shouldn't be directly set but rather a copy should be made. This is needed because we don't want setting optimization levels to affect the other flags for a session. This makes it hard (impossible?) to to make it so that GlobalOptimizationOptions::stripAssertions
should be set based on GlobalOptimizationOptions::optLevel
from inside of of bindOptions
because the GlobalOptimizationOptions
object we use to bind won't be the one that has the optimizations applied.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a real good start!
There's a few super magic ways we could do things, but for v0 I'd have your applyOptimization above walk through the options registered on a binder and if there are registered init_at_opt_level entries perform the override. It's a bit of boilerplate we could remove with template magic but copy/pasting for now is fine. something like:
applyOptimization:
binder.overrideDefault("...-opt-level", optLevel, ...);
binder.overrideOptimizationDefaults(optLevel);
// if there are nested binders, call applyOptimization on them
The fancier automatic way would be to have the pipeline opt level option be stashed by the binder - instead of binder.opt<OptimizationLevel>(...)
could have binder.optimizationLevel("...-opt-level")
to make it explicit what the primary scoped optimization level option is and then the applyOptimization
default impl above can do everything itself: the top level gets called, it checks if it has a registered optimization level option, overrides it if needed, and then calls overrideOptimizationDefaults
. Then we'd only need to override it if we had nested options (but even that could be improved, and for now we could ignore).
- Use llvm::OptimizationLevel - Fix `isChanged` callback and move previus impl to `isDefault` - Add tests for OptionUtils Signed-off-by: Ian Wood <[email protected]>
Signed-off-by: Ian Wood <[email protected]>
- Uses the overall optimization level to set global opt's phase optimization level. Also, sets strip assertions accordingly - Adds a test to make sure that the session flags are not modified. Signed-off-by: Ian Wood <[email protected]>
Signed-off-by: Ian Wood <[email protected]>
This is still a WIP, but I opened the PR and requested reviews to get some feedback on the general approach. There is definitely some cleanup needed + only 1 flag is setup to use the optimization levels. I would like to hear some thoughts on #20047 (comment) before flushing this out. |
void GlobalOptimizationOptions::applyOptimization( | ||
const OptionsBinder &binder, const GlobalPipelineOptions &globalLevel) { | ||
binder.overrideDefault("iree-global-optimization-opt-level", optLevel, | ||
globalLevel.optLevel); | ||
|
||
if (optLevel != llvm::OptimizationLevel::O0) { | ||
binder.overrideDefault("iree-opt-strip-assertions", stripAssertions, true); | ||
llvm::dbgs() << "stripAssertions " << stripAssertions << '\n'; | ||
} | ||
}; | ||
|
||
void GlobalOptimizationOptions::bindOptions(OptionsBinder &binder) { | ||
static llvm::cl::OptionCategory category( | ||
"IREE options for controlling global optimizations."); | ||
binder.opt<llvm::OptimizationLevel>( | ||
"iree-global-optimization-opt-level", optLevel, | ||
llvm::cl::desc("Optimization level for the this pipeline"), | ||
llvm::cl::cat(category)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a real good start!
There's a few super magic ways we could do things, but for v0 I'd have your applyOptimization above walk through the options registered on a binder and if there are registered init_at_opt_level entries perform the override. It's a bit of boilerplate we could remove with template magic but copy/pasting for now is fine. something like:
applyOptimization:
binder.overrideDefault("...-opt-level", optLevel, ...);
binder.overrideOptimizationDefaults(optLevel);
// if there are nested binders, call applyOptimization on them
The fancier automatic way would be to have the pipeline opt level option be stashed by the binder - instead of binder.opt<OptimizationLevel>(...)
could have binder.optimizationLevel("...-opt-level")
to make it explicit what the primary scoped optimization level option is and then the applyOptimization
default impl above can do everything itself: the top level gets called, it checks if it has a registered optimization level option, overrides it if needed, and then calls overrideOptimizationDefaults
. Then we'd only need to override it if we had nested options (but even that could be improved, and for now we could ignore).
@benvanik replying to your comment above, I was trying to get this to work but I think there is a problem with having the binder automatically apply flag modifications specified with Maybe its a problem with how I'm trying to implement it, so I will share some details. I was thinking that For example: GlobalOptimizationOptions options0;
{
GlobalOptimizationOptions options1;
// binds options and stores reference to `options1.stripAssertions` to be updated
// when `applyOptimizations` is called.
options1.bindOptions(binder);
options0 = optioins1;
}
// set from flags...
// Problematic because binder is storing references to options1's members.
// So, `options0` never gets updated and this is UB
options0.applyOptimizations(binder); |
I didn't think of using callbacks and instead just storing the data as a field on the options info that is cloneable - SmallVector or something of the optimization level -> value. |
Okay, so this would still require something that passes this field to the binder? Something roughly similar to void applyOptimizations(...){
binder.overrideDefault("...-opt-level", optLevel, ...);
binder.overrideDefaultWith(optLevel, stripAssertions, stripAssertionsOptToDefaultMap);
} And the benefit would be printability of default levels at each optimization level because they are declared during binding? |
I don't think so. You'd have a subclass of A user should then be able to do something like binder.opt<bool>(
"iree-opt-strip-assertions",
stripAssertions,
init_at_opt_level(O2, true)); (that make_unique'ing your optimization_level_opt, the init_at_opt_level calling the setInitialValue(O3, true) to add it to the opt vector, and your generic applyOptimizations walking over it to do the "if initial value then walk vector and find the max opt level value and use that" (e.g. the O2 option should be picked up above if -O3 was specified)) (rough idea, but it should work just as |
46d1505
to
1f8ae49
Compare
Signed-off-by: Ian Wood <[email protected]>
Signed-off-by: Ian Wood <[email protected]>
Signed-off-by: Ian Wood <[email protected]>
This change adds support for optimization flags that can be used to broadly control compiler optimizations. Currently,
iree-opt-level
is the name of the flag that would control the overall optimization level for the compiler invocation and it would cascade down to more fine-grained flags (i.e.iree-opt-strip-assertions
). This will give users an easy way to control the compilation process and reduce the number of flags required to get the desired optimizations.Progress towards #19072