clover/llvm: Clean up compile_native().
This switches compile_native() to the C++ API (which the rest of this file makes use of anyway so there is little benefit from using the C API), what should get rid of an amount of boilerplate and fix a leak of the TargetMachine object in the error path. v2: Additional fixes for LLVM 3.6. v3: Update for the latest LLVM SVN changes. Reviewed-by: Serge Martin <edb+mesa@sigluy.net> Tested-by: Jan Vesely <jan.vesely@rutgers.edu>
This commit is contained in:
@@ -38,6 +38,7 @@
|
|||||||
|
|
||||||
#include <llvm/Linker/Linker.h>
|
#include <llvm/Linker/Linker.h>
|
||||||
#include <llvm/Transforms/IPO.h>
|
#include <llvm/Transforms/IPO.h>
|
||||||
|
#include <llvm/Target/TargetMachine.h>
|
||||||
|
|
||||||
#if HAVE_LLVM >= 0x0307
|
#if HAVE_LLVM >= 0x0307
|
||||||
#include <llvm/IR/LegacyPassManager.h>
|
#include <llvm/IR/LegacyPassManager.h>
|
||||||
@@ -45,6 +46,8 @@
|
|||||||
#else
|
#else
|
||||||
#include <llvm/PassManager.h>
|
#include <llvm/PassManager.h>
|
||||||
#include <llvm/Target/TargetLibraryInfo.h>
|
#include <llvm/Target/TargetLibraryInfo.h>
|
||||||
|
#include <llvm/Target/TargetSubtargetInfo.h>
|
||||||
|
#include <llvm/Support/FormattedStream.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <clang/Frontend/CodeGenOptions.h>
|
#include <clang/Frontend/CodeGenOptions.h>
|
||||||
@@ -109,6 +112,33 @@ namespace clover {
|
|||||||
map(std::mem_fn(&std::string::data), names))));
|
map(std::mem_fn(&std::string::data), names))));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if HAVE_LLVM >= 0x0307
|
||||||
|
typedef ::llvm::raw_svector_ostream &raw_ostream_to_emit_file;
|
||||||
|
#else
|
||||||
|
typedef ::llvm::formatted_raw_ostream raw_ostream_to_emit_file;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if HAVE_LLVM >= 0x0307
|
||||||
|
typedef ::llvm::DataLayout data_layout;
|
||||||
|
#else
|
||||||
|
typedef const ::llvm::DataLayout *data_layout;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
inline data_layout
|
||||||
|
get_data_layout(::llvm::TargetMachine &tm) {
|
||||||
|
#if HAVE_LLVM >= 0x0307
|
||||||
|
return tm.createDataLayout();
|
||||||
|
#else
|
||||||
|
return tm.getSubtargetImpl()->getDataLayout();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if HAVE_LLVM >= 0x0309
|
||||||
|
const auto default_reloc_model = ::llvm::None;
|
||||||
|
#else
|
||||||
|
const auto default_reloc_model = ::llvm::Reloc::Default;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -81,6 +81,7 @@ using ::llvm::Function;
|
|||||||
using ::llvm::LLVMContext;
|
using ::llvm::LLVMContext;
|
||||||
using ::llvm::Module;
|
using ::llvm::Module;
|
||||||
using ::llvm::raw_string_ostream;
|
using ::llvm::raw_string_ostream;
|
||||||
|
using ::llvm::TargetMachine;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// XXX - Temporary hack to avoid breaking the build for the moment, will
|
// XXX - Temporary hack to avoid breaking the build for the moment, will
|
||||||
@@ -542,80 +543,55 @@ namespace {
|
|||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
std::vector<char>
|
||||||
emit_code(LLVMTargetMachineRef tm, LLVMModuleRef mod,
|
emit_code(::llvm::Module &mod, const target &target,
|
||||||
LLVMCodeGenFileType file_type,
|
TargetMachine::CodeGenFileType ft,
|
||||||
LLVMMemoryBufferRef *out_buffer,
|
|
||||||
std::string &r_log) {
|
std::string &r_log) {
|
||||||
char *err_message = NULL;
|
std::string err;
|
||||||
|
auto t = ::llvm::TargetRegistry::lookupTarget(target.triple, err);
|
||||||
|
if (!t)
|
||||||
|
fail(r_log, compile_error(), err);
|
||||||
|
|
||||||
try {
|
std::unique_ptr<TargetMachine> tm {
|
||||||
if (LLVMTargetMachineEmitToMemoryBuffer(tm, mod, file_type,
|
t->createTargetMachine(target.triple, target.cpu, "", {},
|
||||||
&err_message, out_buffer))
|
compat::default_reloc_model,
|
||||||
fail(r_log, compile_error(), err_message);
|
::llvm::CodeModel::Default,
|
||||||
|
::llvm::CodeGenOpt::Default) };
|
||||||
|
if (!tm)
|
||||||
|
fail(r_log, compile_error(),
|
||||||
|
"Could not create TargetMachine: " + target.triple);
|
||||||
|
|
||||||
} catch (...) {
|
::llvm::SmallVector<char, 1024> data;
|
||||||
LLVMDisposeMessage(err_message);
|
|
||||||
throw;
|
{
|
||||||
|
compat::pass_manager pm;
|
||||||
|
::llvm::raw_svector_ostream os { data };
|
||||||
|
compat::raw_ostream_to_emit_file fos { os };
|
||||||
|
|
||||||
|
mod.setDataLayout(compat::get_data_layout(*tm));
|
||||||
|
tm->Options.MCOptions.AsmVerbose =
|
||||||
|
(ft == TargetMachine::CGFT_AssemblyFile);
|
||||||
|
|
||||||
|
if (tm->addPassesToEmitFile(pm, fos, ft))
|
||||||
|
fail(r_log, compile_error(), "TargetMachine can't emit this file");
|
||||||
|
|
||||||
|
pm.run(mod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return { data.begin(), data.end() };
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<char>
|
std::vector<char>
|
||||||
compile_native(const llvm::Module *mod, const target &t,
|
compile_native(llvm::Module *mod, const target &target,
|
||||||
std::string &r_log) {
|
std::string &r_log) {
|
||||||
|
|
||||||
std::string log;
|
|
||||||
LLVMTargetRef target;
|
|
||||||
char *error_message;
|
|
||||||
LLVMMemoryBufferRef out_buffer;
|
|
||||||
unsigned buffer_size;
|
|
||||||
const char *buffer_data;
|
|
||||||
LLVMModuleRef mod_ref = wrap(mod);
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (LLVMGetTargetFromTriple(t.triple.c_str(), &target, &error_message))
|
|
||||||
fail(r_log, compile_error(), error_message);
|
|
||||||
|
|
||||||
} catch (...) {
|
|
||||||
LLVMDisposeMessage(error_message);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
LLVMTargetMachineRef tm = LLVMCreateTargetMachine(
|
|
||||||
target, t.triple.c_str(), t.cpu.c_str(), "",
|
|
||||||
LLVMCodeGenLevelDefault, LLVMRelocDefault, LLVMCodeModelDefault);
|
|
||||||
if (!tm)
|
|
||||||
fail(r_log, compile_error(),
|
|
||||||
"Could not create TargetMachine: " + t.triple);
|
|
||||||
|
|
||||||
if (has_flag(debug::native)) {
|
if (has_flag(debug::native)) {
|
||||||
LLVMSetTargetMachineAsmVerbosity(tm, true);
|
std::unique_ptr<llvm::Module> cmod { CloneModule(mod) };
|
||||||
#if HAVE_LLVM >= 0x0308
|
debug::log(".asm", as_string(
|
||||||
LLVMModuleRef debug_mod = wrap(llvm::CloneModule(mod).release());
|
emit_code(*cmod, target,
|
||||||
#else
|
TargetMachine::CGFT_AssemblyFile, r_log)));
|
||||||
LLVMModuleRef debug_mod = wrap(llvm::CloneModule(mod));
|
|
||||||
#endif
|
|
||||||
emit_code(tm, debug_mod, LLVMAssemblyFile, &out_buffer, r_log);
|
|
||||||
buffer_size = LLVMGetBufferSize(out_buffer);
|
|
||||||
buffer_data = LLVMGetBufferStart(out_buffer);
|
|
||||||
debug::log(".asm", std::string(buffer_data, buffer_size));
|
|
||||||
|
|
||||||
LLVMSetTargetMachineAsmVerbosity(tm, false);
|
|
||||||
LLVMDisposeMemoryBuffer(out_buffer);
|
|
||||||
LLVMDisposeModule(debug_mod);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
emit_code(tm, mod_ref, LLVMObjectFile, &out_buffer, r_log);
|
return emit_code(*mod, target, TargetMachine::CGFT_ObjectFile, r_log);
|
||||||
|
|
||||||
buffer_size = LLVMGetBufferSize(out_buffer);
|
|
||||||
buffer_data = LLVMGetBufferStart(out_buffer);
|
|
||||||
|
|
||||||
std::vector<char> code(buffer_data, buffer_data + buffer_size);
|
|
||||||
|
|
||||||
LLVMDisposeMemoryBuffer(out_buffer);
|
|
||||||
LLVMDisposeTargetMachine(tm);
|
|
||||||
|
|
||||||
return code;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace elf {
|
namespace elf {
|
||||||
|
@@ -51,6 +51,11 @@ namespace clover {
|
|||||||
return ss;
|
return ss;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline std::string
|
||||||
|
as_string(const std::vector<char> &v) {
|
||||||
|
return { v.begin(), v.end() };
|
||||||
|
}
|
||||||
|
|
||||||
struct target {
|
struct target {
|
||||||
target(const std::string &s) :
|
target(const std::string &s) :
|
||||||
cpu(s.begin(), s.begin() + s.find_first_of("-")),
|
cpu(s.begin(), s.begin() + s.find_first_of("-")),
|
||||||
|
Reference in New Issue
Block a user