Run default optimization pipeline using modern LLVM

三世轮回 提交于 2019-12-02 02:43:04

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!