LLVM official documentation gives a fairly clear way to run a single pass using opt
:
clang -emit-llvm $(CFLAGS) -o target.bc -c target.c
opt -passes="mypass" target.bc > target_optimized.bc
clang target_optimized.bc -o $@
By default, other passes do not run using this method, and if you wanted your pass to run on any project you build, you would have to modify the projects' Makefiles (or other configuration files) in order to run your pass. Instead you can add your pass to the default Clang pipeline.
/llvm/lib/Passes/PassBuilderPipelines.cpp
, and the function you will probably edit is buildPerModuleDefaultPipeline(Level, LTOPreLink)
. You can directly add your pass somewhere using:
MPM.addPass(myPass());
If you want your pass to run only on certain optimization levels, you can check Level == OptimizationLevel::O0
, changing O0
to the relevant level. You can also place your call to addPass
in one of the callee functions like buildModuleSimplificationPipeline
if the function seems appropriate.
/clang/lib/CodeGen/BackendUtil.cpp
, and the relevant function is RunOptimizationPipeline
.
Most passes applied by Clang are added using callbacks. For example, if you'd like your pass to be run with default early simplification passes, then you can use PB.registerPipelineEarlySimplificationEPCallback(...)
. There are a number of callbacks that you can use which determine at which point during compliation your pass would run.
In a nutshell, the RunOptimizationPipeline
registers the callbacks, builds the default pipeline (inserting the callback passes as specified earlier) with MPM = PB.buildPerModuleDefaultPipeline(Level)
, adds some final passes to the pipeline, and then runs the pipeline.
So, callbacks should be inserted before the call to PB.buildPerModuleDefaultPipeline
.
If you're okay with running your pass at the end of the pipeline, then you can use MPM.addPass(myPass())
after that call, but before the statement MPM.run(*TheModule, MAM);
at the very end of the function.
clang
as normal and have your pass run. Yay!
Using opt
, you can just use the -print-pipeline-passes
flag, but Clang doesn't seem to have an option for this right now.
If you run Clang with -emit-llvm
, it does not use LTO and it defaults to -O0
. If you intend to run opt
after clang -emit-llvm
, you may have to include -disable-O0-optnone
, which would otherwise refuse to let passes run on the optnone
-labeled functions.
When you run opt
, it won't run the default LLVM pass pipeline, so when specifying passes, you can specify -passes="myPass,default
, which runs the passes in the order you listed them. There is no way (I think) to use opt
to run the default Clang pipeline.