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:
Francisco Jerez
2016-06-19 17:56:15 -07:00
parent 8195637363
commit 520cc26859
4 changed files with 175 additions and 119 deletions

View File

@@ -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, &section_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