Run default optimization pipeline using modern LLVM

|▌冷眼眸甩不掉的悲伤 提交于 2019-12-02 04:39:01

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.

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.

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