Branch data Line data Source code
1 : : // This file is a part of Julia. License is MIT: https://julialang.org/license
2 : :
3 : : #include "llvm-version.h"
4 : : #include "platform.h"
5 : : #include <stdint.h>
6 : :
7 : : #include "llvm/IR/Mangler.h"
8 : : #include <llvm/ADT/StringMap.h>
9 : : #include <llvm/Analysis/TargetLibraryInfo.h>
10 : : #include <llvm/Analysis/TargetTransformInfo.h>
11 : : #include <llvm/ExecutionEngine/Orc/CompileUtils.h>
12 : : #include <llvm/ExecutionEngine/Orc/ExecutionUtils.h>
13 : : #if JL_LLVM_VERSION >= 130000
14 : : #include <llvm/ExecutionEngine/Orc/ExecutorProcessControl.h>
15 : : #endif
16 : : #include <llvm/Support/DynamicLibrary.h>
17 : : #include <llvm/Support/FormattedStream.h>
18 : : #include <llvm/Support/SmallVectorMemoryBuffer.h>
19 : : #include <llvm/Support/raw_ostream.h>
20 : : #include <llvm/Transforms/Utils/Cloning.h>
21 : : #include <llvm/Transforms/Utils/ModuleUtils.h>
22 : : #include <llvm/Bitcode/BitcodeWriter.h>
23 : :
24 : : // target machine computation
25 : : #include <llvm/CodeGen/TargetSubtargetInfo.h>
26 : : #if JL_LLVM_VERSION >= 140000
27 : : #include <llvm/MC/TargetRegistry.h>
28 : : #else
29 : : #include <llvm/Support/TargetRegistry.h>
30 : : #endif
31 : : #include <llvm/Target/TargetOptions.h>
32 : : #include <llvm/Support/Host.h>
33 : : #include <llvm/Support/TargetSelect.h>
34 : : #include <llvm/Object/SymbolSize.h>
35 : :
36 : : using namespace llvm;
37 : :
38 : : #include "julia.h"
39 : : #include "julia_internal.h"
40 : : #include "codegen_shared.h"
41 : : #include "jitlayers.h"
42 : : #include "julia_assert.h"
43 : : #include "processor.h"
44 : :
45 : : #ifdef JL_USE_JITLINK
46 : : # if JL_LLVM_VERSION >= 140000
47 : : # include <llvm/ExecutionEngine/Orc/DebuggerSupportPlugin.h>
48 : : # endif
49 : : # include <llvm/ExecutionEngine/JITLink/EHFrameSupport.h>
50 : : # include <llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h>
51 : : #else
52 : : # include <llvm/ExecutionEngine/SectionMemoryManager.h>
53 : : #endif
54 : :
55 : : #define DEBUG_TYPE "jitlayers"
56 : :
57 : : // Snooping on which functions are being compiled, and how long it takes
58 : : extern "C" JL_DLLEXPORT
59 : 4 : void jl_dump_compiles_impl(void *s)
60 : : {
61 : 4 : **jl_ExecutionEngine->get_dump_compiles_stream() = (JL_STREAM*)s;
62 : 4 : }
63 : : extern "C" JL_DLLEXPORT
64 : 2 : void jl_dump_llvm_opt_impl(void *s)
65 : : {
66 : 2 : **jl_ExecutionEngine->get_dump_llvm_opt_stream() = (JL_STREAM*)s;
67 : 2 : }
68 : :
69 : : static void jl_add_to_ee(orc::ThreadSafeModule &M, StringMap<orc::ThreadSafeModule*> &NewExports);
70 : : static void jl_decorate_module(Module &M);
71 : : static uint64_t getAddressForFunction(StringRef fname);
72 : :
73 : 179327 : void jl_link_global(GlobalVariable *GV, void *addr)
74 : : {
75 : 179327 : Constant *P = literal_static_pointer_val(addr, GV->getValueType());
76 : 179327 : GV->setInitializer(P);
77 [ - + ]: 179327 : if (jl_options.image_codegen) {
78 : : // If we are forcing imaging mode codegen for debugging,
79 : : // emit external non-const symbol to avoid LLVM optimizing the code
80 : : // similar to non-imaging mode.
81 : 0 : GV->setLinkage(GlobalValue::ExternalLinkage);
82 : : }
83 : : else {
84 : 179327 : GV->setConstant(true);
85 : 179327 : GV->setLinkage(GlobalValue::PrivateLinkage);
86 : 179327 : GV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
87 : : }
88 : 179327 : }
89 : :
90 : 4 : void jl_jit_globals(std::map<void *, GlobalVariable*> &globals)
91 : : {
92 [ - + ]: 4 : for (auto &global : globals) {
93 : 0 : jl_link_global(global.second, global.first);
94 : : }
95 : 4 : }
96 : :
97 : : // this generates llvm code for the lambda info
98 : : // and adds the result to the jitlayers
99 : : // (and the shadow module),
100 : : // and generates code for it
101 : 188320 : static jl_callptr_t _jl_compile_codeinst(
102 : : jl_code_instance_t *codeinst,
103 : : jl_code_info_t *src,
104 : : size_t world,
105 : : orc::ThreadSafeContext context)
106 : : {
107 : : // caller must hold codegen_lock
108 : : // and have disabled finalizers
109 : 188320 : uint64_t start_time = 0;
110 : 188320 : bool timed = !!*jl_ExecutionEngine->get_dump_compiles_stream();
111 [ + + ]: 188320 : if (timed)
112 : 1 : start_time = jl_hrtime();
113 : :
114 [ - + ]: 188320 : assert(jl_is_code_instance(codeinst));
115 [ + - - + : 188320 : assert(codeinst->min_world <= world && (codeinst->max_world >= world || codeinst->max_world == 0) &&
- - ]
116 : : "invalid world for method-instance");
117 [ + - + - ]: 188320 : assert(src && jl_is_code_info(src));
118 : :
119 : 188320 : jl_callptr_t fptr = NULL;
120 : : // emit the code in LLVM IR form
121 : 376629 : jl_codegen_params_t params(std::move(context)); // Locks the context
122 : 188320 : params.cache = true;
123 : 188320 : params.world = world;
124 : 188320 : jl_workqueue_t emitted;
125 : : {
126 : : orc::ThreadSafeModule result_m =
127 : 376629 : jl_create_llvm_module(name_from_method_instance(codeinst->def), params.tsctx, params.imaging);
128 : 376629 : jl_llvm_functions_t decls = jl_emit_codeinst(result_m, codeinst, src, params);
129 [ + - ]: 188310 : if (result_m)
130 : 188310 : emitted[codeinst] = {std::move(result_m), std::move(decls)};
131 : : {
132 : 376620 : auto temp_module = jl_create_llvm_module(name_from_method_instance(codeinst->def), params.tsctx, params.imaging);
133 : 188310 : jl_compile_workqueue(emitted, *temp_module.getModuleUnlocked(), params, CompilationPolicy::Default);
134 : : }
135 : :
136 [ + + ]: 188310 : if (params._shared_module)
137 : 1292 : jl_ExecutionEngine->addModule(std::move(params._shared_module));
138 : 376619 : StringMap<orc::ThreadSafeModule*> NewExports;
139 : 376619 : StringMap<void*> NewGlobals;
140 [ + + ]: 291852 : for (auto &global : params.globals) {
141 : 103542 : NewGlobals[global.second->getName()] = global.first;
142 : : }
143 [ + + ]: 525526 : for (auto &def : emitted) {
144 : 337216 : orc::ThreadSafeModule &TSM = std::get<0>(def.second);
145 : : //The underlying context object is still locked because params is not destroyed yet
146 : 337216 : auto M = TSM.getModuleUnlocked();
147 [ + + ]: 4353980 : for (auto &F : M->global_objects()) {
148 [ + + + + : 4016760 : if (!F.isDeclaration() && F.getLinkage() == GlobalValue::ExternalLinkage) {
+ + ]
149 : 656019 : NewExports[F.getName()] = &TSM;
150 : : }
151 : : }
152 : : // Let's link all globals here also (for now)
153 [ + + ]: 664924 : for (auto &GV : M->globals()) {
154 : 327708 : auto InitValue = NewGlobals.find(GV.getName());
155 [ + + ]: 327708 : if (InitValue != NewGlobals.end()) {
156 : 179327 : jl_link_global(&GV, InitValue->second);
157 : : }
158 : : }
159 : : }
160 [ + + ]: 525525 : for (auto &def : emitted) {
161 : : // Add the results to the execution engine now
162 : 337216 : orc::ThreadSafeModule &M = std::get<0>(def.second);
163 : 337216 : jl_add_to_ee(M, NewExports);
164 : : }
165 : : }
166 : : JL_TIMING(LLVM_MODULE_FINISH);
167 : :
168 [ + + ]: 525524 : for (auto &def : emitted) {
169 : 337215 : jl_code_instance_t *this_code = def.first;
170 : 674430 : jl_llvm_functions_t decls = std::get<1>(def.second);
171 : : jl_callptr_t addr;
172 : 337215 : bool isspecsig = false;
173 [ + + ]: 337215 : if (decls.functionObject == "jl_fptr_args") {
174 : 19041 : addr = jl_fptr_args_addr;
175 : : }
176 [ + + ]: 318174 : else if (decls.functionObject == "jl_fptr_sparam") {
177 : 200 : addr = jl_fptr_sparam_addr;
178 : : }
179 : : else {
180 : 317974 : addr = (jl_callptr_t)getAddressForFunction(decls.functionObject);
181 : 317974 : isspecsig = true;
182 : : }
183 [ + + ]: 337215 : if (jl_atomic_load_relaxed(&this_code->invoke) == NULL) {
184 : : // once set, don't change invoke-ptr, as that leads to race conditions
185 : : // with the (not) simultaneous updates to invoke and specptr
186 [ + - ]: 337214 : if (!decls.specFunctionObject.empty()) {
187 : 337214 : jl_atomic_store_release(&this_code->specptr.fptr, (void*)getAddressForFunction(decls.specFunctionObject));
188 : 337214 : this_code->isspecsig = isspecsig;
189 : : }
190 : 337214 : jl_atomic_store_release(&this_code->invoke, addr);
191 : : }
192 [ + - + - : 1 : else if (jl_atomic_load_relaxed(&this_code->invoke) == jl_fptr_const_return_addr && !decls.specFunctionObject.empty()) {
+ - ]
193 : : // hack to export this pointer value to jl_dump_method_disasm
194 : 1 : jl_atomic_store_release(&this_code->specptr.fptr, (void*)getAddressForFunction(decls.specFunctionObject));
195 : : }
196 [ + + ]: 337215 : if (this_code== codeinst)
197 : 188309 : fptr = addr;
198 : : }
199 : :
200 : 188309 : uint64_t end_time = 0;
201 [ + + ]: 188309 : if (timed)
202 : 1 : end_time = jl_hrtime();
203 : :
204 : : // If logging of the compilation stream is enabled,
205 : : // then dump the method-instance specialization type to the stream
206 : 188309 : jl_method_instance_t *mi = codeinst->def;
207 [ + + ]: 188309 : if (jl_is_method(mi->def.method)) {
208 : 374396 : auto stream = *jl_ExecutionEngine->get_dump_compiles_stream();
209 [ + + ]: 187198 : if (stream) {
210 : 1 : jl_printf(stream, "%" PRIu64 "\t\"", end_time - start_time);
211 : 1 : jl_static_show(stream, mi->specTypes);
212 : 1 : jl_printf(stream, "\"\n");
213 : : }
214 : : }
215 : 188309 : return fptr;
216 : : }
217 : :
218 : : const char *jl_generate_ccallable(LLVMOrcThreadSafeModuleRef llvmmod, void *sysimg_handle, jl_value_t *declrt, jl_value_t *sigt, jl_codegen_params_t ¶ms);
219 : :
220 : : // compile a C-callable alias
221 : : extern "C" JL_DLLEXPORT
222 : 6 : int jl_compile_extern_c_impl(LLVMOrcThreadSafeModuleRef llvmmod, void *p, void *sysimg, jl_value_t *declrt, jl_value_t *sigt)
223 : : {
224 : 6 : JL_LOCK(&jl_codegen_lock);
225 : 6 : uint64_t compiler_start_time = 0;
226 : 6 : uint8_t measure_compile_time_enabled = jl_atomic_load_relaxed(&jl_measure_compile_time_enabled);
227 [ - + ]: 6 : if (measure_compile_time_enabled)
228 : 0 : compiler_start_time = jl_hrtime();
229 : 6 : orc::ThreadSafeContext ctx;
230 : 6 : auto into = unwrap(llvmmod);
231 : 6 : jl_codegen_params_t *pparams = (jl_codegen_params_t*)p;
232 : 6 : orc::ThreadSafeModule backing;
233 [ + - ]: 6 : if (into == NULL) {
234 [ + - ]: 6 : if (!pparams) {
235 : 6 : ctx = jl_ExecutionEngine->acquireContext();
236 : : }
237 [ - + - + ]: 12 : backing = jl_create_llvm_module("cextern", pparams ? pparams->tsctx : ctx, pparams ? pparams->imaging : imaging_default());
238 : 6 : into = &backing;
239 : : }
240 : 6 : jl_codegen_params_t params(into->getContext());
241 [ + - ]: 6 : if (pparams == NULL)
242 : 6 : pparams = ¶ms;
243 [ - + ]: 6 : assert(pparams->tsctx.getContext() == into->getContext().getContext());
244 : 6 : const char *name = jl_generate_ccallable(wrap(into), sysimg, declrt, sigt, *pparams);
245 : 6 : bool success = true;
246 [ + - ]: 6 : if (!sysimg) {
247 [ + + ]: 6 : if (jl_ExecutionEngine->getGlobalValueAddress(name)) {
248 : 2 : success = false;
249 : : }
250 [ + + + - ]: 6 : if (success && p == NULL) {
251 : 4 : jl_jit_globals(params.globals);
252 [ - + ]: 4 : assert(params.workqueue.empty());
253 [ - + ]: 4 : if (params._shared_module)
254 : 0 : jl_ExecutionEngine->addModule(std::move(params._shared_module));
255 : : }
256 [ + + + - ]: 6 : if (success && llvmmod == NULL)
257 : 4 : jl_ExecutionEngine->addModule(std::move(*into));
258 : : }
259 [ + - - + ]: 6 : if (jl_codegen_lock.count == 1 && measure_compile_time_enabled)
260 : 0 : jl_atomic_fetch_add_relaxed(&jl_cumulative_compile_time, (jl_hrtime() - compiler_start_time));
261 [ + - ]: 6 : if (ctx.getContext()) {
262 : 6 : jl_ExecutionEngine->releaseContext(std::move(ctx));
263 : : }
264 : 6 : JL_UNLOCK(&jl_codegen_lock);
265 : 6 : return success;
266 : 6 : }
267 : :
268 : : // declare a C-callable entry point; called during code loading from the toplevel
269 : : extern "C" JL_DLLEXPORT
270 : 4 : void jl_extern_c_impl(jl_value_t *declrt, jl_tupletype_t *sigt)
271 : : {
272 : : // validate arguments. try to do as many checks as possible here to avoid
273 : : // throwing errors later during codegen.
274 [ - + ]: 4 : JL_TYPECHK(@ccallable, type, declrt);
275 [ - + ]: 4 : if (!jl_is_tuple_type(sigt))
276 : 0 : jl_type_error("@ccallable", (jl_value_t*)jl_anytuple_type_type, (jl_value_t*)sigt);
277 : : // check that f is a guaranteed singleton type
278 : 4 : jl_datatype_t *ft = (jl_datatype_t*)jl_tparam0(sigt);
279 [ + - - + ]: 4 : if (!jl_is_datatype(ft) || ft->instance == NULL)
280 : 0 : jl_error("@ccallable: function object must be a singleton");
281 : :
282 : : // compute / validate return type
283 [ + - - + : 4 : if (!jl_is_concrete_type(declrt) || jl_is_kind(declrt))
- + ]
284 : 0 : jl_error("@ccallable: return type must be concrete and correspond to a C type");
285 [ - + ]: 4 : if (!jl_type_mappable_to_c(declrt))
286 : 0 : jl_error("@ccallable: return type doesn't correspond to a C type");
287 : :
288 : : // validate method signature
289 : 4 : size_t i, nargs = jl_nparams(sigt);
290 [ + + ]: 6 : for (i = 1; i < nargs; i++) {
291 : 2 : jl_value_t *ati = jl_tparam(sigt, i);
292 [ + - + - : 2 : if (!jl_is_concrete_type(ati) || jl_is_kind(ati) || !jl_type_mappable_to_c(ati))
- + - + ]
293 : 0 : jl_error("@ccallable: argument types must be concrete");
294 : : }
295 : :
296 : : // save a record of this so that the alias is generated when we write an object file
297 : 4 : jl_method_t *meth = (jl_method_t*)jl_methtable_lookup(ft->name->mt, (jl_value_t*)sigt, jl_atomic_load_acquire(&jl_world_counter));
298 [ - + ]: 4 : if (!jl_is_method(meth))
299 : 0 : jl_error("@ccallable: could not find requested method");
300 : 4 : JL_GC_PUSH1(&meth);
301 : 4 : meth->ccallable = jl_svec2(declrt, (jl_value_t*)sigt);
302 : 4 : jl_gc_wb(meth, meth->ccallable);
303 : 4 : JL_GC_POP();
304 : :
305 : : // create the alias in the current runtime environment
306 : 4 : int success = jl_compile_extern_c(NULL, NULL, NULL, declrt, (jl_value_t*)sigt);
307 [ + + ]: 4 : if (!success)
308 : 1 : jl_error("@ccallable was already defined for this method name");
309 : 3 : }
310 : :
311 : : // this compiles li and emits fptr
312 : : extern "C" JL_DLLEXPORT
313 : 81403900 : jl_code_instance_t *jl_generate_fptr_impl(jl_method_instance_t *mi JL_PROPAGATES_ROOT, size_t world)
314 : : {
315 : 81403900 : JL_LOCK(&jl_codegen_lock); // also disables finalizers, to prevent any unexpected recursion
316 : 81403900 : auto ctx = jl_ExecutionEngine->getContext();
317 : 81403900 : auto &context = *ctx;
318 : 81403900 : uint64_t compiler_start_time = 0;
319 : 81403900 : uint8_t measure_compile_time_enabled = jl_atomic_load_relaxed(&jl_measure_compile_time_enabled);
320 : 81403900 : bool is_recompile = false;
321 [ + + ]: 81403900 : if (measure_compile_time_enabled)
322 : 7 : compiler_start_time = jl_hrtime();
323 : : // if we don't have any decls already, try to generate it now
324 : 81403900 : jl_code_info_t *src = NULL;
325 : 81403900 : JL_GC_PUSH1(&src);
326 : 81403900 : jl_value_t *ci = jl_rettype_inferred(mi, world, world);
327 [ + + ]: 81403900 : jl_code_instance_t *codeinst = (ci == jl_nothing ? NULL : (jl_code_instance_t*)ci);
328 [ + + ]: 81403900 : if (codeinst) {
329 : 58281 : src = (jl_code_info_t*)codeinst->inferred;
330 [ + + ]: 58281 : if ((jl_value_t*)src == jl_nothing)
331 : 4443 : src = NULL;
332 [ + + ]: 53838 : else if (jl_is_method(mi->def.method))
333 : 52828 : src = jl_uncompress_ir(mi->def.method, codeinst, (jl_array_t*)src);
334 : : }
335 : : else {
336 : : // identify whether this is an invalidated method that is being recompiled
337 : 81345700 : is_recompile = jl_atomic_load_relaxed(&mi->cache) != NULL;
338 : : }
339 [ + + + + : 162754000 : if (src == NULL && jl_is_method(mi->def.method) &&
+ + ]
340 [ + + ]: 81350000 : jl_symbol_name(mi->def.method->name)[0] != '@') {
341 [ + - ]: 81265200 : if (mi->def.method->source != jl_nothing) {
342 : : // If the caller didn't provide the source and IR is available,
343 : : // see if it is inferred, or try to infer it for ourself.
344 : : // (but don't bother with typeinf on macros or toplevel thunks)
345 : 81265200 : src = jl_type_infer(mi, world, 0);
346 : : }
347 : : }
348 : 81403900 : jl_code_instance_t *compiled = jl_method_compiled(mi, world);
349 [ + + ]: 81403900 : if (compiled) {
350 : 8929 : codeinst = compiled;
351 : : }
352 [ + + + - ]: 81395000 : else if (src && jl_is_code_info(src)) {
353 [ + + ]: 185181 : if (!codeinst) {
354 : 131339 : codeinst = jl_get_method_inferred(mi, src->rettype, src->min_world, src->max_world);
355 [ + - - + ]: 131339 : if (src->inferred && !codeinst->inferred)
356 : 0 : codeinst->inferred = jl_nothing;
357 : : }
358 : 185181 : _jl_compile_codeinst(codeinst, src, world, context);
359 [ - + ]: 185170 : if (jl_atomic_load_relaxed(&codeinst->invoke) == NULL)
360 : 0 : codeinst = NULL;
361 : : }
362 : : else {
363 : 81209800 : codeinst = NULL;
364 : : }
365 [ + + + + ]: 81403900 : if (jl_codegen_lock.count == 1 && measure_compile_time_enabled) {
366 : 7 : uint64_t t_comp = jl_hrtime() - compiler_start_time;
367 [ + + ]: 7 : if (is_recompile)
368 : 1 : jl_atomic_fetch_add_relaxed(&jl_cumulative_recompile_time, t_comp);
369 : 7 : jl_atomic_fetch_add_relaxed(&jl_cumulative_compile_time, t_comp);
370 : : }
371 : 81403900 : JL_UNLOCK(&jl_codegen_lock);
372 : 81403900 : JL_GC_POP();
373 : 81403900 : return codeinst;
374 : : }
375 : :
376 : : extern "C" JL_DLLEXPORT
377 : 3146 : void jl_generate_fptr_for_unspecialized_impl(jl_code_instance_t *unspec)
378 : : {
379 [ - + ]: 3146 : if (jl_atomic_load_relaxed(&unspec->invoke) != NULL) {
380 : 0 : return;
381 : : }
382 : 3146 : JL_LOCK(&jl_codegen_lock);
383 : 6284 : auto ctx = jl_ExecutionEngine->getContext();
384 : 3146 : auto &context = *ctx;
385 : 3146 : uint64_t compiler_start_time = 0;
386 : 3146 : uint8_t measure_compile_time_enabled = jl_atomic_load_relaxed(&jl_measure_compile_time_enabled);
387 [ - + ]: 3146 : if (measure_compile_time_enabled)
388 : 0 : compiler_start_time = jl_hrtime();
389 [ + - ]: 3146 : if (jl_atomic_load_relaxed(&unspec->invoke) == NULL) {
390 : 3146 : jl_code_info_t *src = NULL;
391 : 3146 : JL_GC_PUSH1(&src);
392 : 3146 : jl_method_t *def = unspec->def->def.method;
393 [ + + ]: 3146 : if (jl_is_method(def)) {
394 : 3045 : src = (jl_code_info_t*)def->source;
395 [ + + ]: 3045 : if (src == NULL) {
396 : : // TODO: this is wrong
397 [ - + ]: 8 : assert(def->generator);
398 : : // TODO: jl_code_for_staged can throw
399 : 8 : src = jl_code_for_staged(unspec->def);
400 : : }
401 [ + - + - ]: 3037 : if (src && (jl_value_t*)src != jl_nothing)
402 : 3037 : src = jl_uncompress_ir(def, NULL, (jl_array_t*)src);
403 : : }
404 : : else {
405 : 101 : src = (jl_code_info_t*)unspec->def->uninferred;
406 : : }
407 [ + - + - ]: 3138 : assert(src && jl_is_code_info(src));
408 : 3138 : _jl_compile_codeinst(unspec, src, unspec->min_world, context);
409 [ - + ]: 3138 : if (jl_atomic_load_relaxed(&unspec->invoke) == NULL) {
410 : : // if we hit a codegen bug (or ran into a broken generated function or llvmcall), fall back to the interpreter as a last resort
411 : 0 : jl_atomic_store_release(&unspec->invoke, jl_fptr_interpret_call_addr);
412 : : }
413 : 3138 : JL_GC_POP();
414 : : }
415 [ + + - + ]: 3138 : if (jl_codegen_lock.count == 1 && measure_compile_time_enabled)
416 : 0 : jl_atomic_fetch_add_relaxed(&jl_cumulative_compile_time, (jl_hrtime() - compiler_start_time));
417 : 3138 : JL_UNLOCK(&jl_codegen_lock); // Might GC
418 : : }
419 : :
420 : :
421 : : // get a native disassembly for a compiled method
422 : : extern "C" JL_DLLEXPORT
423 : 3 : jl_value_t *jl_dump_method_asm_impl(jl_method_instance_t *mi, size_t world,
424 : : char raw_mc, char getwrapper, const char* asm_variant, const char *debuginfo, char binary)
425 : : {
426 : : // printing via disassembly
427 : 3 : jl_code_instance_t *codeinst = jl_generate_fptr(mi, world);
428 [ + - ]: 3 : if (codeinst) {
429 : 3 : uintptr_t fptr = (uintptr_t)jl_atomic_load_relaxed(&codeinst->invoke);
430 [ - + ]: 3 : if (getwrapper)
431 : 0 : return jl_dump_fptr_asm(fptr, raw_mc, asm_variant, debuginfo, binary);
432 : 3 : uintptr_t specfptr = (uintptr_t)jl_atomic_load_relaxed(&codeinst->specptr.fptr);
433 [ + - + + ]: 3 : if (fptr == (uintptr_t)jl_fptr_const_return_addr && specfptr == 0) {
434 : : // normally we prevent native code from being generated for these functions,
435 : : // (using sentinel value `1` instead)
436 : : // so create an exception here so we can print pretty our lies
437 : 1 : JL_LOCK(&jl_codegen_lock); // also disables finalizers, to prevent any unexpected recursion
438 : 2 : auto ctx = jl_ExecutionEngine->getContext();
439 : 1 : auto &context = *ctx;
440 : 1 : uint64_t compiler_start_time = 0;
441 : 1 : uint8_t measure_compile_time_enabled = jl_atomic_load_relaxed(&jl_measure_compile_time_enabled);
442 [ - + ]: 1 : if (measure_compile_time_enabled)
443 : 0 : compiler_start_time = jl_hrtime();
444 : 1 : specfptr = (uintptr_t)jl_atomic_load_relaxed(&codeinst->specptr.fptr);
445 [ + - ]: 1 : if (specfptr == 0) {
446 : 1 : jl_code_info_t *src = jl_type_infer(mi, world, 0);
447 : 1 : JL_GC_PUSH1(&src);
448 : 1 : jl_method_t *def = mi->def.method;
449 [ + - ]: 1 : if (jl_is_method(def)) {
450 [ - + ]: 1 : if (!src) {
451 : : // TODO: jl_code_for_staged can throw
452 [ # # ]: 0 : src = def->generator ? jl_code_for_staged(mi) : (jl_code_info_t*)def->source;
453 : : }
454 [ + - + - ]: 1 : if (src && (jl_value_t*)src != jl_nothing)
455 : 1 : src = jl_uncompress_ir(mi->def.method, codeinst, (jl_array_t*)src);
456 : : }
457 : 1 : fptr = (uintptr_t)jl_atomic_load_relaxed(&codeinst->invoke);
458 : 1 : specfptr = (uintptr_t)jl_atomic_load_relaxed(&codeinst->specptr.fptr);
459 [ + - + - ]: 1 : if (src && jl_is_code_info(src)) {
460 [ + - + - ]: 1 : if (fptr == (uintptr_t)jl_fptr_const_return_addr && specfptr == 0) {
461 : 1 : fptr = (uintptr_t)_jl_compile_codeinst(codeinst, src, world, context);
462 : 1 : specfptr = (uintptr_t)jl_atomic_load_relaxed(&codeinst->specptr.fptr);
463 : : }
464 : : }
465 : 1 : JL_GC_POP();
466 : : }
467 [ - + ]: 1 : if (measure_compile_time_enabled)
468 : 0 : jl_atomic_fetch_add_relaxed(&jl_cumulative_compile_time, (jl_hrtime() - compiler_start_time));
469 : 1 : JL_UNLOCK(&jl_codegen_lock);
470 : : }
471 [ + - ]: 3 : if (specfptr != 0)
472 : 3 : return jl_dump_fptr_asm(specfptr, raw_mc, asm_variant, debuginfo, binary);
473 : : }
474 : :
475 : : // whatever, that didn't work - use the assembler output instead
476 : : jl_llvmf_dump_t llvmf_dump;
477 : 0 : jl_get_llvmf_defn(&llvmf_dump, mi, world, getwrapper, true, jl_default_cgparams);
478 [ # # ]: 0 : if (!llvmf_dump.F)
479 : 0 : return jl_an_empty_string;
480 : 0 : return jl_dump_function_asm(&llvmf_dump, raw_mc, asm_variant, debuginfo, binary);
481 : : }
482 : :
483 : 5103 : CodeGenOpt::Level CodeGenOptLevelFor(int optlevel)
484 : : {
485 : : #ifdef DISABLE_OPT
486 : : return CodeGenOpt::None;
487 : : #else
488 [ + + ]: 7846 : return optlevel < 2 ? CodeGenOpt::None :
489 [ + + ]: 2743 : optlevel == 2 ? CodeGenOpt::Default :
490 : 5103 : CodeGenOpt::Aggressive;
491 : : #endif
492 : : }
493 : :
494 : 2 : static auto countBasicBlocks(const Function &F)
495 : : {
496 : 2 : return std::distance(F.begin(), F.end());
497 : : }
498 : :
499 : 334404 : void JuliaOJIT::OptSelLayerT::emit(std::unique_ptr<orc::MaterializationResponsibility> R, orc::ThreadSafeModule TSM) {
500 : 334404 : size_t optlevel = SIZE_MAX;
501 : 334404 : TSM.withModuleDo([&](Module &M) {
502 [ + + ]: 334404 : if (jl_generating_output()) {
503 : 15065 : optlevel = 0;
504 : : }
505 : : else {
506 : 319339 : optlevel = std::max(static_cast<int>(jl_options.opt_level), 0);
507 : 319339 : size_t optlevel_min = std::max(static_cast<int>(jl_options.opt_level_min), 0);
508 [ + + ]: 3835040 : for (auto &F : M.functions()) {
509 [ + + ]: 3515700 : if (!F.getBasicBlockList().empty()) {
510 : 633657 : Attribute attr = F.getFnAttribute("julia-optimization-level");
511 : 633657 : StringRef val = attr.getValueAsString();
512 [ + + ]: 633657 : if (val != "") {
513 : 2227 : size_t ol = (size_t)val[0] - '0';
514 [ + + ]: 2227 : if (ol < optlevel)
515 : 1933 : optlevel = ol;
516 : : }
517 : : }
518 : : }
519 : 319339 : optlevel = std::min(std::max(optlevel, optlevel_min), this->count);
520 : : }
521 : 334404 : });
522 [ - + ]: 334404 : assert(optlevel != SIZE_MAX && "Failed to select a valid optimization level!");
523 : 334404 : this->optimizers[optlevel]->OptimizeLayer.emit(std::move(R), std::move(TSM));
524 : 334403 : }
525 : :
526 : : void jl_register_jit_object(const object::ObjectFile &debugObj,
527 : : std::function<uint64_t(const StringRef &)> getLoadAddress,
528 : : std::function<void *(void *)> lookupWriteAddress);
529 : :
530 : : #ifdef JL_USE_JITLINK
531 : :
532 : : namespace {
533 : :
534 : : using namespace llvm::orc;
535 : :
536 : : struct JITObjectInfo {
537 : : std::unique_ptr<MemoryBuffer> BackingBuffer;
538 : : std::unique_ptr<object::ObjectFile> Object;
539 : : StringMap<uint64_t> SectionLoadAddresses;
540 : : };
541 : :
542 : : class JLDebuginfoPlugin : public ObjectLinkingLayer::Plugin {
543 : : std::map<MaterializationResponsibility *, std::unique_ptr<JITObjectInfo>> PendingObjs;
544 : : // Resources from distinct MaterializationResponsibilitys can get merged
545 : : // after emission, so we can have multiple debug objects per resource key.
546 : : std::map<ResourceKey, std::vector<std::unique_ptr<JITObjectInfo>>> RegisteredObjs;
547 : :
548 : : public:
549 : : void notifyMaterializing(MaterializationResponsibility &MR, jitlink::LinkGraph &G,
550 : : jitlink::JITLinkContext &Ctx,
551 : : MemoryBufferRef InputObject) override
552 : : {
553 : : // Keeping around a full copy of the input object file (and re-parsing it) is
554 : : // wasteful, but for now, this lets us reuse the existing debuginfo.cpp code.
555 : : // Should look into just directly pulling out all the information required in
556 : : // a JITLink pass and just keeping the required tables/DWARF sections around
557 : : // (perhaps using the LLVM DebuggerSupportPlugin as a reference).
558 : : auto NewBuffer =
559 : : MemoryBuffer::getMemBufferCopy(InputObject.getBuffer(), G.getName());
560 : : auto NewObj =
561 : : cantFail(object::ObjectFile::createObjectFile(NewBuffer->getMemBufferRef()));
562 : :
563 : : assert(PendingObjs.count(&MR) == 0);
564 : : PendingObjs[&MR] = std::unique_ptr<JITObjectInfo>(
565 : : new JITObjectInfo{std::move(NewBuffer), std::move(NewObj), {}});
566 : : }
567 : :
568 : : Error notifyEmitted(MaterializationResponsibility &MR) override
569 : : {
570 : : auto It = PendingObjs.find(&MR);
571 : : if (It == PendingObjs.end())
572 : : return Error::success();
573 : :
574 : : auto NewInfo = PendingObjs[&MR].get();
575 : : auto getLoadAddress = [NewInfo](const StringRef &Name) -> uint64_t {
576 : : auto result = NewInfo->SectionLoadAddresses.find(Name);
577 : : if (result == NewInfo->SectionLoadAddresses.end()) {
578 : : LLVM_DEBUG({
579 : : dbgs() << "JLDebuginfoPlugin: No load address found for section '"
580 : : << Name << "'\n";
581 : : });
582 : : return 0;
583 : : }
584 : : return result->second;
585 : : };
586 : :
587 : : jl_register_jit_object(*NewInfo->Object, getLoadAddress, nullptr);
588 : :
589 : : cantFail(MR.withResourceKeyDo([&](ResourceKey K) {
590 : : RegisteredObjs[K].push_back(std::move(PendingObjs[&MR]));
591 : : PendingObjs.erase(&MR);
592 : : }));
593 : :
594 : : return Error::success();
595 : : }
596 : :
597 : : Error notifyFailed(MaterializationResponsibility &MR) override
598 : : {
599 : : PendingObjs.erase(&MR);
600 : : return Error::success();
601 : : }
602 : :
603 : : Error notifyRemovingResources(ResourceKey K) override
604 : : {
605 : : RegisteredObjs.erase(K);
606 : : // TODO: If we ever unload code, need to notify debuginfo registry.
607 : : return Error::success();
608 : : }
609 : :
610 : : void notifyTransferringResources(ResourceKey DstKey, ResourceKey SrcKey) override
611 : : {
612 : : auto SrcIt = RegisteredObjs.find(SrcKey);
613 : : if (SrcIt != RegisteredObjs.end()) {
614 : : for (std::unique_ptr<JITObjectInfo> &Info : SrcIt->second)
615 : : RegisteredObjs[DstKey].push_back(std::move(Info));
616 : : RegisteredObjs.erase(SrcIt);
617 : : }
618 : : }
619 : :
620 : : void modifyPassConfig(MaterializationResponsibility &MR, jitlink::LinkGraph &,
621 : : jitlink::PassConfiguration &PassConfig) override
622 : : {
623 : : auto It = PendingObjs.find(&MR);
624 : : if (It == PendingObjs.end())
625 : : return;
626 : :
627 : : JITObjectInfo &Info = *It->second;
628 : : PassConfig.PostAllocationPasses.push_back([&Info](jitlink::LinkGraph &G) -> Error {
629 : : for (const jitlink::Section &Sec : G.sections()) {
630 : : // Canonical JITLink section names have the segment name included, e.g.
631 : : // "__TEXT,__text" or "__DWARF,__debug_str". There are some special internal
632 : : // sections without a comma separator, which we can just ignore.
633 : : size_t SepPos = Sec.getName().find(',');
634 : : if (SepPos >= 16 || (Sec.getName().size() - (SepPos + 1) > 16)) {
635 : : LLVM_DEBUG({
636 : : dbgs() << "JLDebuginfoPlugin: Ignoring section '" << Sec.getName()
637 : : << "'\n";
638 : : });
639 : : continue;
640 : : }
641 : : auto SecName = Sec.getName().substr(SepPos + 1);
642 : : // https://github.com/llvm/llvm-project/commit/118e953b18ff07d00b8f822dfbf2991e41d6d791
643 : : #if JL_LLVM_VERSION >= 140000
644 : : Info.SectionLoadAddresses[SecName] = jitlink::SectionRange(Sec).getStart().getValue();
645 : : #else
646 : : Info.SectionLoadAddresses[SecName] = jitlink::SectionRange(Sec).getStart();
647 : : #endif
648 : : }
649 : : return Error::success();
650 : : });
651 : : }
652 : : };
653 : : }
654 : :
655 : : # ifdef LLVM_SHLIB
656 : :
657 : : # if JL_LLVM_VERSION >= 140000
658 : : # define EHFRAME_RANGE(name) orc::ExecutorAddrRange name
659 : : # define UNPACK_EHFRAME_RANGE(name) \
660 : : name.Start.toPtr<uint8_t *>(), \
661 : : static_cast<size_t>(name.size())
662 : : # else
663 : : # define EHFRAME_RANGE(name) JITTargetAddress name##Addr, size_t name##Size
664 : : # define UNPACK_EHFRAME_RANGE(name) \
665 : : jitTargetAddressToPointer<uint8_t *>(name##Addr), \
666 : : name##Size
667 : : # endif
668 : :
669 : : class JLEHFrameRegistrar final : public jitlink::EHFrameRegistrar {
670 : : public:
671 : : Error registerEHFrames(EHFRAME_RANGE(EHFrameSection)) override {
672 : : register_eh_frames(
673 : : UNPACK_EHFRAME_RANGE(EHFrameSection));
674 : : return Error::success();
675 : : }
676 : :
677 : : Error deregisterEHFrames(EHFRAME_RANGE(EHFrameSection)) override {
678 : : deregister_eh_frames(
679 : : UNPACK_EHFRAME_RANGE(EHFrameSection));
680 : : return Error::success();
681 : : }
682 : : };
683 : : # endif
684 : :
685 : : #else // !JL_USE_JITLINK
686 : :
687 : : RTDyldMemoryManager* createRTDyldMemoryManager(void);
688 : :
689 : : // A simple forwarding class, since OrcJIT v2 needs a unique_ptr, while we have a shared_ptr
690 : : class ForwardingMemoryManager : public RuntimeDyld::MemoryManager {
691 : : private:
692 : : std::shared_ptr<RuntimeDyld::MemoryManager> MemMgr;
693 : :
694 : : public:
695 : 334403 : ForwardingMemoryManager(std::shared_ptr<RuntimeDyld::MemoryManager> MemMgr) : MemMgr(MemMgr) {}
696 : 0 : virtual ~ForwardingMemoryManager() = default;
697 : 334380 : virtual uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
698 : : unsigned SectionID,
699 : : StringRef SectionName) override {
700 : 334380 : return MemMgr->allocateCodeSection(Size, Alignment, SectionID, SectionName);
701 : : }
702 : 454179 : virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
703 : : unsigned SectionID,
704 : : StringRef SectionName,
705 : : bool IsReadOnly) override {
706 : 454179 : return MemMgr->allocateDataSection(Size, Alignment, SectionID, SectionName, IsReadOnly);
707 : : }
708 : 0 : virtual void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign,
709 : : uintptr_t RODataSize,
710 : : uint32_t RODataAlign,
711 : : uintptr_t RWDataSize,
712 : : uint32_t RWDataAlign) override {
713 : 0 : return MemMgr->reserveAllocationSpace(CodeSize, CodeAlign, RODataSize, RODataAlign, RWDataSize, RWDataAlign);
714 : : }
715 : 334403 : virtual bool needsToReserveAllocationSpace() override {
716 : 334403 : return MemMgr->needsToReserveAllocationSpace();
717 : : }
718 : 334380 : virtual void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr,
719 : : size_t Size) override {
720 : 334380 : return MemMgr->registerEHFrames(Addr, LoadAddr, Size);
721 : : }
722 : 0 : virtual void deregisterEHFrames() override {
723 : 0 : return MemMgr->deregisterEHFrames();
724 : : }
725 : 334403 : virtual bool finalizeMemory(std::string *ErrMsg = nullptr) override {
726 : 334403 : return MemMgr->finalizeMemory(ErrMsg);
727 : : }
728 : 334403 : virtual void notifyObjectLoaded(RuntimeDyld &RTDyld,
729 : : const object::ObjectFile &Obj) override {
730 : 334403 : return MemMgr->notifyObjectLoaded(RTDyld, Obj);
731 : : }
732 : : };
733 : :
734 : :
735 : : #if defined(_OS_WINDOWS_) && defined(_CPU_X86_64_)
736 : : void *lookupWriteAddressFor(RTDyldMemoryManager *MemMgr, void *rt_addr);
737 : : #endif
738 : :
739 : 334403 : void registerRTDyldJITObject(const object::ObjectFile &Object,
740 : : const RuntimeDyld::LoadedObjectInfo &L,
741 : : const std::shared_ptr<RTDyldMemoryManager> &MemMgr)
742 : : {
743 : 668806 : auto SavedObject = L.getObjectForDebug(Object).takeBinary();
744 : : // If the debug object is unavailable, save (a copy of) the original object
745 : : // for our backtraces.
746 : : // This copy seems unfortunate, but there doesn't seem to be a way to take
747 : : // ownership of the original buffer.
748 [ - + ]: 334403 : if (!SavedObject.first) {
749 : : auto NewBuffer =
750 : 0 : MemoryBuffer::getMemBufferCopy(Object.getData(), Object.getFileName());
751 : : auto NewObj =
752 : 0 : cantFail(object::ObjectFile::createObjectFile(NewBuffer->getMemBufferRef()));
753 : 0 : SavedObject = std::make_pair(std::move(NewObj), std::move(NewBuffer));
754 : : }
755 : 334403 : const object::ObjectFile *DebugObj = SavedObject.first.release();
756 : 334403 : SavedObject.second.release();
757 : :
758 : 668806 : StringMap<object::SectionRef> loadedSections;
759 : : // Use the original Object, not the DebugObject, as this is used for the
760 : : // RuntimeDyld::LoadedObjectInfo lookup.
761 [ + + ]: 6912650 : for (const object::SectionRef &lSection : Object.sections()) {
762 : 13156500 : auto sName = lSection.getName();
763 [ + - ]: 6578250 : if (sName) {
764 : 6578250 : bool inserted = loadedSections.insert(std::make_pair(*sName, lSection)).second;
765 [ - + ]: 6578250 : assert(inserted);
766 : : (void)inserted;
767 : : }
768 : : }
769 : 334403 : auto getLoadAddress = [loadedSections = std::move(loadedSections),
770 : 660334 : &L](const StringRef &sName) -> uint64_t {
771 : 660334 : auto search = loadedSections.find(sName);
772 [ - + ]: 660334 : if (search == loadedSections.end())
773 : 0 : return 0;
774 : 660334 : return L.getSectionLoadAddress(search->second);
775 : 334403 : };
776 : :
777 : 334403 : jl_register_jit_object(*DebugObj, getLoadAddress,
778 : : #if defined(_OS_WINDOWS_) && defined(_CPU_X86_64_)
779 : : [MemMgr](void *p) { return lookupWriteAddressFor(MemMgr.get(), p); }
780 : : #else
781 : : nullptr
782 : : #endif
783 : : );
784 : 334403 : }
785 : : #endif
786 : : namespace {
787 : 567 : std::unique_ptr<TargetMachine> createTargetMachine() {
788 : :
789 : 1134 : TargetOptions options = TargetOptions();
790 : : #if defined(_OS_WINDOWS_)
791 : : // use ELF because RuntimeDyld COFF i686 support didn't exist
792 : : // use ELF because RuntimeDyld COFF X86_64 doesn't seem to work (fails to generate function pointers)?
793 : : #define FORCE_ELF
794 : : #endif
795 : : //options.PrintMachineCode = true; //Print machine code produced during JIT compiling
796 : : #if defined(_OS_WINDOWS_) && !defined(_CPU_X86_64_) && JL_LLVM_VERSION < 130000
797 : : // tell Win32 to assume the stack is always 16-byte aligned,
798 : : // and to ensure that it is 16-byte aligned for out-going calls,
799 : : // to ensure compatibility with GCC codes
800 : : // In LLVM 13 and onwards this has turned into a module option
801 : : options.StackAlignmentOverride = 16;
802 : : #endif
803 : : #if defined(JL_DEBUG_BUILD) && JL_LLVM_VERSION < 130000
804 : : // LLVM defaults to tls stack guard, which causes issues with Julia's tls implementation
805 : : options.StackProtectorGuard = StackProtectorGuards::Global;
806 : : #endif
807 : 1134 : Triple TheTriple(sys::getProcessTriple());
808 : : #if defined(FORCE_ELF)
809 : : TheTriple.setObjectFormat(Triple::ELF);
810 : : #endif
811 : 567 : uint32_t target_flags = 0;
812 : 1134 : auto target = jl_get_llvm_target(imaging_default(), target_flags);
813 : 567 : auto &TheCPU = target.first;
814 : 1134 : SmallVector<std::string, 10> targetFeatures(target.second.begin(), target.second.end());
815 : 1134 : std::string errorstr;
816 : 567 : const Target *TheTarget = TargetRegistry::lookupTarget("", TheTriple, errorstr);
817 [ - + ]: 567 : if (!TheTarget) {
818 : : // Note we are explicitly not using `jl_errorf()` here, as it will attempt to
819 : : // collect a backtrace, but we're too early in LLVM initialization for that.
820 : 0 : jl_printf(JL_STDERR, "ERROR: %s", errorstr.c_str());
821 : 0 : exit(1);
822 : : }
823 [ + - - + ]: 567 : if (jl_processor_print_help || (target_flags & JL_TARGET_UNKNOWN_NAME)) {
824 : : std::unique_ptr<MCSubtargetInfo> MSTI(
825 : 0 : TheTarget->createMCSubtargetInfo(TheTriple.str(), "", ""));
826 [ # # ]: 0 : if (!MSTI->isCPUStringValid(TheCPU)) {
827 : : // Same as above, we are too early to use `jl_errorf()` here.
828 : 0 : jl_printf(JL_STDERR, "ERROR: Invalid CPU name \"%s\".", TheCPU.c_str());
829 : 0 : exit(1);
830 : : }
831 [ # # ]: 0 : if (jl_processor_print_help) {
832 : : // This is the only way I can find to print the help message once.
833 : : // It'll be nice if we can iterate through the features and print our own help
834 : : // message...
835 : 0 : MSTI->setDefaultFeatures("help", "", "");
836 : : }
837 : : }
838 : : // Package up features to be passed to target/subtarget
839 : 1134 : std::string FeaturesStr;
840 [ + - ]: 567 : if (!targetFeatures.empty()) {
841 : 567 : SubtargetFeatures Features;
842 [ + + ]: 44793 : for (unsigned i = 0; i != targetFeatures.size(); ++i)
843 : 44226 : Features.AddFeature(targetFeatures[i]);
844 : 567 : FeaturesStr = Features.getString();
845 : : }
846 : : // Allocate a target...
847 : 567 : Optional<CodeModel::Model> codemodel =
848 : : #ifdef _P64
849 : : // Make sure we are using the large code model on 64bit
850 : : // Let LLVM pick a default suitable for jitting on 32bit
851 : : CodeModel::Large;
852 : : #else
853 : : None;
854 : : #endif
855 : 567 : auto optlevel = CodeGenOptLevelFor(jl_options.opt_level);
856 : 567 : auto TM = TheTarget->createTargetMachine(
857 : : TheTriple.getTriple(), TheCPU, FeaturesStr,
858 : : options,
859 : 567 : Reloc::Static, // Generate simpler code for JIT
860 : : codemodel,
861 : : optlevel,
862 : : true // JIT
863 : : );
864 [ - + ]: 567 : assert(TM && "Failed to select target machine -"
865 : : " Is the LLVM backend for this CPU enabled?");
866 : : #if (!defined(_CPU_ARM_) && !defined(_CPU_PPC64_))
867 : : // FastISel seems to be buggy for ARM. Ref #13321
868 [ + + ]: 567 : if (jl_options.opt_level < 2)
869 : 92 : TM->setFastISel(true);
870 : : #endif
871 : 567 : return std::unique_ptr<TargetMachine>(TM);
872 : : }
873 : : } // namespace
874 : :
875 : : namespace {
876 : :
877 : : typedef legacy::PassManager PassManager;
878 : :
879 : 4536 : orc::JITTargetMachineBuilder createJTMBFromTM(TargetMachine &TM, int optlevel) {
880 : 9072 : return orc::JITTargetMachineBuilder(TM.getTargetTriple())
881 : 9072 : .setCPU(TM.getTargetCPU().str())
882 : 4536 : .setFeatures(TM.getTargetFeatureString())
883 : 9072 : .setOptions(TM.Options)
884 : 4536 : .setRelocationModel(Reloc::Static)
885 : 9072 : .setCodeModel(TM.getCodeModel())
886 : 4536 : .setCodeGenOptLevel(CodeGenOptLevelFor(optlevel));
887 : : }
888 : :
889 : : struct TMCreator {
890 : : orc::JITTargetMachineBuilder JTMB;
891 : :
892 : 2268 : TMCreator(TargetMachine &TM, int optlevel) : JTMB(createJTMBFromTM(TM, optlevel)) {}
893 : :
894 : 952 : std::unique_ptr<TargetMachine> operator()() {
895 : 952 : return cantFail(JTMB.createTargetMachine());
896 : : }
897 : : };
898 : :
899 : : struct PMCreator {
900 : : std::unique_ptr<TargetMachine> TM;
901 : : int optlevel;
902 : 2268 : PMCreator(TargetMachine &TM, int optlevel) : TM(cantFail(createJTMBFromTM(TM, optlevel).createTargetMachine())), optlevel(optlevel) {}
903 : 0 : PMCreator(const PMCreator &other) : PMCreator(*other.TM, other.optlevel) {}
904 : 2268 : PMCreator(PMCreator &&other) : TM(std::move(other.TM)), optlevel(other.optlevel) {}
905 : : friend void swap(PMCreator &self, PMCreator &other) {
906 : : using std::swap;
907 : : swap(self.TM, other.TM);
908 : : swap(self.optlevel, other.optlevel);
909 : : }
910 : : PMCreator &operator=(PMCreator other) {
911 : : swap(*this, other);
912 : : return *this;
913 : : }
914 : 952 : std::unique_ptr<PassManager> operator()() {
915 : 952 : auto PM = std::make_unique<legacy::PassManager>();
916 : 952 : addTargetPasses(PM.get(), TM->getTargetTriple(), TM->getTargetIRAnalysis());
917 : 952 : addOptimizationPasses(PM.get(), optlevel);
918 : 952 : addMachinePasses(PM.get(), optlevel);
919 : 952 : return PM;
920 : : }
921 : : };
922 : :
923 : : struct OptimizerT {
924 : 2268 : OptimizerT(TargetMachine &TM, int optlevel) : optlevel(optlevel), PMs(PMCreator(TM, optlevel)) {}
925 : :
926 : 334404 : OptimizerResultT operator()(orc::ThreadSafeModule TSM, orc::MaterializationResponsibility &R) {
927 : 334404 : TSM.withModuleDo([&](Module &M) {
928 : 334404 : uint64_t start_time = 0;
929 : : {
930 : 668808 : auto stream = *jl_ExecutionEngine->get_dump_llvm_opt_stream();
931 [ + + ]: 334404 : if (stream) {
932 : : // Print LLVM function statistics _before_ optimization
933 : : // Print all the information about this invocation as a YAML object
934 : 1 : jl_printf(stream, "- \n");
935 : : // We print the name and some statistics for each function in the module, both
936 : : // before optimization and again afterwards.
937 : 1 : jl_printf(stream, " before: \n");
938 [ + + ]: 5 : for (auto &F : M.functions()) {
939 [ + + + + : 4 : if (F.isDeclaration() || F.getName().startswith("jfptr_")) {
+ + ]
940 : 3 : continue;
941 : : }
942 : : // Each function is printed as a YAML object with several attributes
943 : 1 : jl_printf(stream, " \"%s\":\n", F.getName().str().c_str());
944 : 1 : jl_printf(stream, " instructions: %u\n", F.getInstructionCount());
945 : 1 : jl_printf(stream, " basicblocks: %zd\n", countBasicBlocks(F));
946 : : }
947 : :
948 : 1 : start_time = jl_hrtime();
949 : : }
950 : : }
951 : :
952 : : JL_TIMING(LLVM_OPT);
953 : :
954 : : //Run the optimization
955 : 334404 : (***PMs).run(M);
956 : :
957 : 334404 : uint64_t end_time = 0;
958 : : {
959 : 668808 : auto stream = *jl_ExecutionEngine->get_dump_llvm_opt_stream();
960 [ + + ]: 334404 : if (stream) {
961 : 1 : end_time = jl_hrtime();
962 : 1 : jl_printf(stream, " time_ns: %" PRIu64 "\n", end_time - start_time);
963 : 1 : jl_printf(stream, " optlevel: %d\n", optlevel);
964 : :
965 : : // Print LLVM function statistics _after_ optimization
966 : 1 : jl_printf(stream, " after: \n");
967 [ + + ]: 9 : for (auto &F : M.functions()) {
968 [ + + + + : 8 : if (F.isDeclaration() || F.getName().startswith("jfptr_")) {
+ + ]
969 : 7 : continue;
970 : : }
971 : 1 : jl_printf(stream, " \"%s\":\n", F.getName().str().c_str());
972 : 1 : jl_printf(stream, " instructions: %u\n", F.getInstructionCount());
973 : 1 : jl_printf(stream, " basicblocks: %zd\n", countBasicBlocks(F));
974 : : }
975 : : }
976 : : }
977 : 334404 : });
978 : 334404 : return Expected<orc::ThreadSafeModule>{std::move(TSM)};
979 : : }
980 : : private:
981 : : int optlevel;
982 : : JuliaOJIT::ResourcePool<std::unique_ptr<PassManager>> PMs;
983 : : };
984 : :
985 : : struct CompilerT : orc::IRCompileLayer::IRCompiler {
986 : :
987 : 2268 : CompilerT(orc::IRSymbolMapper::ManglingOptions MO, TargetMachine &TM, int optlevel)
988 : 2268 : : orc::IRCompileLayer::IRCompiler(MO), TMs(TMCreator(TM, optlevel)) {}
989 : :
990 : 334404 : Expected<std::unique_ptr<MemoryBuffer>> operator()(Module &M) override {
991 : 334404 : return orc::SimpleCompiler(***TMs)(M);
992 : : }
993 : :
994 : : JuliaOJIT::ResourcePool<std::unique_ptr<TargetMachine>> TMs;
995 : : };
996 : : }
997 : :
998 : 568 : llvm::DataLayout jl_create_datalayout(TargetMachine &TM) {
999 : : // Mark our address spaces as non-integral
1000 : 568 : auto jl_data_layout = TM.createDataLayout();
1001 : 568 : jl_data_layout.reset(jl_data_layout.getStringRepresentation() + "-ni:10:11:12:13");
1002 : 568 : return jl_data_layout;
1003 : : }
1004 : :
1005 : 2268 : JuliaOJIT::PipelineT::PipelineT(orc::ObjectLayer &BaseLayer, TargetMachine &TM, int optlevel)
1006 : : : CompileLayer(BaseLayer.getExecutionSession(), BaseLayer,
1007 : 2268 : std::make_unique<CompilerT>(orc::irManglingOptionsFromTargetOptions(TM.Options), TM, optlevel)),
1008 : 4536 : OptimizeLayer(CompileLayer.getExecutionSession(), CompileLayer, OptimizerT(TM, optlevel)) {}
1009 : :
1010 : 567 : JuliaOJIT::JuliaOJIT()
1011 : : : TM(createTargetMachine()),
1012 : 567 : DL(jl_create_datalayout(*TM)),
1013 : : #if JL_LLVM_VERSION >= 130000
1014 : 1134 : ES(cantFail(orc::SelfExecutorProcessControl::Create())),
1015 : : #else
1016 : : ES(),
1017 : : #endif
1018 : 1134 : GlobalJD(ES.createBareJITDylib("JuliaGlobals")),
1019 : 1134 : JD(ES.createBareJITDylib("JuliaOJIT")),
1020 : 812 : ContextPool([](){
1021 : 812 : auto ctx = std::make_unique<LLVMContext>();
1022 : : #ifdef JL_LLVM_OPAQUE_POINTERS
1023 : : ctx->enableOpaquePointers();
1024 : : #endif
1025 : 812 : return orc::ThreadSafeContext(std::move(ctx));
1026 : : }),
1027 : : #ifdef JL_USE_JITLINK
1028 : : // TODO: Port our memory management optimisations to JITLink instead of using the
1029 : : // default InProcessMemoryManager.
1030 : : # if JL_LLVM_VERSION < 140000
1031 : : ObjectLayer(ES, std::make_unique<jitlink::InProcessMemoryManager>()),
1032 : : # else
1033 : : ObjectLayer(ES, cantFail(jitlink::InProcessMemoryManager::Create())),
1034 : : # endif
1035 : : #else
1036 : : MemMgr(createRTDyldMemoryManager()),
1037 : : ObjectLayer(
1038 : 567 : ES,
1039 : 334403 : [this]() {
1040 : 334403 : std::unique_ptr<RuntimeDyld::MemoryManager> result(new ForwardingMemoryManager(MemMgr));
1041 : 334403 : return result;
1042 : : }
1043 : : ),
1044 : : #endif
1045 : : Pipelines{
1046 : 1701 : std::make_unique<PipelineT>(ObjectLayer, *TM, 0),
1047 : 567 : std::make_unique<PipelineT>(ObjectLayer, *TM, 1),
1048 : 567 : std::make_unique<PipelineT>(ObjectLayer, *TM, 2),
1049 : 567 : std::make_unique<PipelineT>(ObjectLayer, *TM, 3),
1050 : : },
1051 : 5103 : OptSelLayer(Pipelines)
1052 : : {
1053 : : #ifdef JL_USE_JITLINK
1054 : : # if defined(_OS_DARWIN_) && defined(LLVM_SHLIB)
1055 : : // When dynamically linking against LLVM, use our custom EH frame registration code
1056 : : // also used with RTDyld to inform both our and the libc copy of libunwind.
1057 : : auto ehRegistrar = std::make_unique<JLEHFrameRegistrar>();
1058 : : # else
1059 : : auto ehRegistrar = std::make_unique<jitlink::InProcessEHFrameRegistrar>();
1060 : : # endif
1061 : : ObjectLayer.addPlugin(std::make_unique<EHFrameRegistrationPlugin>(
1062 : : ES, std::move(ehRegistrar)));
1063 : :
1064 : : ObjectLayer.addPlugin(std::make_unique<JLDebuginfoPlugin>());
1065 : : #else
1066 : : ObjectLayer.setNotifyLoaded(
1067 : 334403 : [this](orc::MaterializationResponsibility &MR,
1068 : : const object::ObjectFile &Object,
1069 : 334403 : const RuntimeDyld::LoadedObjectInfo &LO) {
1070 : 334403 : registerRTDyldJITObject(Object, LO, MemMgr);
1071 : 567 : });
1072 : : #endif
1073 : :
1074 : : // Make sure SectionMemoryManager::getSymbolAddressInProcess can resolve
1075 : : // symbols in the program as well. The nullptr argument to the function
1076 : : // tells DynamicLibrary to load the program, not a library.
1077 : 1134 : std::string ErrorStr;
1078 [ - + ]: 567 : if (sys::DynamicLibrary::LoadLibraryPermanently(nullptr, &ErrorStr))
1079 : 0 : report_fatal_error(llvm::Twine("FATAL: unable to dlopen self\n") + ErrorStr);
1080 : :
1081 : 567 : GlobalJD.addGenerator(
1082 : 1701 : cantFail(orc::DynamicLibrarySearchGenerator::GetForCurrentProcess(
1083 : 1134 : DL.getGlobalPrefix())));
1084 : :
1085 : : // Resolve non-lock free atomic functions in the libatomic1 library.
1086 : : // This is the library that provides support for c11/c++11 atomic operations.
1087 : 567 : const char *const libatomic =
1088 : : #if defined(_OS_LINUX_) || defined(_OS_FREEBSD_)
1089 : : "libatomic.so.1";
1090 : : #elif defined(_OS_WINDOWS_)
1091 : : "libatomic-1.dll";
1092 : : #else
1093 : : NULL;
1094 : : #endif
1095 : : if (libatomic) {
1096 [ + - + - ]: 567 : static void *atomic_hdl = jl_load_dynamic_library(libatomic, JL_RTLD_LOCAL, 0);
1097 [ + - ]: 567 : if (atomic_hdl != NULL) {
1098 : 567 : GlobalJD.addGenerator(
1099 : 1701 : cantFail(orc::DynamicLibrarySearchGenerator::Load(
1100 : : libatomic,
1101 : 567 : DL.getGlobalPrefix(),
1102 : 809546 : [&](const orc::SymbolStringPtr &S) {
1103 : 809546 : const char *const atomic_prefix = "__atomic_";
1104 : 809546 : return (*S).startswith(atomic_prefix);
1105 : 567 : })));
1106 : : }
1107 : : }
1108 : :
1109 : 567 : JD.addToLinkOrder(GlobalJD, orc::JITDylibLookupFlags::MatchExportedSymbolsOnly);
1110 : 567 : }
1111 : :
1112 : 130346 : void JuliaOJIT::addGlobalMapping(StringRef Name, uint64_t Addr)
1113 : : {
1114 : 130346 : std::string MangleName = getMangledName(Name);
1115 [ + + ]: 260692 : cantFail(JD.define(orc::absoluteSymbols({{ES.intern(MangleName), JITEvaluatedSymbol::fromPointer((void*)Addr)}})));
1116 : 130346 : }
1117 : :
1118 : 334404 : void JuliaOJIT::addModule(orc::ThreadSafeModule TSM)
1119 : : {
1120 : : JL_TIMING(LLVM_MODULE_FINISH);
1121 : 668807 : std::vector<std::string> NewExports;
1122 : 334404 : TSM.withModuleDo([&](Module &M) {
1123 : 334404 : jl_decorate_module(M);
1124 : 334404 : shareStrings(M);
1125 [ + + ]: 4315620 : for (auto &F : M.global_values()) {
1126 [ + + + + : 3981220 : if (!F.isDeclaration() && F.getLinkage() == GlobalValue::ExternalLinkage) {
+ + ]
1127 : 665980 : NewExports.push_back(getMangledName(F.getName()));
1128 : : }
1129 : : }
1130 : : #if !defined(JL_NDEBUG) && !defined(JL_USE_JITLINK)
1131 : : // validate the relocations for M (not implemented for the JITLink memory manager yet)
1132 [ + + ]: 4315620 : for (Module::global_object_iterator I = M.global_objects().begin(), E = M.global_objects().end(); I != E; ) {
1133 : 3981210 : GlobalObject *F = &*I;
1134 : 3981210 : ++I;
1135 [ + + ]: 3981210 : if (F->isDeclaration()) {
1136 [ + + ]: 3012550 : if (F->use_empty())
1137 : 4586 : F->eraseFromParent();
1138 [ + + + + : 4401960 : else if (!((isa<Function>(F) && isIntrinsicFunction(cast<Function>(F))) ||
- - ]
1139 [ - + - + ]: 4401960 : findUnmangledSymbol(F->getName()) ||
1140 : 0 : SectionMemoryManager::getSymbolAddressInProcess(
1141 [ - + + + ]: 3007960 : getMangledName(F->getName())))) {
1142 : 0 : llvm::errs() << "FATAL ERROR: "
1143 : 0 : << "Symbol \"" << F->getName().str() << "\""
1144 : 0 : << "not found";
1145 : 0 : abort();
1146 : : }
1147 : : }
1148 : : }
1149 : : #endif
1150 : 334404 : });
1151 : : // TODO: what is the performance characteristics of this?
1152 : 334404 : cantFail(OptSelLayer.add(JD, std::move(TSM)));
1153 : : // force eager compilation (for now), due to memory management specifics
1154 : : // (can't handle compilation recursion)
1155 [ + + ]: 1000380 : for (auto Name : NewExports)
1156 : 665979 : cantFail(ES.lookup({&JD}, Name));
1157 : :
1158 : 334403 : }
1159 : :
1160 : 2049200 : JL_JITSymbol JuliaOJIT::findSymbol(StringRef Name, bool ExportedSymbolsOnly)
1161 : : {
1162 : 2049200 : orc::JITDylib* SearchOrders[2] = {&GlobalJD, &JD};
1163 [ + + + + ]: 2049200 : ArrayRef<orc::JITDylib*> SearchOrder = makeArrayRef(&SearchOrders[ExportedSymbolsOnly ? 0 : 1], ExportedSymbolsOnly ? 2 : 1);
1164 : 4098390 : auto Sym = ES.lookup(SearchOrder, Name);
1165 [ + + ]: 2049200 : if (Sym)
1166 : 2049190 : return *Sym;
1167 : 4 : return Sym.takeError();
1168 : : }
1169 : :
1170 : 1394000 : JL_JITSymbol JuliaOJIT::findUnmangledSymbol(StringRef Name)
1171 : : {
1172 : 1394000 : return findSymbol(getMangledName(Name), true);
1173 : : }
1174 : :
1175 : 6 : uint64_t JuliaOJIT::getGlobalValueAddress(StringRef Name)
1176 : : {
1177 : 12 : auto addr = findSymbol(getMangledName(Name), false);
1178 [ + + ]: 6 : if (!addr) {
1179 : 4 : consumeError(addr.takeError());
1180 : 4 : return 0;
1181 : : }
1182 : 2 : return cantFail(addr.getAddress());
1183 : : }
1184 : :
1185 : 655189 : uint64_t JuliaOJIT::getFunctionAddress(StringRef Name)
1186 : : {
1187 : 1310380 : auto addr = findSymbol(getMangledName(Name), false);
1188 [ - + ]: 655189 : if (!addr) {
1189 : 0 : consumeError(addr.takeError());
1190 : 0 : return 0;
1191 : : }
1192 : 655189 : return cantFail(addr.getAddress());
1193 : : }
1194 : :
1195 : 1286480 : StringRef JuliaOJIT::getFunctionAtAddress(uint64_t Addr, jl_code_instance_t *codeinst)
1196 : : {
1197 : 1286480 : std::lock_guard<std::mutex> lock(RLST_mutex);
1198 : 1286480 : std::string *fname = &ReverseLocalSymbolTable[(void*)(uintptr_t)Addr];
1199 [ + + ]: 1286480 : if (fname->empty()) {
1200 : 141622 : std::string string_fname;
1201 : 70811 : raw_string_ostream stream_fname(string_fname);
1202 : : // try to pick an appropriate name that describes it
1203 : 70811 : jl_callptr_t invoke = jl_atomic_load_relaxed(&codeinst->invoke);
1204 [ - + ]: 70811 : if (Addr == (uintptr_t)invoke) {
1205 : 0 : stream_fname << "jsysw_";
1206 : : }
1207 [ + + ]: 70811 : else if (invoke == jl_fptr_args_addr) {
1208 : 3995 : stream_fname << "jsys1_";
1209 : : }
1210 [ - + ]: 66816 : else if (invoke == jl_fptr_sparam_addr) {
1211 : 0 : stream_fname << "jsys3_";
1212 : : }
1213 : : else {
1214 : 66816 : stream_fname << "jlsys_";
1215 : : }
1216 : 70811 : const char* unadorned_name = jl_symbol_name(codeinst->def->def.method->name);
1217 : 70811 : stream_fname << unadorned_name << "_" << RLST_inc++;
1218 : 70811 : *fname = std::move(stream_fname.str()); // store to ReverseLocalSymbolTable
1219 : 70811 : addGlobalMapping(*fname, Addr);
1220 : : }
1221 : 1286480 : return *fname;
1222 : : }
1223 : :
1224 : :
1225 : : #ifdef JL_USE_JITLINK
1226 : : # if JL_LLVM_VERSION < 140000
1227 : : # pragma message("JIT debugging (GDB integration) not available on LLVM < 14.0 (for JITLink)")
1228 : : void JuliaOJIT::enableJITDebuggingSupport() {}
1229 : : # else
1230 : : extern "C" orc::shared::CWrapperFunctionResult
1231 : : llvm_orc_registerJITLoaderGDBAllocAction(const char *Data, size_t Size);
1232 : :
1233 : : void JuliaOJIT::enableJITDebuggingSupport()
1234 : : {
1235 : : // We do not use GDBJITDebugInfoRegistrationPlugin::Create, as the runtime name
1236 : : // lookup is unnecessarily involved/fragile for our in-process JIT use case
1237 : : // (with the llvm_orc_registerJITLoaderGDBAllocAction symbol being in either
1238 : : // libjulia-codegen or yet another shared library for LLVM depending on the build
1239 : : // flags, etc.).
1240 : : const auto Addr = ExecutorAddr::fromPtr(&llvm_orc_registerJITLoaderGDBAllocAction);
1241 : : ObjectLayer.addPlugin(std::make_unique<orc::GDBJITDebugInfoRegistrationPlugin>(Addr));
1242 : : }
1243 : : # endif
1244 : : #else
1245 : 567 : void JuliaOJIT::enableJITDebuggingSupport()
1246 : : {
1247 : 567 : RegisterJITEventListener(JITEventListener::createGDBRegistrationListener());
1248 : 567 : }
1249 : :
1250 : 567 : void JuliaOJIT::RegisterJITEventListener(JITEventListener *L)
1251 : : {
1252 [ - + ]: 567 : if (!L)
1253 : 0 : return;
1254 : 567 : this->ObjectLayer.registerJITEventListener(*L);
1255 : : }
1256 : : #endif
1257 : :
1258 : 376745 : const DataLayout& JuliaOJIT::getDataLayout() const
1259 : : {
1260 : 376745 : return DL;
1261 : : }
1262 : :
1263 : 2845520 : std::string JuliaOJIT::getMangledName(StringRef Name)
1264 : : {
1265 : 2845520 : SmallString<128> FullName;
1266 : 2845520 : Mangler::getNameWithPrefix(FullName, Name, DL);
1267 : 2845520 : return FullName.str().str();
1268 : : }
1269 : :
1270 : 0 : std::string JuliaOJIT::getMangledName(const GlobalValue *GV)
1271 : : {
1272 : 0 : return getMangledName(GV->getName());
1273 : : }
1274 : :
1275 : : #ifdef JL_USE_JITLINK
1276 : : size_t JuliaOJIT::getTotalBytes() const
1277 : : {
1278 : : // TODO: Implement in future custom JITLink memory manager.
1279 : : return 0;
1280 : : }
1281 : : #else
1282 : : size_t getRTDyldMemoryManagerTotalBytes(RTDyldMemoryManager *mm);
1283 : :
1284 : 1 : size_t JuliaOJIT::getTotalBytes() const
1285 : : {
1286 : 1 : return getRTDyldMemoryManagerTotalBytes(MemMgr.get());
1287 : : }
1288 : : #endif
1289 : :
1290 : : JuliaOJIT *jl_ExecutionEngine;
1291 : :
1292 : : // destructively move the contents of src into dest
1293 : : // this assumes that the targets of the two modules are the same
1294 : : // including the DataLayout and ModuleFlags (for example)
1295 : : // and that there is no module-level assembly
1296 : : // Comdat is also removed, since the JIT doesn't need it
1297 : 33720 : void jl_merge_module(orc::ThreadSafeModule &destTSM, orc::ThreadSafeModule srcTSM)
1298 : : {
1299 : 33720 : destTSM.withModuleDo([&](Module &dest) {
1300 : 33720 : srcTSM.withModuleDo([&](Module &src) {
1301 [ - + ]: 33720 : assert(&dest != &src && "Cannot merge module with itself!");
1302 [ + - ]: 33720 : assert(&dest.getContext() == &src.getContext() && "Cannot merge modules with different contexts!");
1303 [ + - ]: 33720 : assert(dest.getDataLayout() == src.getDataLayout() && "Cannot merge modules with different data layouts!");
1304 [ + - ]: 33720 : assert(dest.getTargetTriple() == src.getTargetTriple() && "Cannot merge modules with different target triples!");
1305 : :
1306 [ + + ]: 425418 : for (Module::global_iterator I = src.global_begin(), E = src.global_end(); I != E;) {
1307 : 391698 : GlobalVariable *sG = &*I;
1308 : 391698 : GlobalVariable *dG = cast_or_null<GlobalVariable>(dest.getNamedValue(sG->getName()));
1309 : 391698 : ++I;
1310 : : // Replace a declaration with the definition:
1311 [ + + ]: 391698 : if (dG) {
1312 [ + + ]: 357081 : if (sG->isDeclaration()) {
1313 : 340807 : sG->replaceAllUsesWith(dG);
1314 : 340807 : sG->eraseFromParent();
1315 : 340807 : continue;
1316 : : }
1317 : : //// If we start using llvm.used, we need to enable and test this
1318 : : //else if (!dG->isDeclaration() && dG->hasAppendingLinkage() && sG->hasAppendingLinkage()) {
1319 : : // auto *dCA = cast<ConstantArray>(dG->getInitializer());
1320 : : // auto *sCA = cast<ConstantArray>(sG->getInitializer());
1321 : : // SmallVector<Constant *, 16> Init;
1322 : : // for (auto &Op : dCA->operands())
1323 : : // Init.push_back(cast_or_null<Constant>(Op));
1324 : : // for (auto &Op : sCA->operands())
1325 : : // Init.push_back(cast_or_null<Constant>(Op));
1326 : : // Type *Int8PtrTy = Type::getInt8PtrTy(dest.getContext());
1327 : : // ArrayType *ATy = ArrayType::get(Int8PtrTy, Init.size());
1328 : : // GlobalVariable *GV = new GlobalVariable(dest, ATy, dG->isConstant(),
1329 : : // GlobalValue::AppendingLinkage, ConstantArray::get(ATy, Init), "",
1330 : : // dG->getThreadLocalMode(), dG->getType()->getAddressSpace());
1331 : : // GV->copyAttributesFrom(dG);
1332 : : // sG->replaceAllUsesWith(GV);
1333 : : // dG->replaceAllUsesWith(GV);
1334 : : // GV->takeName(sG);
1335 : : // sG->eraseFromParent();
1336 : : // dG->eraseFromParent();
1337 : : // continue;
1338 : : //}
1339 : : else {
1340 [ + + - + ]: 16274 : assert(dG->isDeclaration() || dG->getInitializer() == sG->getInitializer());
1341 : 16274 : dG->replaceAllUsesWith(sG);
1342 : 16274 : dG->eraseFromParent();
1343 : : }
1344 : : }
1345 : : // Reparent the global variable:
1346 : 50891 : sG->removeFromParent();
1347 : 50891 : dest.getGlobalList().push_back(sG);
1348 : : // Comdat is owned by the Module
1349 : 50891 : sG->setComdat(nullptr);
1350 : : }
1351 : :
1352 [ + + ]: 331716 : for (Module::iterator I = src.begin(), E = src.end(); I != E;) {
1353 : 297996 : Function *sG = &*I;
1354 : 297996 : Function *dG = cast_or_null<Function>(dest.getNamedValue(sG->getName()));
1355 : 297996 : ++I;
1356 : : // Replace a declaration with the definition:
1357 [ + + ]: 297996 : if (dG) {
1358 [ + + ]: 223459 : if (sG->isDeclaration()) {
1359 : 215234 : sG->replaceAllUsesWith(dG);
1360 : 215234 : sG->eraseFromParent();
1361 : 215234 : continue;
1362 : : }
1363 : : else {
1364 [ - + ]: 8225 : assert(dG->isDeclaration());
1365 : 8225 : dG->replaceAllUsesWith(sG);
1366 : 8225 : dG->eraseFromParent();
1367 : : }
1368 : : }
1369 : : // Reparent the global variable:
1370 : 82762 : sG->removeFromParent();
1371 : 82762 : dest.getFunctionList().push_back(sG);
1372 : : // Comdat is owned by the Module
1373 : 82762 : sG->setComdat(nullptr);
1374 : : }
1375 : :
1376 [ - + ]: 33720 : for (Module::alias_iterator I = src.alias_begin(), E = src.alias_end(); I != E;) {
1377 : 0 : GlobalAlias *sG = &*I;
1378 : 0 : GlobalAlias *dG = cast_or_null<GlobalAlias>(dest.getNamedValue(sG->getName()));
1379 : 0 : ++I;
1380 [ # # ]: 0 : if (dG) {
1381 [ # # ]: 0 : if (!dG->isDeclaration()) { // aliases are always definitions, so this test is reversed from the above two
1382 : 0 : sG->replaceAllUsesWith(dG);
1383 : 0 : sG->eraseFromParent();
1384 : 0 : continue;
1385 : : }
1386 : : else {
1387 : 0 : dG->replaceAllUsesWith(sG);
1388 : 0 : dG->eraseFromParent();
1389 : : }
1390 : : }
1391 : 0 : sG->removeFromParent();
1392 : 0 : dest.getAliasList().push_back(sG);
1393 : : }
1394 : :
1395 : : // metadata nodes need to be explicitly merged not just copied
1396 : : // so there are special passes here for each known type of metadata
1397 : 33720 : NamedMDNode *sNMD = src.getNamedMetadata("llvm.dbg.cu");
1398 [ + + ]: 33720 : if (sNMD) {
1399 : 27874 : NamedMDNode *dNMD = dest.getOrInsertNamedMetadata("llvm.dbg.cu");
1400 [ + + ]: 55748 : for (NamedMDNode::op_iterator I = sNMD->op_begin(), E = sNMD->op_end(); I != E; ++I) {
1401 : 27874 : dNMD->addOperand(*I);
1402 : : }
1403 : : }
1404 : 33720 : });
1405 : 33720 : });
1406 : 33720 : }
1407 : :
1408 : : // optimize memory by turning long strings into memoized copies, instead of
1409 : : // making a copy per object file of output.
1410 : 334404 : void JuliaOJIT::shareStrings(Module &M)
1411 : : {
1412 : 668808 : std::vector<GlobalVariable*> erase;
1413 [ + + ]: 665489 : for (auto &GV : M.globals()) {
1414 [ + + + + : 331085 : if (!GV.hasInitializer() || !GV.isConstant())
+ + ]
1415 : 280564 : continue;
1416 : 305413 : ConstantDataSequential *CDS = dyn_cast<ConstantDataSequential>(GV.getInitializer());
1417 [ + + ]: 305413 : if (CDS == nullptr)
1418 : 254892 : continue;
1419 : 50521 : StringRef data = CDS->getRawDataValues();
1420 [ + + ]: 50521 : if (data.size() > 16) { // only for long strings: keep short ones as values
1421 : 7688 : Type *T_size = Type::getIntNTy(GV.getContext(), sizeof(void*) * 8);
1422 : 7688 : Constant *v = ConstantExpr::getIntToPtr(
1423 : 15376 : ConstantInt::get(T_size, (uintptr_t)(*ES.intern(data)).data()),
1424 : 7688 : GV.getType());
1425 : 7688 : GV.replaceAllUsesWith(v);
1426 : 7688 : erase.push_back(&GV);
1427 : : }
1428 : : }
1429 [ + + ]: 342092 : for (auto GV : erase)
1430 : 7688 : GV->eraseFromParent();
1431 : 334404 : }
1432 : :
1433 : : //TargetMachine pass-through methods
1434 : :
1435 : 24 : std::unique_ptr<TargetMachine> JuliaOJIT::cloneTargetMachine() const
1436 : : {
1437 : 24 : return std::unique_ptr<TargetMachine>(getTarget()
1438 : : .createTargetMachine(
1439 : 24 : getTargetTriple().str(),
1440 : : getTargetCPU(),
1441 : : getTargetFeatureString(),
1442 : : getTargetOptions(),
1443 : 24 : TM->getRelocationModel(),
1444 : 24 : TM->getCodeModel(),
1445 : 96 : TM->getOptLevel()));
1446 : : }
1447 : :
1448 : 376893 : const Triple& JuliaOJIT::getTargetTriple() const {
1449 : 376893 : return TM->getTargetTriple();
1450 : : }
1451 : 476 : StringRef JuliaOJIT::getTargetFeatureString() const {
1452 : 476 : return TM->getTargetFeatureString();
1453 : : }
1454 : 25 : StringRef JuliaOJIT::getTargetCPU() const {
1455 : 25 : return TM->getTargetCPU();
1456 : : }
1457 : 25 : const TargetOptions &JuliaOJIT::getTargetOptions() const {
1458 : 25 : return TM->Options;
1459 : : }
1460 : 25 : const Target &JuliaOJIT::getTarget() const {
1461 : 25 : return TM->getTarget();
1462 : : }
1463 : 99 : TargetIRAnalysis JuliaOJIT::getTargetIRAnalysis() const {
1464 : 99 : return TM->getTargetIRAnalysis();
1465 : : }
1466 : :
1467 : 334404 : static void jl_decorate_module(Module &M) {
1468 : : #if defined(_CPU_X86_64_) && defined(_OS_WINDOWS_)
1469 : : // Add special values used by debuginfo to build the UnwindData table registration for Win64
1470 : : // This used to be GV, but with https://reviews.llvm.org/D100944 we no longer can emit GV into `.text`
1471 : : // TODO: The data is set in debuginfo.cpp but it should be okay to actually emit it here.
1472 : : M.appendModuleInlineAsm("\
1473 : : .section .text \n\
1474 : : .type __UnwindData,@object \n\
1475 : : .p2align 2, 0x90 \n\
1476 : : __UnwindData: \n\
1477 : : .zero 12 \n\
1478 : : .size __UnwindData, 12 \n\
1479 : : \n\
1480 : : .type __catchjmp,@object \n\
1481 : : .p2align 2, 0x90 \n\
1482 : : __catchjmp: \n\
1483 : : .zero 12 \n\
1484 : : .size __catchjmp, 12");
1485 : : #endif
1486 : 334404 : }
1487 : :
1488 : 519813 : static int jl_add_to_ee(
1489 : : orc::ThreadSafeModule &M,
1490 : : StringMap<orc::ThreadSafeModule*> &NewExports,
1491 : : DenseMap<orc::ThreadSafeModule*, int> &Queued,
1492 : : std::vector<std::vector<orc::ThreadSafeModule*>> &ToMerge,
1493 : : int depth)
1494 : : {
1495 : : // DAG-sort (post-dominator) the compile to compute the minimum
1496 : : // merge-module sets for linkage
1497 [ + + ]: 519813 : if (!M)
1498 : 180007 : return 0;
1499 : : // First check and record if it's on the stack somewhere
1500 : : {
1501 : 339806 : auto &Cycle = Queued[&M];
1502 [ + + ]: 339806 : if (Cycle)
1503 : 2590 : return Cycle;
1504 : 337216 : ToMerge.push_back({});
1505 : 337216 : Cycle = depth;
1506 : : }
1507 : 337216 : int MergeUp = depth;
1508 : : // Compute the cycle-id
1509 : 337216 : M.withModuleDo([&](Module &m) {
1510 [ + + ]: 4353980 : for (auto &F : m.global_objects()) {
1511 [ + + + - : 4016760 : if (F.isDeclaration() && F.getLinkage() == GlobalValue::ExternalLinkage) {
+ + ]
1512 : 3046220 : auto Callee = NewExports.find(F.getName());
1513 [ + + ]: 3046220 : if (Callee != NewExports.end()) {
1514 : 182597 : auto &CM = Callee->second;
1515 : 182597 : int Down = jl_add_to_ee(*CM, NewExports, Queued, ToMerge, depth + 1);
1516 [ - + ]: 182597 : assert(Down <= depth);
1517 [ + + + + ]: 182597 : if (Down && Down < MergeUp)
1518 : 4224 : MergeUp = Down;
1519 : : }
1520 : : }
1521 : : }
1522 : 337216 : });
1523 [ + + ]: 337216 : if (MergeUp == depth) {
1524 : : // Not in a cycle (or at the top of it)
1525 : 333108 : Queued.erase(&M);
1526 [ + + ]: 337216 : for (auto &CM : ToMerge.at(depth - 1)) {
1527 [ - + ]: 4108 : assert(Queued.find(CM)->second == depth);
1528 : 4108 : Queued.erase(CM);
1529 : 4108 : jl_merge_module(M, std::move(*CM));
1530 : : }
1531 : 333108 : jl_ExecutionEngine->addModule(std::move(M));
1532 : 333107 : MergeUp = 0;
1533 : : }
1534 : : else {
1535 : : // Add our frame(s) to the top of the cycle
1536 : 4108 : Queued[&M] = MergeUp;
1537 : 4108 : auto &Top = ToMerge.at(MergeUp - 1);
1538 : 4108 : Top.push_back(&M);
1539 [ + + ]: 4464 : for (auto &CM : ToMerge.at(depth - 1)) {
1540 [ - + ]: 356 : assert(Queued.find(CM)->second == depth);
1541 : 356 : Queued[CM] = MergeUp;
1542 : 356 : Top.push_back(CM);
1543 : : }
1544 : : }
1545 : 337215 : ToMerge.pop_back();
1546 : 337215 : return MergeUp;
1547 : : }
1548 : :
1549 : 337216 : static void jl_add_to_ee(orc::ThreadSafeModule &M, StringMap<orc::ThreadSafeModule*> &NewExports)
1550 : : {
1551 : 674431 : DenseMap<orc::ThreadSafeModule*, int> Queued;
1552 : 674431 : std::vector<std::vector<orc::ThreadSafeModule*>> ToMerge;
1553 : 337216 : jl_add_to_ee(M, NewExports, Queued, ToMerge, 1);
1554 [ - + ]: 337215 : assert(!M);
1555 : 337215 : }
1556 : :
1557 : :
1558 : 655189 : static uint64_t getAddressForFunction(StringRef fname)
1559 : : {
1560 : 655189 : auto addr = jl_ExecutionEngine->getFunctionAddress(fname);
1561 [ - + ]: 655189 : assert(addr);
1562 : 655189 : return addr;
1563 : : }
1564 : :
1565 : : // helper function for adding a DLLImport (dlsym) address to the execution engine
1566 : 59535 : void add_named_global(StringRef name, void *addr)
1567 : : {
1568 : 59535 : jl_ExecutionEngine->addGlobalMapping(name, (uint64_t)(uintptr_t)addr);
1569 : 59535 : }
1570 : :
1571 : : extern "C" JL_DLLEXPORT
1572 : 1 : size_t jl_jit_total_bytes_impl(void)
1573 : : {
1574 : 1 : return jl_ExecutionEngine->getTotalBytes();
1575 : : }
|