I'm using LLVM 7 and I have an llvm::Module
that I'd like to optimize using the standard optimization pipeline. Unfortunately, there isn't a llvm::runDefaultOptimizations
function that I can call. There seems to be a bajillion ways to optimize a module in LLVM. My searches on this topic have found many old/depreciated APIs and some examples that don't work on my system.
I want to run all of the standard optimizations at -O3
with the least amount of hassle possible. I don't want to manually list all of the passes or even write a for loop. I thought llvm::PassBuilder::buildModuleOptimizationPipeline
might be the solution but I get a linker error when I try to use that function which I think is really strange.
I ended up taking the source of the opt
tool (found here) and stripping everything I didn't need. I ended up with this:
#include <llvm/IR/Verifier.h>
#include <llvm/Transforms/IPO.h>
#include <llvm/IR/LegacyPassManager.h>
#include <llvm/Target/TargetMachine.h>
#include <llvm/Analysis/TargetLibraryInfo.h>
#include <llvm/Analysis/TargetTransformInfo.h>
#include <llvm/Transforms/IPO/PassManagerBuilder.h>
namespace {
void addOptPasses(
llvm::legacy::PassManagerBase &passes,
llvm::legacy::FunctionPassManager &fnPasses,
llvm::TargetMachine *machine
) {
llvm::PassManagerBuilder builder;
builder.OptLevel = 3;
builder.SizeLevel = 0;
builder.Inliner = llvm::createFunctionInliningPass(3, 0, false);
builder.LoopVectorize = true;
builder.SLPVectorize = true;
machine->adjustPassManager(builder);
builder.populateFunctionPassManager(fnPasses);
builder.populateModulePassManager(passes);
}
void addLinkPasses(llvm::legacy::PassManagerBase &passes) {
llvm::PassManagerBuilder builder;
builder.VerifyInput = true;
builder.Inliner = llvm::createFunctionInliningPass(3, 0, false);
builder.populateLTOPassManager(passes);
}
}
void optimizeModule(llvm::TargetMachine *machine, llvm::Module *module) {
module->setTargetTriple(machine->getTargetTriple().str());
module->setDataLayout(machine->createDataLayout());
llvm::legacy::PassManager passes;
passes.add(new llvm::TargetLibraryInfoWrapperPass(machine->getTargetTriple()));
passes.add(llvm::createTargetTransformInfoWrapperPass(machine->getTargetIRAnalysis()));
llvm::legacy::FunctionPassManager fnPasses(module);
fnPasses.add(llvm::createTargetTransformInfoWrapperPass(machine->getTargetIRAnalysis()));
addOptPasses(passes, fnPasses, machine);
addLinkPasses(passes);
fnPasses.doInitialization();
for (llvm::Function &func : *module) {
fnPasses.run(func);
}
fnPasses.doFinalization();
passes.add(llvm::createVerifierPass());
passes.run(*module);
}
This is roughly equivalent to passing -O3
to opt
. It's using some legacy
stuff but I don't really mind.