diff options
Diffstat (limited to 'src')
4 files changed, 175 insertions, 119 deletions
diff --git a/src/gallium/state_trackers/clover/Makefile.sources b/src/gallium/state_trackers/clover/Makefile.sources index bf0a533..0d1fb8c 100644 --- a/src/gallium/state_trackers/clover/Makefile.sources +++ b/src/gallium/state_trackers/clover/Makefile.sources @@ -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 \ diff --git a/src/gallium/state_trackers/clover/llvm/codegen.hpp b/src/gallium/state_trackers/clover/llvm/codegen.hpp index 929bbda..c4d4997 100644 --- a/src/gallium/state_trackers/clover/llvm/codegen.hpp +++ b/src/gallium/state_trackers/clover/llvm/codegen.hpp @@ -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> @@ -45,6 +46,14 @@ namespace clover { 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, const std::map<std::string, unsigned> &offsets, diff --git a/src/gallium/state_trackers/clover/llvm/codegen/native.cpp b/src/gallium/state_trackers/clover/llvm/codegen/native.cpp new file mode 100644 index 0000000..4adb05f --- /dev/null +++ b/src/gallium/state_trackers/clover/llvm/codegen/native.cpp @@ -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; + } +} diff --git a/src/gallium/state_trackers/clover/llvm/invocation.cpp b/src/gallium/state_trackers/clover/llvm/invocation.cpp index 54e2866..1d7b0d3 100644 --- a/src/gallium/state_trackers/clover/llvm/invocation.cpp +++ b/src/gallium/state_trackers/clover/llvm/invocation.cpp @@ -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 |