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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

[llvm] Add support for the new pass manager API #558

Open
gloaming2dawn opened this issue Feb 1, 2022 · 5 comments
Open

[llvm] Add support for the new pass manager API #558

gloaming2dawn opened this issue Feb 1, 2022 · 5 comments
Labels
Enhancement New feature or request

Comments

@gloaming2dawn
Copy link

馃殌 Feature

Motivation

The new pass manager (now the default pass manager for the optimization pipeline in LLVM 13) leads to better compile times and benefits runtime of many programs. It requires explicit pass nesting. For example, to run a function pass, then a module pass, we need to wrap the function pass in a module adaptor:
$ opt -passes='function(no-op-function),no-op-module' /tmp/a.ll -S

The trend is that LLVM will abandon the legacy pass manager (which is now used by LLVM 10 of Compilergym). As shown in https://llvm.org/docs/ReleaseNotes.html, using the legacy pass manager for the optimization pipeline is deprecated and will be removed after LLVM 14.

So if Compilergym could support for the newest LLVM which use new pass manager, it could be more attractive.

@gloaming2dawn gloaming2dawn added the Enhancement New feature or request label Feb 1, 2022
@ChrisCummins
Copy link
Contributor

Hi @gloaming2dawn, thanks for the feature request! I agree this would be nice. I haven't used the new pass manager API, but from what I understand it is supported in LLVM 10, so I would happily take a patch to port the current LLVM environment to the new pass manager API.

Here is the code which uses the legacy pass manager:

bool LlvmSession::runPass(llvm::Pass* pass) {
llvm::legacy::PassManager passManager;
setupPassManager(&passManager, pass);
return passManager.run(benchmark().module());
}
bool LlvmSession::runPass(llvm::FunctionPass* pass) {
llvm::legacy::FunctionPassManager passManager(&benchmark().module());
setupPassManager(&passManager, pass);
bool changed = passManager.doInitialization();
for (auto& function : benchmark().module()) {
changed |= (passManager.run(function) ? 1 : 0);
}
changed |= (passManager.doFinalization() ? 1 : 0);
return changed;
}

I believe that swapping from LLVM 10 to 13 should be easier using the new CMake build system, though it may require a couple of API updates.

Left to my own devices, I would probably get around to taking a look at this in Q2, so patches welcome!

Cheers,
Chris

@gloaming2dawn
Copy link
Author

Thank you for your quick reply. Here are some supplements from https://llvm.org/docs/NewPassManager.html. The following code

ModulePassManager MPM;
MPM.addPass(createModuleToFunctionPassAdaptor(FunctionPass1()));
MPM.addPass(createModuleToFunctionPassAdaptor(FunctionPass2()));
MPM.run();

will run FunctionPass1 on each function in a module, then run FunctionPass2 on each function in the module. In contrast,

ModulePassManager MPM;
FunctionPassManager FPM;
FPM.addPass(FunctionPass1());
FPM.addPass(FunctionPass2());
MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));

will run FunctionPass1 and FunctionPass2 on the first function in a module, then run both passes on the second function in the module, and so on. This is better for cache locality around LLVM data structures. For example, running all loop passes on a loop may cause a later loop to be able to be optimized more than if each loop pass were run separately.

So, the new pass manager may have a larger search space than the legacy pass manager, which can be quite different from the current action space (the current action space: each pass is an action, separately applying pass1 and pass2 is the same as applying pass1 and pass2 in the pass manager).

@ChrisCummins
Copy link
Contributor

So, the new pass manager may have a larger search space than the legacy pass manager, which can be quite different from the current action space (the current action space: each pass is an action, separately applying pass1 and pass2 is the same as applying pass1 and pass2 in the pass manager).

Interesting! I think this could be exposed pretty neatly by creating a new action space that takes a list of passes, that are applied in a single step. Something like:

env = compiler_gym.make(
    "llvm-v0",
    combine_function_passes_into_single_adaptor=True,
)
env.reset()
# "normal" use:
env.step(0)
env.step(1)
# run pass 0 -> 1 -> 2, combining adjacent function passes into a single function pass adaptor where possible:
env.step([0, 1, 2])

What do you think?

Cheers,
Chris

@ChrisCummins ChrisCummins changed the title Support for LLVM 13 (new pass manager) [llvm] Add support for the new pass manager API Feb 10, 2022
@libin049
Copy link

libin049 commented May 29, 2023

@gloaming2dawn @ChrisCummins Do you have any progress on new pass manager API?

@ChrisCummins
Copy link
Contributor

Nothing on my end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants