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