Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
numba
GitHub Repository: numba/llvmlite
Path: blob/main/ffi/executionengine.cpp
1154 views
1
#include "core.h"
2
#include "memorymanager.h"
3
4
#include "llvm-c/ExecutionEngine.h"
5
#include "llvm-c/Object.h"
6
7
#include "llvm/ExecutionEngine/ExecutionEngine.h"
8
#include "llvm/ExecutionEngine/JITEventListener.h"
9
#include "llvm/ExecutionEngine/ObjectCache.h"
10
#include "llvm/IR/Module.h"
11
#include "llvm/Object/Binary.h"
12
#include "llvm/Object/ObjectFile.h"
13
#include "llvm/Support/Memory.h"
14
15
#include <cstdio>
16
#include <memory>
17
18
namespace llvm {
19
20
// wrap/unwrap for LLVMTargetMachineRef.
21
// Ripped from lib/Target/TargetMachineC.cpp.
22
23
inline TargetMachine *unwrap(LLVMTargetMachineRef P) {
24
return reinterpret_cast<TargetMachine *>(P);
25
}
26
inline LLVMTargetMachineRef wrap(const TargetMachine *P) {
27
return reinterpret_cast<LLVMTargetMachineRef>(
28
const_cast<TargetMachine *>(P));
29
}
30
31
// unwrap for LLVMObjectFileRef
32
// from Object/Object.cpp
33
namespace object {
34
35
inline OwningBinary<ObjectFile> *unwrap(LLVMObjectFileRef OF) {
36
return reinterpret_cast<OwningBinary<ObjectFile> *>(OF);
37
}
38
} // namespace object
39
} // namespace llvm
40
41
extern "C" {
42
43
API_EXPORT(void)
44
LLVMPY_LinkInMCJIT() { LLVMLinkInMCJIT(); }
45
46
API_EXPORT(void)
47
LLVMPY_DisposeExecutionEngine(LLVMExecutionEngineRef EE) {
48
LLVMDisposeExecutionEngine(EE);
49
}
50
51
API_EXPORT(void)
52
LLVMPY_AddModule(LLVMExecutionEngineRef EE, LLVMModuleRef M) {
53
LLVMAddModule(EE, M);
54
}
55
56
API_EXPORT(int)
57
LLVMPY_RemoveModule(LLVMExecutionEngineRef EE, LLVMModuleRef M,
58
char **OutError) {
59
return LLVMRemoveModule(EE, M, &M, OutError);
60
}
61
62
API_EXPORT(void)
63
LLVMPY_FinalizeObject(LLVMExecutionEngineRef EE) {
64
llvm::unwrap(EE)->finalizeObject();
65
}
66
67
static LLVMExecutionEngineRef create_execution_engine(LLVMModuleRef M,
68
LLVMTargetMachineRef TM,
69
bool use_lmm,
70
const char **OutError) {
71
LLVMExecutionEngineRef ee = nullptr;
72
73
llvm::EngineBuilder eb(std::unique_ptr<llvm::Module>(llvm::unwrap(M)));
74
std::string err;
75
eb.setErrorStr(&err);
76
eb.setEngineKind(llvm::EngineKind::JIT);
77
78
if (use_lmm) {
79
std::unique_ptr<llvm::RTDyldMemoryManager> mm =
80
std::make_unique<llvm::LlvmliteMemoryManager>();
81
eb.setMCJITMemoryManager(std::move(mm));
82
}
83
84
/* EngineBuilder::create loads the current process symbols */
85
llvm::ExecutionEngine *engine = eb.create(llvm::unwrap(TM));
86
87
if (!engine)
88
*OutError = LLVMPY_CreateString(err.c_str());
89
else
90
ee = llvm::wrap(engine);
91
return ee;
92
}
93
94
API_EXPORT(LLVMExecutionEngineRef)
95
LLVMPY_CreateMCJITCompiler(LLVMModuleRef M, LLVMTargetMachineRef TM,
96
bool use_lmm, const char **OutError) {
97
return create_execution_engine(M, TM, use_lmm, OutError);
98
}
99
100
API_EXPORT(uint64_t)
101
LLVMPY_GetGlobalValueAddress(LLVMExecutionEngineRef EE, const char *Name) {
102
return LLVMGetGlobalValueAddress(EE, Name);
103
}
104
105
API_EXPORT(uint64_t)
106
LLVMPY_GetFunctionAddress(LLVMExecutionEngineRef EE, const char *Name) {
107
return LLVMGetFunctionAddress(EE, Name);
108
}
109
110
API_EXPORT(void)
111
LLVMPY_RunStaticConstructors(LLVMExecutionEngineRef EE) {
112
return LLVMRunStaticConstructors(EE);
113
}
114
115
API_EXPORT(void)
116
LLVMPY_RunStaticDestructors(LLVMExecutionEngineRef EE) {
117
return LLVMRunStaticDestructors(EE);
118
}
119
120
API_EXPORT(void)
121
LLVMPY_AddGlobalMapping(LLVMExecutionEngineRef EE, LLVMValueRef Global,
122
void *Addr) {
123
LLVMAddGlobalMapping(EE, Global, Addr);
124
}
125
126
API_EXPORT(LLVMTargetDataRef)
127
LLVMPY_GetExecutionEngineTargetData(LLVMExecutionEngineRef EE) {
128
return LLVMGetExecutionEngineTargetData(EE);
129
}
130
131
API_EXPORT(int)
132
LLVMPY_TryAllocateExecutableMemory(void) {
133
using namespace llvm::sys;
134
std::error_code ec;
135
MemoryBlock mb = Memory::allocateMappedMemory(
136
4096, nullptr, Memory::MF_READ | Memory::MF_WRITE, ec);
137
if (!ec) {
138
ec = Memory::protectMappedMemory(mb, Memory::MF_READ | Memory::MF_EXEC);
139
(void)Memory::releaseMappedMemory(mb); /* Should always succeed */
140
}
141
return ec.value();
142
}
143
144
API_EXPORT(bool)
145
LLVMPY_EnableJITEvents(LLVMExecutionEngineRef EE) {
146
llvm::JITEventListener *listener;
147
bool result = false;
148
149
#ifdef __linux__
150
listener = llvm::JITEventListener::createOProfileJITEventListener();
151
// if listener is null, then LLVM was not compiled for OProfile JIT events.
152
if (listener) {
153
llvm::unwrap(EE)->RegisterJITEventListener(listener);
154
result = true;
155
}
156
#endif
157
listener = llvm::JITEventListener::createIntelJITEventListener();
158
// if listener is null, then LLVM was not compiled for Intel JIT events.
159
if (listener) {
160
llvm::unwrap(EE)->RegisterJITEventListener(listener);
161
result = true;
162
}
163
return result;
164
}
165
166
API_EXPORT(void)
167
LLVMPY_MCJITAddObjectFile(LLVMExecutionEngineRef EE, LLVMObjectFileRef ObjF) {
168
using namespace llvm;
169
using namespace llvm::object;
170
auto engine = unwrap(EE);
171
auto object_file = unwrap(ObjF);
172
auto binary_tuple = object_file->takeBinary();
173
174
engine->addObjectFile(
175
{std::move(binary_tuple.first), std::move(binary_tuple.second)});
176
}
177
178
//
179
// Object cache
180
//
181
182
typedef struct {
183
LLVMModuleRef modref;
184
const char *buf_ptr;
185
size_t buf_len;
186
} ObjectCacheData;
187
188
typedef void (*ObjectCacheNotifyFunc)(void *, const ObjectCacheData *);
189
typedef void (*ObjectCacheGetObjectFunc)(void *, ObjectCacheData *);
190
191
class LLVMPYObjectCache : public llvm::ObjectCache {
192
public:
193
LLVMPYObjectCache(ObjectCacheNotifyFunc notify_func,
194
ObjectCacheGetObjectFunc getobject_func, void *user_data)
195
: notify_func(notify_func), getobject_func(getobject_func),
196
user_data(user_data) {}
197
198
virtual void notifyObjectCompiled(const llvm::Module *M,
199
llvm::MemoryBufferRef MBR) {
200
if (notify_func) {
201
ObjectCacheData data = {llvm::wrap(M), MBR.getBufferStart(),
202
MBR.getBufferSize()};
203
notify_func(user_data, &data);
204
}
205
}
206
207
// MCJIT will call this function before compiling any module
208
// MCJIT takes ownership of both the MemoryBuffer object and the memory
209
// to which it refers.
210
virtual std::unique_ptr<llvm::MemoryBuffer>
211
getObject(const llvm::Module *M) {
212
std::unique_ptr<llvm::MemoryBuffer> res = nullptr;
213
214
if (getobject_func) {
215
ObjectCacheData data = {llvm::wrap(M), nullptr, 0};
216
217
getobject_func(user_data, &data);
218
if (data.buf_ptr && data.buf_len > 0) {
219
// Assume the returned string was allocated
220
// with LLVMPY_CreateByteString
221
res = llvm::MemoryBuffer::getMemBufferCopy(
222
llvm::StringRef(data.buf_ptr, data.buf_len));
223
LLVMPY_DisposeString(data.buf_ptr);
224
}
225
}
226
return res;
227
}
228
229
private:
230
ObjectCacheNotifyFunc notify_func;
231
ObjectCacheGetObjectFunc getobject_func;
232
void *user_data;
233
};
234
235
typedef LLVMPYObjectCache *LLVMPYObjectCacheRef;
236
237
API_EXPORT(LLVMPYObjectCacheRef)
238
LLVMPY_CreateObjectCache(ObjectCacheNotifyFunc notify_func,
239
ObjectCacheGetObjectFunc getobject_func,
240
void *user_data) {
241
return new LLVMPYObjectCache(notify_func, getobject_func, user_data);
242
}
243
244
API_EXPORT(void)
245
LLVMPY_DisposeObjectCache(LLVMPYObjectCacheRef C) { delete C; }
246
247
API_EXPORT(void)
248
LLVMPY_SetObjectCache(LLVMExecutionEngineRef EE, LLVMPYObjectCacheRef C) {
249
llvm::unwrap(EE)->setObjectCache(C);
250
}
251
252
} // end extern "C"
253
254