clover/llvm: Split native codegen into separate file.
Reviewed-by: Serge Martin <edb+mesa@sigluy.net> Tested-by: Jan Vesely <jan.vesely@rutgers.edu>
This commit is contained in:
parent
8195637363
commit
520cc26859
|
@ -56,6 +56,7 @@ CPP_SOURCES := \
|
|||
LLVM_SOURCES := \
|
||||
llvm/codegen/bitcode.cpp \
|
||||
llvm/codegen/common.cpp \
|
||||
llvm/codegen/native.cpp \
|
||||
llvm/codegen.hpp \
|
||||
llvm/compat.hpp \
|
||||
llvm/invocation.cpp \
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#ifndef CLOVER_LLVM_CODEGEN_HPP
|
||||
#define CLOVER_LLVM_CODEGEN_HPP
|
||||
|
||||
#include "llvm/util.hpp"
|
||||
#include "core/module.hpp"
|
||||
|
||||
#include <llvm/IR/Module.h>
|
||||
|
@ -44,6 +45,14 @@ namespace clover {
|
|||
std::string
|
||||
print_module_bitcode(const ::llvm::Module &mod);
|
||||
|
||||
module
|
||||
build_module_native(::llvm::Module &mod, const target &target,
|
||||
const clang::CompilerInstance &c,
|
||||
std::string &r_log);
|
||||
|
||||
std::string
|
||||
print_module_native(const ::llvm::Module &mod, const target &target);
|
||||
|
||||
module
|
||||
build_module_common(const ::llvm::Module &mod,
|
||||
const std::vector<char> &code,
|
||||
|
|
|
@ -0,0 +1,165 @@
|
|||
//
|
||||
// Copyright 2012-2016 Francisco Jerez
|
||||
// Copyright 2012-2016 Advanced Micro Devices, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
///
|
||||
/// \file
|
||||
/// Generate code using an arbitrary LLVM back-end capable of emitting
|
||||
/// executable code as an ELF object file.
|
||||
///
|
||||
|
||||
#include "llvm/codegen.hpp"
|
||||
#include "llvm/compat.hpp"
|
||||
#include "llvm/util.hpp"
|
||||
#include "core/error.hpp"
|
||||
|
||||
#include <llvm/Target/TargetMachine.h>
|
||||
#include <llvm/Support/TargetRegistry.h>
|
||||
#include <llvm/Transforms/Utils/Cloning.h>
|
||||
|
||||
#include <libelf.h>
|
||||
#include <gelf.h>
|
||||
|
||||
using namespace clover;
|
||||
using namespace clover::llvm;
|
||||
using ::llvm::TargetMachine;
|
||||
|
||||
namespace {
|
||||
namespace elf {
|
||||
std::unique_ptr<Elf, int (*)(Elf *)>
|
||||
get(const std::vector<char> &code) {
|
||||
// One of the libelf implementations
|
||||
// (http://www.mr511.de/software/english.htm) requires calling
|
||||
// elf_version() before elf_memory().
|
||||
elf_version(EV_CURRENT);
|
||||
return { elf_memory(const_cast<char *>(code.data()), code.size()),
|
||||
elf_end };
|
||||
}
|
||||
|
||||
Elf_Scn *
|
||||
get_symbol_table(Elf *elf) {
|
||||
size_t section_str_index;
|
||||
elf_getshdrstrndx(elf, §ion_str_index);
|
||||
|
||||
for (Elf_Scn *s = elf_nextscn(elf, NULL); s; s = elf_nextscn(elf, s)) {
|
||||
GElf_Shdr header;
|
||||
if (gelf_getshdr(s, &header) != &header)
|
||||
return nullptr;
|
||||
|
||||
if (!std::strcmp(elf_strptr(elf, section_str_index, header.sh_name),
|
||||
".symtab"))
|
||||
return s;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::map<std::string, unsigned>
|
||||
get_symbol_offsets(Elf *elf, Elf_Scn *symtab) {
|
||||
Elf_Data *const symtab_data = elf_getdata(symtab, NULL);
|
||||
GElf_Shdr header;
|
||||
if (gelf_getshdr(symtab, &header) != &header)
|
||||
return {};
|
||||
|
||||
std::map<std::string, unsigned> symbol_offsets;
|
||||
GElf_Sym symbol;
|
||||
unsigned i = 0;
|
||||
|
||||
while (GElf_Sym *s = gelf_getsym(symtab_data, i++, &symbol)) {
|
||||
const char *name = elf_strptr(elf, header.sh_link, s->st_name);
|
||||
symbol_offsets[name] = s->st_value;
|
||||
}
|
||||
|
||||
return symbol_offsets;
|
||||
}
|
||||
}
|
||||
|
||||
std::map<std::string, unsigned>
|
||||
get_symbol_offsets(const std::vector<char> &code, std::string &r_log) {
|
||||
const auto elf = elf::get(code);
|
||||
const auto symtab = elf::get_symbol_table(elf.get());
|
||||
if (!symtab)
|
||||
fail(r_log, compile_error(), "Unable to find symbol table.");
|
||||
|
||||
return elf::get_symbol_offsets(elf.get(), symtab);
|
||||
}
|
||||
|
||||
std::vector<char>
|
||||
emit_code(::llvm::Module &mod, const target &target,
|
||||
TargetMachine::CodeGenFileType ft,
|
||||
std::string &r_log) {
|
||||
std::string err;
|
||||
auto t = ::llvm::TargetRegistry::lookupTarget(target.triple, err);
|
||||
if (!t)
|
||||
fail(r_log, compile_error(), err);
|
||||
|
||||
std::unique_ptr<TargetMachine> tm {
|
||||
t->createTargetMachine(target.triple, target.cpu, "", {},
|
||||
compat::default_reloc_model,
|
||||
::llvm::CodeModel::Default,
|
||||
::llvm::CodeGenOpt::Default) };
|
||||
if (!tm)
|
||||
fail(r_log, compile_error(),
|
||||
"Could not create TargetMachine: " + target.triple);
|
||||
|
||||
::llvm::SmallVector<char, 1024> data;
|
||||
|
||||
{
|
||||
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() };
|
||||
}
|
||||
}
|
||||
|
||||
module
|
||||
clover::llvm::build_module_native(::llvm::Module &mod, const target &target,
|
||||
const clang::CompilerInstance &c,
|
||||
std::string &r_log) {
|
||||
const auto code = emit_code(mod, target,
|
||||
TargetMachine::CGFT_ObjectFile, r_log);
|
||||
return build_module_common(mod, code, get_symbol_offsets(code, r_log), c);
|
||||
}
|
||||
|
||||
std::string
|
||||
clover::llvm::print_module_native(const ::llvm::Module &mod,
|
||||
const target &target) {
|
||||
std::string log;
|
||||
try {
|
||||
std::unique_ptr<::llvm::Module> cmod { CloneModule(&mod) };
|
||||
return as_string(emit_code(*cmod, target,
|
||||
TargetMachine::CGFT_AssemblyFile, log));
|
||||
} catch (...) {
|
||||
return "Couldn't output native disassembly: " + log;
|
||||
}
|
||||
}
|
|
@ -249,125 +249,6 @@ namespace {
|
|||
pmb.populateModulePassManager(pm);
|
||||
pm.run(mod);
|
||||
}
|
||||
|
||||
std::vector<char>
|
||||
emit_code(::llvm::Module &mod, const target &target,
|
||||
TargetMachine::CodeGenFileType ft,
|
||||
std::string &r_log) {
|
||||
std::string err;
|
||||
auto t = ::llvm::TargetRegistry::lookupTarget(target.triple, err);
|
||||
if (!t)
|
||||
fail(r_log, compile_error(), err);
|
||||
|
||||
std::unique_ptr<TargetMachine> tm {
|
||||
t->createTargetMachine(target.triple, target.cpu, "", {},
|
||||
compat::default_reloc_model,
|
||||
::llvm::CodeModel::Default,
|
||||
::llvm::CodeGenOpt::Default) };
|
||||
if (!tm)
|
||||
fail(r_log, compile_error(),
|
||||
"Could not create TargetMachine: " + target.triple);
|
||||
|
||||
::llvm::SmallVector<char, 1024> data;
|
||||
|
||||
{
|
||||
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() };
|
||||
}
|
||||
|
||||
namespace elf {
|
||||
std::unique_ptr<Elf, int (*)(Elf *)>
|
||||
get(const std::vector<char> &code) {
|
||||
// One of the libelf implementations
|
||||
// (http://www.mr511.de/software/english.htm) requires calling
|
||||
// elf_version() before elf_memory().
|
||||
elf_version(EV_CURRENT);
|
||||
return { elf_memory(const_cast<char *>(code.data()), code.size()),
|
||||
elf_end };
|
||||
}
|
||||
|
||||
Elf_Scn *
|
||||
get_symbol_table(Elf *elf) {
|
||||
size_t section_str_index;
|
||||
elf_getshdrstrndx(elf, §ion_str_index);
|
||||
|
||||
for (Elf_Scn *s = elf_nextscn(elf, NULL); s; s = elf_nextscn(elf, s)) {
|
||||
GElf_Shdr header;
|
||||
if (gelf_getshdr(s, &header) != &header)
|
||||
return nullptr;
|
||||
|
||||
if (!std::strcmp(elf_strptr(elf, section_str_index, header.sh_name),
|
||||
".symtab"))
|
||||
return s;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::map<std::string, unsigned>
|
||||
get_symbol_offsets(Elf *elf, Elf_Scn *symtab) {
|
||||
Elf_Data *const symtab_data = elf_getdata(symtab, NULL);
|
||||
GElf_Shdr header;
|
||||
if (gelf_getshdr(symtab, &header) != &header)
|
||||
return {};
|
||||
|
||||
std::map<std::string, unsigned> symbol_offsets;
|
||||
GElf_Sym symbol;
|
||||
unsigned i = 0;
|
||||
|
||||
while (GElf_Sym *s = gelf_getsym(symtab_data, i++, &symbol)) {
|
||||
const char *name = elf_strptr(elf, header.sh_link, s->st_name);
|
||||
symbol_offsets[name] = s->st_value;
|
||||
}
|
||||
|
||||
return symbol_offsets;
|
||||
}
|
||||
}
|
||||
|
||||
std::map<std::string, unsigned>
|
||||
get_symbol_offsets(const std::vector<char> &code,
|
||||
std::string &r_log) {
|
||||
const auto elf = elf::get(code);
|
||||
const auto symtab = elf::get_symbol_table(elf.get());
|
||||
if (!symtab)
|
||||
fail(r_log, compile_error(), "Unable to find symbol table.");
|
||||
|
||||
return elf::get_symbol_offsets(elf.get(), symtab);
|
||||
}
|
||||
|
||||
module
|
||||
build_module_native(::llvm::Module &mod, const target &target,
|
||||
const clang::CompilerInstance &c,
|
||||
std::string &r_log) {
|
||||
const auto code = emit_code(mod, target,
|
||||
TargetMachine::CGFT_ObjectFile, r_log);
|
||||
return build_module_common(mod, code, get_symbol_offsets(code, r_log), c);
|
||||
}
|
||||
|
||||
std::string
|
||||
print_module_native(const ::llvm::Module &mod, const target &target) {
|
||||
std::string log;
|
||||
try {
|
||||
std::unique_ptr<llvm::Module> cmod { CloneModule(&mod) };
|
||||
return as_string(emit_code(*cmod, target,
|
||||
TargetMachine::CGFT_AssemblyFile, log));
|
||||
} catch (...) {
|
||||
return "Couldn't output native disassembly: " + log;
|
||||
}
|
||||
}
|
||||
} // End anonymous namespace
|
||||
|
||||
module
|
||||
|
|
Loading…
Reference in New Issue