In Writing an LLVM Pass, we can know a lot about the Passes and PassManagers in LLVM. Therefore the following content is based on my understanding of them.
First of all, a pass is a task or transformation run on a unit. It can iterate over each element inside that unit, do some modification (transformation pass), or collection information (analysis pass). And the PassManager is the one to manage all the passes it owns, to analyze the relations between passes then schedule those passes to run one by one, in order to correctly execute all the passes in order and reduce computation resouces. Moreover PassManager itself is a pass as well, that means a PassManager, owning a number of passes, can be owned by and scheduled by another PassManager. In other words, a PassManager can be seen as a group of all passes that becomes a pass for higher PassManager to manage.
The particular example of PassManager
is FPPassManager
.
/* /wtsc/llvm-project/llvm/include/llvm/IR/LegacyPassManager.h */
...
//===----------------------------------------------------------------------===//
// FPPassManager
//
/// FPPassManager manages BBPassManagers and FunctionPasses.
/// It batches all function passes and basic block pass managers together and
/// sequence them to process one function at a time before processing next
/// function.
class FPPassManager : public ModulePass, public PMDataManager {...}
...
It itself is a pass, ModulePass, which run on a module. And manages other PassManages and FunctionPasses, which run on a function inside the module it runs on.
So what is the unit those different kind of Pass running on?
The input for a compiler is source code file, and each source code file will be compiled into an object file, an object file is a production from a translation unit, therefore a source code file and its including files will be turned into a translation unit by preprocessor. And a module in LLVM context corresponds to one translation unit.
Inside a LLVM Module
, there are global variables, Function
s, and other information describing this module for later processing. And inside those Function
s, we have smaller components named BasicBlock
s which contains a sequence of Instruction
s. Moreover, inside a Function
, there are bigger constructs, ControlFlowGraph
s, Loop
s, Region
s, Call Graph
s, that is made of BasicBlock
s.
Those Module, Function, ControlFlowGraph(CFG), Loop, Region, CallGraph, BasicBlock are the called unit above, which can have some kind of passes run on it.
One more thing, there different layer of those abstractions, in Swift Intermediate Language (SIL), there are corresponding Module (SILModule), Function (SILFunction, and so on. In the latter part of backend, There are Machine Function, Machine BasicBlock as well. Those have corresponding Passes and PassManagers operating on them.