Запустите конвейер оптимизации по умолчанию с использованием современного LLVM - PullRequest
0 голосов
/ 12 декабря 2018

Я использую LLVM 7, и у меня есть llvm::Module, который я хотел бы оптимизировать, используя стандартный конвейер оптимизации.К сожалению, нет функции llvm::runDefaultOptimizations, которую я могу вызвать.Кажется, существует несколько способов оптимизации модуля в LLVM.Мои поиски по этой теме обнаружили много старых / устаревших API и некоторые примеры, которые не работают в моей системе.

Я хочу запустить все стандартные оптимизации на -O3 с наименьшим количеством возможных хлопот,Я не хочу вручную перечислять все проходы или даже писать цикл for.Я думал, что llvm::PassBuilder::buildModuleOptimizationPipeline может быть решением, но я получаю ошибку компоновщика, когда пытаюсь использовать эту функцию, что я считаю действительно странным.

Ответы [ 2 ]

0 голосов
/ 14 декабря 2018

В итоге я взял источник инструмента opt (, найденный здесь ) и удалил все, что мне не нужно.Я закончил с этим:

#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);
}

Это примерно эквивалентно передаче -O3 в opt.Он использует некоторые вещи legacy, но я не против.

0 голосов
/ 12 декабря 2018

Чтобы узнать, что такое стандартные проходы для LLVM, вы можете попробовать проверить подклассы интерфейса Pass.Насколько я знаю, нет прохода, который запускает специфичные для clang проходы в самом API LLVM.Для этого вам нужно взглянуть на clang.

Чтобы выяснить, какие именно проходы вы хотели бы добавить, посмотрите на

llvm-as < /dev/null | opt -O3 -disable-output -debug-pass=Arguments  

См. Где найти последовательность оптимизации для clang-OX?

Тем не менее, возникают некоторые трудности, поиск используемого вами API и так далее.То же самое можно применить к Clang -O3.

Что вы можете сделать, если это возможно для вашего проекта, это сгенерировать IR LLVM для файла на диске и затем скомпилировать неоптимизированный IR LLVM с clang отдельно с O3flag.

Вот как вы можете запустить некоторые проходы, используя устаревший менеджер проходов.Предполагая, что у вас есть контекст LLVM.

 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.

Затем они могут запускаться с помощью

functionPassMngr->run(getLLVMFunc());

Если бы getLLVMFunc вернул llvm :: Function *, который вы генерируете в данный момент.Обратите внимание, что здесь я использую устаревший менеджер пропусков, причина в том, что clang использует устаревший менеджер пропусков внутри.

...