1bf215546Sopenharmony_ci//
2bf215546Sopenharmony_ci// Copyright 2012-2016 Francisco Jerez
3bf215546Sopenharmony_ci// Copyright 2012-2016 Advanced Micro Devices, Inc.
4bf215546Sopenharmony_ci//
5bf215546Sopenharmony_ci// Permission is hereby granted, free of charge, to any person obtaining a
6bf215546Sopenharmony_ci// copy of this software and associated documentation files (the "Software"),
7bf215546Sopenharmony_ci// to deal in the Software without restriction, including without limitation
8bf215546Sopenharmony_ci// the rights to use, copy, modify, merge, publish, distribute, sublicense,
9bf215546Sopenharmony_ci// and/or sell copies of the Software, and to permit persons to whom the
10bf215546Sopenharmony_ci// Software is furnished to do so, subject to the following conditions:
11bf215546Sopenharmony_ci//
12bf215546Sopenharmony_ci// The above copyright notice and this permission notice shall be included in
13bf215546Sopenharmony_ci// all copies or substantial portions of the Software.
14bf215546Sopenharmony_ci//
15bf215546Sopenharmony_ci// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19bf215546Sopenharmony_ci// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20bf215546Sopenharmony_ci// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21bf215546Sopenharmony_ci// OTHER DEALINGS IN THE SOFTWARE.
22bf215546Sopenharmony_ci//
23bf215546Sopenharmony_ci
24bf215546Sopenharmony_ci///
25bf215546Sopenharmony_ci/// \file
26bf215546Sopenharmony_ci/// Generate code using an arbitrary LLVM back-end capable of emitting
27bf215546Sopenharmony_ci/// executable code as an ELF object file.
28bf215546Sopenharmony_ci///
29bf215546Sopenharmony_ci
30bf215546Sopenharmony_ci#include <llvm/Target/TargetMachine.h>
31bf215546Sopenharmony_ci#include <llvm/Transforms/Utils/Cloning.h>
32bf215546Sopenharmony_ci
33bf215546Sopenharmony_ci#include "llvm/codegen.hpp"
34bf215546Sopenharmony_ci#include "llvm/compat.hpp"
35bf215546Sopenharmony_ci#include "llvm/util.hpp"
36bf215546Sopenharmony_ci#include "core/error.hpp"
37bf215546Sopenharmony_ci
38bf215546Sopenharmony_ciusing clover::binary;
39bf215546Sopenharmony_ciusing clover::build_error;
40bf215546Sopenharmony_ciusing namespace clover::llvm;
41bf215546Sopenharmony_ciusing ::llvm::TargetMachine;
42bf215546Sopenharmony_ci
43bf215546Sopenharmony_ci#ifdef HAVE_CLOVER_NATIVE
44bf215546Sopenharmony_ci
45bf215546Sopenharmony_ci#include <libelf.h>
46bf215546Sopenharmony_ci#include <gelf.h>
47bf215546Sopenharmony_ci
48bf215546Sopenharmony_cinamespace {
49bf215546Sopenharmony_ci   namespace elf {
50bf215546Sopenharmony_ci      std::unique_ptr<Elf, int (*)(Elf *)>
51bf215546Sopenharmony_ci      get(const std::vector<char> &code) {
52bf215546Sopenharmony_ci         // One of the libelf implementations
53bf215546Sopenharmony_ci         // (http://www.mr511.de/software/english.htm) requires calling
54bf215546Sopenharmony_ci         // elf_version() before elf_memory().
55bf215546Sopenharmony_ci         elf_version(EV_CURRENT);
56bf215546Sopenharmony_ci         return { elf_memory(const_cast<char *>(code.data()), code.size()),
57bf215546Sopenharmony_ci                  elf_end };
58bf215546Sopenharmony_ci      }
59bf215546Sopenharmony_ci
60bf215546Sopenharmony_ci      Elf_Scn *
61bf215546Sopenharmony_ci      get_symbol_table(Elf *elf) {
62bf215546Sopenharmony_ci         size_t section_str_index;
63bf215546Sopenharmony_ci         elf_getshdrstrndx(elf, &section_str_index);
64bf215546Sopenharmony_ci
65bf215546Sopenharmony_ci         for (Elf_Scn *s = elf_nextscn(elf, NULL); s; s = elf_nextscn(elf, s)) {
66bf215546Sopenharmony_ci            GElf_Shdr header;
67bf215546Sopenharmony_ci            if (gelf_getshdr(s, &header) != &header)
68bf215546Sopenharmony_ci               return nullptr;
69bf215546Sopenharmony_ci
70bf215546Sopenharmony_ci            if (!std::strcmp(elf_strptr(elf, section_str_index, header.sh_name),
71bf215546Sopenharmony_ci                             ".symtab"))
72bf215546Sopenharmony_ci               return s;
73bf215546Sopenharmony_ci         }
74bf215546Sopenharmony_ci
75bf215546Sopenharmony_ci         return nullptr;
76bf215546Sopenharmony_ci      }
77bf215546Sopenharmony_ci
78bf215546Sopenharmony_ci      std::map<std::string, unsigned>
79bf215546Sopenharmony_ci      get_symbol_offsets(Elf *elf, Elf_Scn *symtab) {
80bf215546Sopenharmony_ci         Elf_Data *const symtab_data = elf_getdata(symtab, NULL);
81bf215546Sopenharmony_ci         GElf_Shdr header;
82bf215546Sopenharmony_ci         if (gelf_getshdr(symtab, &header) != &header)
83bf215546Sopenharmony_ci            return {};
84bf215546Sopenharmony_ci
85bf215546Sopenharmony_ci         std::map<std::string, unsigned> symbol_offsets;
86bf215546Sopenharmony_ci         GElf_Sym symbol;
87bf215546Sopenharmony_ci         unsigned i = 0;
88bf215546Sopenharmony_ci
89bf215546Sopenharmony_ci         while (GElf_Sym *s = gelf_getsym(symtab_data, i++, &symbol)) {
90bf215546Sopenharmony_ci            const char *name = elf_strptr(elf, header.sh_link, s->st_name);
91bf215546Sopenharmony_ci            symbol_offsets[name] = s->st_value;
92bf215546Sopenharmony_ci         }
93bf215546Sopenharmony_ci
94bf215546Sopenharmony_ci         return symbol_offsets;
95bf215546Sopenharmony_ci      }
96bf215546Sopenharmony_ci   }
97bf215546Sopenharmony_ci
98bf215546Sopenharmony_ci   std::map<std::string, unsigned>
99bf215546Sopenharmony_ci   get_symbol_offsets(const std::vector<char> &code, std::string &r_log) {
100bf215546Sopenharmony_ci      const auto elf = elf::get(code);
101bf215546Sopenharmony_ci      const auto symtab = elf::get_symbol_table(elf.get());
102bf215546Sopenharmony_ci      if (!symtab)
103bf215546Sopenharmony_ci         fail(r_log, build_error(), "Unable to find symbol table.");
104bf215546Sopenharmony_ci
105bf215546Sopenharmony_ci      return elf::get_symbol_offsets(elf.get(), symtab);
106bf215546Sopenharmony_ci   }
107bf215546Sopenharmony_ci
108bf215546Sopenharmony_ci   std::vector<char>
109bf215546Sopenharmony_ci   emit_code(::llvm::Module &mod, const target &target,
110bf215546Sopenharmony_ci             compat::CodeGenFileType ft,
111bf215546Sopenharmony_ci             std::string &r_log) {
112bf215546Sopenharmony_ci      std::string err;
113bf215546Sopenharmony_ci      auto t = ::llvm::TargetRegistry::lookupTarget(target.triple, err);
114bf215546Sopenharmony_ci      if (!t)
115bf215546Sopenharmony_ci         fail(r_log, build_error(), err);
116bf215546Sopenharmony_ci
117bf215546Sopenharmony_ci      std::unique_ptr<TargetMachine> tm {
118bf215546Sopenharmony_ci         t->createTargetMachine(target.triple, target.cpu, "", {},
119bf215546Sopenharmony_ci                                ::llvm::None, ::llvm::None,
120bf215546Sopenharmony_ci                                ::llvm::CodeGenOpt::Default) };
121bf215546Sopenharmony_ci      if (!tm)
122bf215546Sopenharmony_ci         fail(r_log, build_error(),
123bf215546Sopenharmony_ci              "Could not create TargetMachine: " + target.triple);
124bf215546Sopenharmony_ci
125bf215546Sopenharmony_ci      ::llvm::SmallVector<char, 1024> data;
126bf215546Sopenharmony_ci
127bf215546Sopenharmony_ci      {
128bf215546Sopenharmony_ci         ::llvm::legacy::PassManager pm;
129bf215546Sopenharmony_ci         ::llvm::raw_svector_ostream os { data };
130bf215546Sopenharmony_ci
131bf215546Sopenharmony_ci         mod.setDataLayout(tm->createDataLayout());
132bf215546Sopenharmony_ci         tm->Options.MCOptions.AsmVerbose =
133bf215546Sopenharmony_ci            (ft == compat::CGFT_AssemblyFile);
134bf215546Sopenharmony_ci
135bf215546Sopenharmony_ci         if (tm->addPassesToEmitFile(pm, os, nullptr, ft))
136bf215546Sopenharmony_ci            fail(r_log, build_error(), "TargetMachine can't emit this file");
137bf215546Sopenharmony_ci
138bf215546Sopenharmony_ci         pm.run(mod);
139bf215546Sopenharmony_ci      }
140bf215546Sopenharmony_ci
141bf215546Sopenharmony_ci      return { data.begin(), data.end() };
142bf215546Sopenharmony_ci   }
143bf215546Sopenharmony_ci}
144bf215546Sopenharmony_ci
145bf215546Sopenharmony_cibinary
146bf215546Sopenharmony_ciclover::llvm::build_module_native(::llvm::Module &mod, const target &target,
147bf215546Sopenharmony_ci                                  const clang::CompilerInstance &c,
148bf215546Sopenharmony_ci                                  std::string &r_log) {
149bf215546Sopenharmony_ci   const auto code = emit_code(mod, target,
150bf215546Sopenharmony_ci                               compat::CGFT_ObjectFile, r_log);
151bf215546Sopenharmony_ci   return build_module_common(mod, code, get_symbol_offsets(code, r_log), c);
152bf215546Sopenharmony_ci}
153bf215546Sopenharmony_ci
154bf215546Sopenharmony_cistd::string
155bf215546Sopenharmony_ciclover::llvm::print_module_native(const ::llvm::Module &mod,
156bf215546Sopenharmony_ci                                  const target &target) {
157bf215546Sopenharmony_ci   std::string log;
158bf215546Sopenharmony_ci   try {
159bf215546Sopenharmony_ci      std::unique_ptr< ::llvm::Module> cmod { ::llvm::CloneModule(mod) };
160bf215546Sopenharmony_ci      return as_string(emit_code(*cmod, target,
161bf215546Sopenharmony_ci                                 compat::CGFT_AssemblyFile, log));
162bf215546Sopenharmony_ci   } catch (...) {
163bf215546Sopenharmony_ci      return "Couldn't output native disassembly: " + log;
164bf215546Sopenharmony_ci   }
165bf215546Sopenharmony_ci}
166bf215546Sopenharmony_ci
167bf215546Sopenharmony_ci#else
168bf215546Sopenharmony_ci
169bf215546Sopenharmony_cibinary
170bf215546Sopenharmony_ciclover::llvm::build_module_native(::llvm::Module &mod, const target &target,
171bf215546Sopenharmony_ci                                  const clang::CompilerInstance &c,
172bf215546Sopenharmony_ci                                  std::string &r_log) {
173bf215546Sopenharmony_ci   unreachable("Native codegen support disabled at build time");
174bf215546Sopenharmony_ci}
175bf215546Sopenharmony_ci
176bf215546Sopenharmony_cistd::string
177bf215546Sopenharmony_ciclover::llvm::print_module_native(const ::llvm::Module &mod,
178bf215546Sopenharmony_ci                                  const target &target) {
179bf215546Sopenharmony_ci   unreachable("Native codegen support disabled at build time");
180bf215546Sopenharmony_ci}
181bf215546Sopenharmony_ci
182bf215546Sopenharmony_ci#endif
183