Find order of passes

Hi!

I’m trying to find the order in which passes are expected to be executed - general order not for particular compilation. I have read Writing an LLVM Pass — LLVM 15.0.0git documentation and especially in section about basic required code few places are mentioned where pass should be added. However, I don’t see any explanation there as to how determine which pass is happening after which.

The fact that pass in the tutorial is transformation pass on function I believe doesn’t change the main question I have.

Closest to what I would understand as order of passes execution can be found in llvm-project/PassBuilderPipelines.cpp at main · llvm/llvm-project · GitHub but not all passes registered in PassRegistry.def are present in PassBuilderPipelines.cpp. Example being InstCountPass().

My understanding based on observations so far is that order of passes listed in PassBuilderPipelines.cpp applies only to selected passes (based on what criteria?), which are also entry points to other passes. And only inside those we see the calls to all other passes being executed. In other words - there isn’t one place where order of all passes is presented, which is a bit unfortunate. Is this correct assumption?

Just as a disclaimer, I am aware that different passes are triggered by different conditions based on compilation and there is a way of printing passes that has been executed using -debug-pass=Executions but this is not what I’m looking for exactly.

My understanding based on observations so far is that order of passes listed in PassBuilderPipelines.cpp applies only to selected passes (based on what criteria?), which are also entry points to other passes. And only inside those we see the calls to all other passes being executed. In other words - there isn’t one place where order of all passes is presented, which is a bit unfortunate. Is this correct assumption?

The story is somewhat complicated depending on what precisely you mean by “pass.” LLVM generally considers two types of passes: analysis passes, which provide facts about the IR without doing any transformations, and transformation passes, which may transform the IR and, in doing so, invalidate the results of prior analyses, requiring them to be read the next time a pass wishes to gather analysis passes. However, transformation passes are also encouraged to avoid invalidating analyses–particularly “core” analysis passes such as computing dominator tree information.

If your goal is to ask what is the sequence of transformation passes that will optimize the IR, then the list of passes in PassBuilderPipelines will be a correct, complete list in most circumstances (at least, until you do the LLVM IR->assembly codegen pipeline embodied by llc). Analysis passes will not be included in the list, so you will not see when, say, ScalarEvolution or MemorySSA or similar passes in the list have run just by reading PassBuilderPipelines. Demanding a single, static list of these passes is actually impossible: whether or not a transformation pass invalidates an analysis pass is dependent on the execution of the pass, and how much it does or does not transform in the IR, so for different inputs, you may get a different list of passes actually run.

Since you brought up InstCountPass, it’s worth pointing out that there are several passes which are never run as part of the usual pass pipelines. These passes exist to be explicitly requested when running opt for various utility purposes. For example, I frequently use view-cfg to be able to get diagrams of the program’s control flow as I’m debugging code.

2 Likes

Thank you very much for detailed answer! To be honest I though that order of transformation passes and analysis passes is controlled from some common place. It’s good to know that story there is completely different.

A small follow-up to this topic.
Passes that are printed when using print-after-all flag are only transformation passes - right?