From reading the source code of LLVM in lib/Transforms/IPO/Inliner.cpp
I found that LLVM designed the actual inliner pass as a CGSCC pass, and then there is ModuleInlinerWrapperPass
that wraps around the CGSCC pass to do per-module inlining.
Peeking inside PassBuilder.cpp
, I found the module-level inliner wrapper pass is typically run at the PGO-instrumentation stage (as part of the addPGOInstrPipeline
pipeline), as well as the LTO stage.
I was interested in the differences between the CGSCC pass and the module-level pass and which one is scheduled earlier, so I added some LLVM_DEBUG statements to print from the initializer of the module-level pass. seems like by default opt -O2
does not run the module-level inliner; instead, it runs the CGSCC pass quite early in the optimization pipeline.
My question is: When is the module-level inliner pass run in the optimization pipeline (if ever), and what is its relationship with the CGSCC inliner pass?
This question boils down to the difference between the new PassManager and old PassManager in LLVM.
Essentially, there are two ways to write a pass: either we can use the new PassManager (with pass classes extending PassInfoMixin<...>
) or use the legacy PassManager (with pass classes extending ModulePass
/CGSCCPass
/FunctionPass
...).
The new PassManager uses the PassBuilder
class to schedule passes into pipelines and then run the pipeline in the sequence it is scheduled. The ModuleInlinerWrapperPass
is essentially a module-level wrapper pass in order for the new PassManager to schedule inliner into its existing module-level optimization pipeline.