Path: blob/21.2-virgl/src/gallium/frontends/clover/llvm/codegen/native.cpp
4574 views
//1// Copyright 2012-2016 Francisco Jerez2// Copyright 2012-2016 Advanced Micro Devices, Inc.3//4// Permission is hereby granted, free of charge, to any person obtaining a5// copy of this software and associated documentation files (the "Software"),6// to deal in the Software without restriction, including without limitation7// the rights to use, copy, modify, merge, publish, distribute, sublicense,8// and/or sell copies of the Software, and to permit persons to whom the9// Software is furnished to do so, subject to the following conditions:10//11// The above copyright notice and this permission notice shall be included in12// all copies or substantial portions of the Software.13//14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR18// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,19// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR20// OTHER DEALINGS IN THE SOFTWARE.21//2223///24/// \file25/// Generate code using an arbitrary LLVM back-end capable of emitting26/// executable code as an ELF object file.27///2829#include <llvm/Target/TargetMachine.h>30#include <llvm/Support/TargetRegistry.h>31#include <llvm/Transforms/Utils/Cloning.h>3233#include "llvm/codegen.hpp"34#include "llvm/compat.hpp"35#include "llvm/util.hpp"36#include "core/error.hpp"3738using clover::module;39using clover::build_error;40using namespace clover::llvm;41using ::llvm::TargetMachine;4243#ifdef HAVE_CLOVER_NATIVE4445#include <libelf.h>46#include <gelf.h>4748namespace {49namespace elf {50std::unique_ptr<Elf, int (*)(Elf *)>51get(const std::vector<char> &code) {52// One of the libelf implementations53// (http://www.mr511.de/software/english.htm) requires calling54// elf_version() before elf_memory().55elf_version(EV_CURRENT);56return { elf_memory(const_cast<char *>(code.data()), code.size()),57elf_end };58}5960Elf_Scn *61get_symbol_table(Elf *elf) {62size_t section_str_index;63elf_getshdrstrndx(elf, §ion_str_index);6465for (Elf_Scn *s = elf_nextscn(elf, NULL); s; s = elf_nextscn(elf, s)) {66GElf_Shdr header;67if (gelf_getshdr(s, &header) != &header)68return nullptr;6970if (!std::strcmp(elf_strptr(elf, section_str_index, header.sh_name),71".symtab"))72return s;73}7475return nullptr;76}7778std::map<std::string, unsigned>79get_symbol_offsets(Elf *elf, Elf_Scn *symtab) {80Elf_Data *const symtab_data = elf_getdata(symtab, NULL);81GElf_Shdr header;82if (gelf_getshdr(symtab, &header) != &header)83return {};8485std::map<std::string, unsigned> symbol_offsets;86GElf_Sym symbol;87unsigned i = 0;8889while (GElf_Sym *s = gelf_getsym(symtab_data, i++, &symbol)) {90const char *name = elf_strptr(elf, header.sh_link, s->st_name);91symbol_offsets[name] = s->st_value;92}9394return symbol_offsets;95}96}9798std::map<std::string, unsigned>99get_symbol_offsets(const std::vector<char> &code, std::string &r_log) {100const auto elf = elf::get(code);101const auto symtab = elf::get_symbol_table(elf.get());102if (!symtab)103fail(r_log, build_error(), "Unable to find symbol table.");104105return elf::get_symbol_offsets(elf.get(), symtab);106}107108std::vector<char>109emit_code(::llvm::Module &mod, const target &target,110compat::CodeGenFileType ft,111std::string &r_log) {112std::string err;113auto t = ::llvm::TargetRegistry::lookupTarget(target.triple, err);114if (!t)115fail(r_log, build_error(), err);116117std::unique_ptr<TargetMachine> tm {118t->createTargetMachine(target.triple, target.cpu, "", {},119::llvm::None, ::llvm::None,120::llvm::CodeGenOpt::Default) };121if (!tm)122fail(r_log, build_error(),123"Could not create TargetMachine: " + target.triple);124125::llvm::SmallVector<char, 1024> data;126127{128::llvm::legacy::PassManager pm;129::llvm::raw_svector_ostream os { data };130131mod.setDataLayout(tm->createDataLayout());132tm->Options.MCOptions.AsmVerbose =133(ft == compat::CGFT_AssemblyFile);134135if (tm->addPassesToEmitFile(pm, os, nullptr, ft))136fail(r_log, build_error(), "TargetMachine can't emit this file");137138pm.run(mod);139}140141return { data.begin(), data.end() };142}143}144145module146clover::llvm::build_module_native(::llvm::Module &mod, const target &target,147const clang::CompilerInstance &c,148std::string &r_log) {149const auto code = emit_code(mod, target,150compat::CGFT_ObjectFile, r_log);151return build_module_common(mod, code, get_symbol_offsets(code, r_log), c);152}153154std::string155clover::llvm::print_module_native(const ::llvm::Module &mod,156const target &target) {157std::string log;158try {159std::unique_ptr< ::llvm::Module> cmod { ::llvm::CloneModule(mod) };160return as_string(emit_code(*cmod, target,161compat::CGFT_AssemblyFile, log));162} catch (...) {163return "Couldn't output native disassembly: " + log;164}165}166167#else168169module170clover::llvm::build_module_native(::llvm::Module &mod, const target &target,171const clang::CompilerInstance &c,172std::string &r_log) {173unreachable("Native codegen support disabled at build time");174}175176std::string177clover::llvm::print_module_native(const ::llvm::Module &mod,178const target &target) {179unreachable("Native codegen support disabled at build time");180}181182#endif183184185