mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
146 lines
4.8 KiB
C++
146 lines
4.8 KiB
C++
/// \file CompileModule.cpp
|
|
/// \brief The compile module pipe transforma llvm module into a object file
|
|
|
|
//
|
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
|
//
|
|
|
|
#include <memory>
|
|
|
|
#include "llvm/Analysis/TargetLibraryInfo.h"
|
|
#include "llvm/CodeGen/CommandFlags.h"
|
|
#include "llvm/CodeGen/MachineModuleInfo.h"
|
|
#include "llvm/IR/AutoUpgrade.h"
|
|
#include "llvm/IR/LegacyPassManager.h"
|
|
#include "llvm/Option/OptTable.h"
|
|
#include "llvm/Support/CodeGen.h"
|
|
#include "llvm/Support/TargetRegistry.h"
|
|
#include "llvm/Support/raw_os_ostream.h"
|
|
#include "llvm/Target/TargetMachine.h"
|
|
|
|
#include "revng/Pipeline/AllRegistries.h"
|
|
#include "revng/Pipeline/LLVMContainer.h"
|
|
#include "revng/Pipes/CompileModulePipe.h"
|
|
#include "revng/Support/Assert.h"
|
|
#include "revng/Support/IRAnnotators.h"
|
|
#include "revng/Support/OriginalAssemblyAnnotationWriter.h"
|
|
|
|
using namespace llvm;
|
|
using namespace llvm::codegen;
|
|
using namespace std;
|
|
using namespace pipeline;
|
|
using namespace ::revng::pipes;
|
|
using namespace sys;
|
|
using namespace cl;
|
|
|
|
static cl::opt<char> OptLevel("compile-opt-level",
|
|
cl::desc("Optimization level. [-O0, -O1, -O2, or "
|
|
"-O3] "
|
|
"(default = '-O2')"),
|
|
cl::Prefix,
|
|
cl::ZeroOrMore,
|
|
cl::init(' '));
|
|
|
|
static void
|
|
compileModuleRunImpl(LLVMContainer &Module, FileContainer &TargetBinary) {
|
|
|
|
StringMap<Option *> &RegOptions(getRegisteredOptions());
|
|
getOption<bool>(RegOptions, "disable-machine-licm")->setInitialValue(true);
|
|
|
|
llvm::Module *M = &Module.getModule();
|
|
|
|
OriginalAssemblyAnnotationWriter OAAW(M->getContext());
|
|
createSelfReferencingDebugInfo(M, Module.name(), &OAAW);
|
|
|
|
// Get the target specific parser.
|
|
std::string Error;
|
|
Triple TheTriple(M->getTargetTriple());
|
|
const auto *TheTarget = TargetRegistry::lookupTarget("", TheTriple, Error);
|
|
revng_assert(TheTarget);
|
|
|
|
TargetOptions Options = InitTargetOptionsFromCodeGenFlags(TheTriple);
|
|
|
|
CodeGenOpt::Level OLvl = CodeGenOpt::Default;
|
|
switch (OptLevel) {
|
|
case ' ':
|
|
break;
|
|
case '0':
|
|
OLvl = CodeGenOpt::None;
|
|
break;
|
|
case '1':
|
|
OLvl = CodeGenOpt::Less;
|
|
break;
|
|
case '2':
|
|
OLvl = CodeGenOpt::Default;
|
|
break;
|
|
case '3':
|
|
OLvl = CodeGenOpt::Aggressive;
|
|
break;
|
|
default:
|
|
revng_abort("Wrong Optimization Level");
|
|
return;
|
|
}
|
|
|
|
auto Ptr = TheTarget->createTargetMachine(TheTriple.getTriple(),
|
|
"",
|
|
"",
|
|
Options,
|
|
getRelocModel(),
|
|
M->getCodeModel(),
|
|
OLvl);
|
|
unique_ptr<TargetMachine> Target(Ptr);
|
|
|
|
// Add the target data from the target machine, if it exists, or the module.
|
|
M->setDataLayout(Target->createDataLayout());
|
|
|
|
// This needs to be done after setting datalayout since it calls verifier
|
|
// to check debug info whereas verifier relies on correct datalayout.
|
|
UpgradeDebugInfo(*M);
|
|
|
|
LLVMTargetMachine &LLVMTM = static_cast<LLVMTargetMachine &>(*Target);
|
|
auto *MMIWP = new MachineModuleInfoWrapperPass(&LLVMTM);
|
|
|
|
std::error_code EC;
|
|
raw_fd_ostream OutputStream(TargetBinary.getOrCreatePath(), EC);
|
|
revng_assert(!EC);
|
|
|
|
// Create pass manager
|
|
legacy::PassManager PM;
|
|
|
|
// Add an appropriate TargetLibraryInfo pass for the module's triple.
|
|
TargetLibraryInfoImpl TLII(Triple(M->getTargetTriple()));
|
|
PM.add(new TargetLibraryInfoWrapperPass(TLII));
|
|
|
|
bool Err = Target->addPassesToEmitFile(PM,
|
|
OutputStream,
|
|
nullptr,
|
|
CGFT_ObjectFile,
|
|
true,
|
|
MMIWP);
|
|
revng_assert(not Err);
|
|
revng_assert(llvm::verifyModule(*M, &llvm::dbgs()) == 0);
|
|
PM.run(*M);
|
|
revng_assert(llvm::verifyModule(*M, &llvm::dbgs()) == 0);
|
|
|
|
auto Path = TargetBinary.path();
|
|
|
|
auto Permissions = cantFail(errorOrToExpected(fs::getPermissions(*Path)));
|
|
Permissions = Permissions | fs::owner_exe;
|
|
fs::setPermissions(*TargetBinary.path(), Permissions);
|
|
}
|
|
|
|
void CompileModulePipe::run(const Context &,
|
|
LLVMContainer &Module,
|
|
FileContainer &TargetBinary) {
|
|
compileModuleRunImpl(Module, TargetBinary);
|
|
}
|
|
|
|
void CompileIsolatedModulePipe::run(const Context &,
|
|
LLVMContainer &Module,
|
|
FileContainer &TargetBinary) {
|
|
compileModuleRunImpl(Module, TargetBinary);
|
|
}
|
|
|
|
static RegisterPipe<CompileModulePipe> E2;
|
|
static RegisterPipe<CompileIsolatedModulePipe> E3;
|