From 520cc268593edad750d0dbab520a715c31a5c230 Mon Sep 17 00:00:00 2001
From: Francisco Jerez <currojerez@riseup.net>
Date: Sun, 19 Jun 2016 17:56:15 -0700
Subject: clover/llvm: Split native codegen into separate file.

Reviewed-by: Serge Martin <edb+mesa@sigluy.net>
Tested-by: Jan Vesely <jan.vesely@rutgers.edu>
---
 src/gallium/state_trackers/clover/Makefile.sources |   1 +
 src/gallium/state_trackers/clover/llvm/codegen.hpp |   9 ++
 .../state_trackers/clover/llvm/codegen/native.cpp  | 165 +++++++++++++++++++++
 .../state_trackers/clover/llvm/invocation.cpp      | 119 ---------------
 4 files changed, 175 insertions(+), 119 deletions(-)
 create mode 100644 src/gallium/state_trackers/clover/llvm/codegen/native.cpp

diff --git a/src/gallium/state_trackers/clover/Makefile.sources b/src/gallium/state_trackers/clover/Makefile.sources
index bf0a5331938..0d1fb8cb018 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 929bbda004f..c4d4997dfed 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>
@@ -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,
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 00000000000..4adb05f5633
--- /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, &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);
+   }
+
+   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 54e2866966b..1d7b0d34924 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, &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
-- 
cgit v1.2.3