Is it possible to make passes running after optimizer?

I’m just learning how to write passes.

This is not necessarily a reasonable question for LLVM.

In LLVM, broadly there are several stages of compilation:

  • Clang turns C/C++ into LLVM IR.
  • Lots of passes run on LLVM IR (middle-end passes)
  • The instruction selector turns LLVM IR into MIR
  • Lots of passes run on MIR (backend passes)
  • the MIR is turned into an output, usually an object file or assembly.

There are a multitude of middle-end (IR to IR) passes, and a multitude of backend (MIR to MIR) passes. Middle-end passes tend to be target-agnostic, but some are required for correctness, and some are optimisation passes. Backend passes tend to be target-specific (as they deal with a mixture of target-specific instructions and target-independent instructions - the latter will all become target-specific instructions by the time all the backend passes are complete), but again some are required to even produce an object, and some are optimisations.

Broadly, developers can insert a pass anywhere they like in the pass pipeline. For backend passes, there are more invariants that need to be preserved which depend on your place in the pass pipeline.

“After all optimisation passes” can be very late in these two pipelines, and so does not always make sense for what your pass actually wants to do, as you may not have the high-level information you need any more, so a better question to ask is “Where do I have the information my pass requires?” and (especially for backend passes) “Will the invariants I have carefully ensured in the output from my pass be preserved by later passes?”

One thing to look at is to use -mllvm -debug-pass=Structure to see the entire set of passes used by LLVM (the exact output will depend on your target and your optimisation level). Lots of these will be analysis passes (which do not change their input program), but you might find a good place to put your pass. One tip is the last possible place for an IR pass is just before CodeGenPrepare (or as part of it) - this pass does some final modifications to ensure the IR is easier to generate instructions from.