问题
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.
回答1:
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.
回答2:
To see what the standard passes are for LLVM you can try to check to subclasses of the Pass interface. As far as I know there is no pass that run the clang specific passes in the LLVM API itself. For that you have to look at clang.
To figure out exactly what passes that you would like to add look at
llvm-as < /dev/null | opt -O3 -disable-output -debug-pass=Arguments
See Where to find the optimization sequence for clang -OX?
Still, there is some hassle, finding the API you use and so on. The same can be applied for Clang -O3.
What you can do if it is possible for your project is to generate the LLVM IR to file on disk and then compiling the unoptimised LLVM IR with clang separately with the O3 flag.
This is how you can run some passes using the legacy pass manager. Assuming you have an LLVM context.
module = llvm::make_unique<llvm::Module>("module",context); //Context is your LLVM context.
functionPassMngr = llvm::make_unique<llvm::legacy::FunctionPassManager>(module.get());
functionPassMngr->add(llvm::createPromoteMemoryToRegisterPass()); //SSA conversion
functionPassMngr->add(llvm::createCFGSimplificationPass()); //Dead code elimination
functionPassMngr->add(llvm::createSROAPass());
functionPassMngr->add(llvm::createLoopSimplifyCFGPass());
functionPassMngr->add(llvm::createConstantPropagationPass());
functionPassMngr->add(llvm::createNewGVNPass());//Global value numbering
functionPassMngr->add(llvm::createReassociatePass());
functionPassMngr->add(llvm::createPartiallyInlineLibCallsPass()); //Inline standard calls
functionPassMngr->add(llvm::createDeadCodeEliminationPass());
functionPassMngr->add(llvm::createCFGSimplificationPass()); //Cleanup
functionPassMngr->add(llvm::createInstructionCombiningPass());
functionPassMngr->add(llvm::createFlattenCFGPass()); //Flatten the control flow graph.
These can then by run by
functionPassMngr->run(getLLVMFunc());
Were getLLVMFunc would return a llvm::Function* that you are currently generating. Note that I use the legacy pass manager here, the reason being that clang uses the legacy pass manager internally.
来源:https://stackoverflow.com/questions/53738883/run-default-optimization-pipeline-using-modern-llvm