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/ADT/MapVector.h>
4 : :
5 : : #include <llvm/IR/LLVMContext.h>
6 : : #include <llvm/IR/Constants.h>
7 : : #include <llvm/IR/Module.h>
8 : : #include <llvm/IR/Value.h>
9 : : #include <llvm/IR/PassManager.h>
10 : : #include <llvm/IR/LegacyPassManager.h>
11 : :
12 : : #include <llvm/ExecutionEngine/Orc/IRCompileLayer.h>
13 : : #include <llvm/ExecutionEngine/Orc/IRTransformLayer.h>
14 : : #include <llvm/ExecutionEngine/JITEventListener.h>
15 : :
16 : : #include <llvm/Target/TargetMachine.h>
17 : : #include "julia_assert.h"
18 : : #include "debug-registry.h"
19 : :
20 : : #include <stack>
21 : : #include <queue>
22 : :
23 : : // As of LLVM 13, there are two runtime JIT linker implementations, the older
24 : : // RuntimeDyld (used via orc::RTDyldObjectLinkingLayer) and the newer JITLink
25 : : // (used via orc::ObjectLinkingLayer).
26 : : //
27 : : // JITLink is not only more flexible (which isn't of great importance for us, as
28 : : // we do only single-threaded in-process codegen), but crucially supports using
29 : : // the Small code model, where the linker needs to fix up relocations between
30 : : // object files that end up far apart in address space. RuntimeDyld can't do
31 : : // that and relies on the Large code model instead, which is broken on
32 : : // aarch64-darwin (macOS on ARM64), and not likely to ever be supported there
33 : : // (see https://bugs.llvm.org/show_bug.cgi?id=52029).
34 : : //
35 : : // However, JITLink is a relatively young library and lags behind in platform
36 : : // and feature support (e.g. Windows, JITEventListeners for various profilers,
37 : : // etc.). Thus, we currently only use JITLink where absolutely required, that is,
38 : : // for Mac/aarch64.
39 : : #if defined(_OS_DARWIN_) && defined(_CPU_AARCH64_)
40 : : # if JL_LLVM_VERSION < 130000
41 : : # pragma message("On aarch64-darwin, LLVM version >= 13 is required for JITLink; fallback suffers from occasional segfaults")
42 : : # endif
43 : : # define JL_USE_JITLINK
44 : : #endif
45 : :
46 : : #ifdef JL_USE_JITLINK
47 : : # include <llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h>
48 : : #else
49 : : # include <llvm/ExecutionEngine/RTDyldMemoryManager.h>
50 : : # include <llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h>
51 : : #endif
52 : :
53 : : using namespace llvm;
54 : :
55 : : extern "C" jl_cgparams_t jl_default_cgparams;
56 : :
57 : : DEFINE_SIMPLE_CONVERSION_FUNCTIONS(orc::ThreadSafeContext, LLVMOrcThreadSafeContextRef)
58 : 0 : DEFINE_SIMPLE_CONVERSION_FUNCTIONS(orc::ThreadSafeModule, LLVMOrcThreadSafeModuleRef)
59 : :
60 : : void addTargetPasses(legacy::PassManagerBase *PM, const Triple &triple, TargetIRAnalysis analysis);
61 : : void addOptimizationPasses(legacy::PassManagerBase *PM, int opt_level, bool lower_intrinsics=true, bool dump_native=false, bool external_use=false);
62 : : void addMachinePasses(legacy::PassManagerBase *PM, int optlevel);
63 : : void jl_finalize_module(orc::ThreadSafeModule m);
64 : : void jl_merge_module(orc::ThreadSafeModule &dest, orc::ThreadSafeModule src);
65 : : GlobalVariable *jl_emit_RTLD_DEFAULT_var(Module *M);
66 : : DataLayout jl_create_datalayout(TargetMachine &TM);
67 : :
68 : 16230 : static inline bool imaging_default() {
69 [ + - + + : 16230 : return jl_options.image_codegen || (jl_generating_output() && !jl_options.incremental);
+ + ]
70 : : }
71 : :
72 : : struct jl_locked_stream {
73 : : JL_STREAM *stream = nullptr;
74 : : std::mutex mutex;
75 : :
76 : : struct lock {
77 : : std::unique_lock<std::mutex> lck;
78 : : JL_STREAM *&stream;
79 : :
80 : 203420 : lock(std::mutex &mutex, JL_STREAM *&stream) : lck(mutex), stream(stream) {}
81 : :
82 : 0 : JL_STREAM *&operator*() {
83 : 0 : return stream;
84 : : }
85 : :
86 : 203420 : explicit operator bool() {
87 : 203420 : return !!stream;
88 : : }
89 : :
90 : 0 : operator JL_STREAM *() {
91 : 0 : return stream;
92 : : }
93 : : };
94 : :
95 : 203420 : lock operator*() {
96 : 203420 : return lock(mutex, stream);
97 : : }
98 : : };
99 : :
100 : : typedef struct _jl_llvm_functions_t {
101 : : std::string functionObject; // jlcall llvm Function name
102 : : std::string specFunctionObject; // specialized llvm Function name
103 : : } jl_llvm_functions_t;
104 : :
105 : : struct jl_returninfo_t {
106 : : llvm::Function *decl;
107 : : enum CallingConv {
108 : : Boxed = 0,
109 : : Register,
110 : : SRet,
111 : : Union,
112 : : Ghosts
113 : : } cc;
114 : : size_t union_bytes;
115 : : size_t union_align;
116 : : size_t union_minalign;
117 : : unsigned return_roots;
118 : : };
119 : :
120 : : typedef std::tuple<jl_returninfo_t::CallingConv, unsigned, llvm::Function*, bool> jl_codegen_call_target_t;
121 : :
122 : : typedef struct _jl_codegen_params_t {
123 : : orc::ThreadSafeContext tsctx;
124 : : orc::ThreadSafeContext::Lock tsctx_lock;
125 : : typedef StringMap<GlobalVariable*> SymMapGV;
126 : : // outputs
127 : : std::vector<std::pair<jl_code_instance_t*, jl_codegen_call_target_t>> workqueue;
128 : : std::map<void*, GlobalVariable*> globals;
129 : : std::map<jl_datatype_t*, DIType*> ditypes;
130 : : std::map<jl_datatype_t*, Type*> llvmtypes;
131 : : DenseMap<Constant*, GlobalVariable*> mergedConstants;
132 : : // Map from symbol name (in a certain library) to its GV in sysimg and the
133 : : // DL handle address in the current session.
134 : : StringMap<std::pair<GlobalVariable*,SymMapGV>> libMapGV;
135 : : #ifdef _OS_WINDOWS_
136 : : SymMapGV symMapExe;
137 : : SymMapGV symMapDll;
138 : : SymMapGV symMapDlli;
139 : : #endif
140 : : SymMapGV symMapDefault;
141 : : // Map from distinct callee's to its GOT entry.
142 : : // In principle the attribute, function type and calling convention
143 : : // don't need to be part of the key but it seems impossible to forward
144 : : // all the arguments without writing assembly directly.
145 : : // This doesn't matter too much in reality since a single function is usually
146 : : // not called with multiple signatures.
147 : : DenseMap<AttributeList, std::map<
148 : : std::tuple<GlobalVariable*, FunctionType*, CallingConv::ID>,
149 : : GlobalVariable*>> allPltMap;
150 : : orc::ThreadSafeModule _shared_module;
151 : : inline orc::ThreadSafeModule &shared_module(Module &from);
152 : : // inputs
153 : : size_t world = 0;
154 : : const jl_cgparams_t *params = &jl_default_cgparams;
155 : : bool cache = false;
156 : : bool imaging;
157 : 16208 : _jl_codegen_params_t(orc::ThreadSafeContext ctx) : tsctx(std::move(ctx)), tsctx_lock(tsctx.getLock()), imaging(imaging_default()) {}
158 : : } jl_codegen_params_t;
159 : :
160 : : jl_llvm_functions_t jl_emit_code(
161 : : orc::ThreadSafeModule &M,
162 : : jl_method_instance_t *mi,
163 : : jl_code_info_t *src,
164 : : jl_value_t *jlrettype,
165 : : jl_codegen_params_t ¶ms);
166 : :
167 : : jl_llvm_functions_t jl_emit_codeinst(
168 : : orc::ThreadSafeModule &M,
169 : : jl_code_instance_t *codeinst,
170 : : jl_code_info_t *src,
171 : : jl_codegen_params_t ¶ms);
172 : :
173 : : enum CompilationPolicy {
174 : : Default = 0,
175 : : Extern = 1,
176 : : ImagingMode = 2
177 : : };
178 : :
179 : : typedef std::map<jl_code_instance_t*, std::pair<orc::ThreadSafeModule, jl_llvm_functions_t>> jl_workqueue_t;
180 : :
181 : : void jl_compile_workqueue(
182 : : jl_workqueue_t &emitted,
183 : : Module &original,
184 : : jl_codegen_params_t ¶ms,
185 : : CompilationPolicy policy);
186 : :
187 : : Function *jl_cfunction_object(jl_function_t *f, jl_value_t *rt, jl_tupletype_t *argt,
188 : : jl_codegen_params_t ¶ms);
189 : :
190 : : void add_named_global(StringRef name, void *addr);
191 : :
192 : 2039193 : static inline Constant *literal_static_pointer_val(const void *p, Type *T)
193 : : {
194 : : // this function will emit a static pointer into the generated code
195 : : // the generated code will only be valid during the current session,
196 : : // and thus, this should typically be avoided in new API's
197 : : #if defined(_P64)
198 : 2039193 : return ConstantExpr::getIntToPtr(ConstantInt::get(Type::getInt64Ty(T->getContext()), (uint64_t)p), T);
199 : : #else
200 : : return ConstantExpr::getIntToPtr(ConstantInt::get(Type::getInt32Ty(T->getContext()), (uint32_t)p), T);
201 : : #endif
202 : : }
203 : :
204 : 214953 : static const inline char *name_from_method_instance(jl_method_instance_t *li) JL_NOTSAFEPOINT
205 : : {
206 [ + + ]: 214953 : return jl_is_method(li->def.method) ? jl_symbol_name(li->def.method->name) : "top-level scope";
207 : : }
208 : :
209 : : typedef JITSymbol JL_JITSymbol;
210 : : // The type that is similar to SymbolInfo on LLVM 4.0 is actually
211 : : // `JITEvaluatedSymbol`. However, we only use this type when a JITSymbol
212 : : // is expected.
213 : : typedef JITSymbol JL_SymbolInfo;
214 : :
215 : : using CompilerResultT = Expected<std::unique_ptr<llvm::MemoryBuffer>>;
216 : : using OptimizerResultT = Expected<orc::ThreadSafeModule>;
217 : :
218 : : class JuliaOJIT {
219 : : public:
220 : : #ifdef JL_USE_JITLINK
221 : : typedef orc::ObjectLinkingLayer ObjLayerT;
222 : : #else
223 : : typedef orc::RTDyldObjectLinkingLayer ObjLayerT;
224 : : #endif
225 : : typedef orc::IRCompileLayer CompileLayerT;
226 : : typedef orc::IRTransformLayer OptimizeLayerT;
227 : : typedef object::OwningBinary<object::ObjectFile> OwningObj;
228 : : template
229 : : <typename ResourceT, size_t max = 0,
230 : : typename BackingT = std::stack<ResourceT,
231 : : std::conditional_t<max == 0,
232 : : SmallVector<ResourceT>,
233 : : SmallVector<ResourceT, max>
234 : : >
235 : : >
236 : : >
237 : : struct ResourcePool {
238 : : public:
239 : 135 : ResourcePool(std::function<ResourceT()> creator) : creator(std::move(creator)), mutex(std::make_unique<WNMutex>()) {}
240 : : class OwningResource {
241 : : public:
242 : 77945298 : OwningResource(ResourcePool &pool, ResourceT resource) : pool(pool), resource(std::move(resource)) {}
243 : : OwningResource(const OwningResource &) = delete;
244 : : OwningResource &operator=(const OwningResource &) = delete;
245 : : OwningResource(OwningResource &&) = default;
246 : : OwningResource &operator=(OwningResource &&) = default;
247 : 77945298 : ~OwningResource() {
248 [ + - ]: 77945298 : if (resource) pool.release(std::move(*resource));
249 : 77945298 : }
250 : : ResourceT release() {
251 : : ResourceT res(std::move(*resource));
252 : : resource.reset();
253 : : return res;
254 : : }
255 : : void reset(ResourceT res) {
256 : : *resource = std::move(res);
257 : : }
258 : 77945298 : ResourceT &operator*() {
259 : 77945298 : return *resource;
260 : : }
261 : : ResourceT *operator->() {
262 : : return get();
263 : : }
264 : : ResourceT *get() {
265 : : return resource.getPointer();
266 : : }
267 : : const ResourceT &operator*() const {
268 : : return *resource;
269 : : }
270 : : const ResourceT *operator->() const {
271 : : return get();
272 : : }
273 : : const ResourceT *get() const {
274 : : return resource.getPointer();
275 : : }
276 : : explicit operator bool() const {
277 : : return resource;
278 : : }
279 : : private:
280 : : ResourcePool &pool;
281 : : llvm::Optional<ResourceT> resource;
282 : : };
283 : :
284 : 77945298 : OwningResource operator*() {
285 : 77945298 : return OwningResource(*this, acquire());
286 : : }
287 : :
288 : : OwningResource get() {
289 : : return **this;
290 : : }
291 : :
292 : 77945298 : ResourceT acquire() {
293 : 155890596 : std::unique_lock<std::mutex> lock(mutex->mutex);
294 [ + + ]: 77945298 : if (!pool.empty()) {
295 : 77945168 : return pop(pool);
296 : : }
297 : : if (!max || created < max) {
298 : 71 : created++;
299 : 71 : return creator();
300 : : }
301 : : mutex->empty.wait(lock, [&](){ return !pool.empty(); });
302 : : assert(!pool.empty() && "Expected resource pool to have a value!");
303 : : return pop(pool);
304 : : }
305 : 77945298 : void release(ResourceT &&resource) {
306 : 155890596 : std::lock_guard<std::mutex> lock(mutex->mutex);
307 : 77945298 : pool.push(std::move(resource));
308 : 77945298 : mutex->empty.notify_one();
309 : 77945298 : }
310 : : private:
311 : : template<typename T, typename Container>
312 : 77864400 : static ResourceT pop(std::queue<T, Container> &pool) {
313 : 77864400 : ResourceT top = std::move(pool.front());
314 : 77864400 : pool.pop();
315 : 77864400 : return top;
316 : : }
317 : : template<typename PoolT>
318 : 80768 : static ResourceT pop(PoolT &pool) {
319 : 80768 : ResourceT top = std::move(pool.top());
320 : 80768 : pool.pop();
321 : 80768 : return top;
322 : : }
323 : : std::function<ResourceT()> creator;
324 : : size_t created = 0;
325 : : BackingT pool;
326 : : struct WNMutex {
327 : : std::mutex mutex;
328 : : std::condition_variable empty;
329 : : };
330 : :
331 : : std::unique_ptr<WNMutex> mutex;
332 : : };
333 : : struct PipelineT {
334 : : PipelineT(orc::ObjectLayer &BaseLayer, TargetMachine &TM, int optlevel);
335 : : CompileLayerT CompileLayer;
336 : : OptimizeLayerT OptimizeLayer;
337 : : };
338 : :
339 : : struct OptSelLayerT : orc::IRLayer {
340 : :
341 : : template<size_t N>
342 : 15 : OptSelLayerT(const std::array<std::unique_ptr<PipelineT>, N> &optimizers)
343 : 15 : : orc::IRLayer(optimizers[0]->OptimizeLayer.getExecutionSession(),
344 : 15 : optimizers[0]->OptimizeLayer.getManglingOptions()),
345 : : optimizers(optimizers.data()),
346 : 45 : count(N) {
347 : : static_assert(N > 0, "Expected array with at least one optimizer!");
348 : 15 : }
349 : :
350 : : void emit(std::unique_ptr<orc::MaterializationResponsibility> R, orc::ThreadSafeModule TSM) override;
351 : :
352 : : private:
353 : : const std::unique_ptr<PipelineT> * const optimizers;
354 : : size_t count;
355 : : };
356 : :
357 : : private:
358 : : // Custom object emission notification handler for the JuliaOJIT
359 : : template <typename ObjT, typename LoadResult>
360 : : void registerObject(const ObjT &Obj, const LoadResult &LO);
361 : :
362 : : public:
363 : :
364 : : JuliaOJIT();
365 : :
366 : : void enableJITDebuggingSupport();
367 : : #ifndef JL_USE_JITLINK
368 : : // JITLink doesn't support old JITEventListeners (yet).
369 : : void RegisterJITEventListener(JITEventListener *L);
370 : : #endif
371 : :
372 : : void addGlobalMapping(StringRef Name, uint64_t Addr);
373 : : void addModule(orc::ThreadSafeModule M);
374 : :
375 : : JL_JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly);
376 : : JL_JITSymbol findUnmangledSymbol(StringRef Name);
377 : : uint64_t getGlobalValueAddress(StringRef Name);
378 : : uint64_t getFunctionAddress(StringRef Name);
379 : : StringRef getFunctionAtAddress(uint64_t Addr, jl_code_instance_t *codeinst);
380 : 77864500 : auto getContext() {
381 : 77864500 : return *ContextPool;
382 : : }
383 : 5 : orc::ThreadSafeContext acquireContext() {
384 : 5 : return ContextPool.acquire();
385 : : }
386 : 5 : void releaseContext(orc::ThreadSafeContext &&ctx) {
387 : 5 : ContextPool.release(std::move(ctx));
388 : 5 : }
389 : : const DataLayout& getDataLayout() const;
390 : :
391 : : // TargetMachine pass-through methods
392 : : std::unique_ptr<TargetMachine> cloneTargetMachine() const;
393 : : const Triple& getTargetTriple() const;
394 : : StringRef getTargetFeatureString() const;
395 : : StringRef getTargetCPU() const;
396 : : const TargetOptions &getTargetOptions() const;
397 : : const Target &getTarget() const;
398 : : TargetIRAnalysis getTargetIRAnalysis() const;
399 : :
400 : : size_t getTotalBytes() const;
401 : :
402 : 115280 : JITDebugInfoRegistry &getDebugInfoRegistry() JL_NOTSAFEPOINT {
403 : 115280 : return DebugRegistry;
404 : : }
405 : :
406 : 90315 : jl_locked_stream &get_dump_emitted_mi_name_stream() JL_NOTSAFEPOINT {
407 : 90315 : return dump_emitted_mi_name_stream;
408 : : }
409 : 32307 : jl_locked_stream &get_dump_compiles_stream() JL_NOTSAFEPOINT {
410 : 32307 : return dump_compiles_stream;
411 : : }
412 : 80798 : jl_locked_stream &get_dump_llvm_opt_stream() JL_NOTSAFEPOINT {
413 : 80798 : return dump_llvm_opt_stream;
414 : : }
415 : : private:
416 : : std::string getMangledName(StringRef Name);
417 : : std::string getMangledName(const GlobalValue *GV);
418 : : void shareStrings(Module &M);
419 : :
420 : : const std::unique_ptr<TargetMachine> TM;
421 : : const DataLayout DL;
422 : :
423 : : orc::ExecutionSession ES;
424 : : orc::JITDylib &GlobalJD;
425 : : orc::JITDylib &JD;
426 : :
427 : : JITDebugInfoRegistry DebugRegistry;
428 : :
429 : : //Map and inc are guarded by RLST_mutex
430 : : std::mutex RLST_mutex{};
431 : : int RLST_inc = 0;
432 : : DenseMap<void*, std::string> ReverseLocalSymbolTable;
433 : :
434 : : //Compilation streams
435 : : jl_locked_stream dump_emitted_mi_name_stream;
436 : : jl_locked_stream dump_compiles_stream;
437 : : jl_locked_stream dump_llvm_opt_stream;
438 : :
439 : : ResourcePool<orc::ThreadSafeContext, 0, std::queue<orc::ThreadSafeContext>> ContextPool;
440 : :
441 : : #ifndef JL_USE_JITLINK
442 : : const std::shared_ptr<RTDyldMemoryManager> MemMgr;
443 : : #endif
444 : : ObjLayerT ObjectLayer;
445 : : const std::array<std::unique_ptr<PipelineT>, 4> Pipelines;
446 : : OptSelLayerT OptSelLayer;
447 : : };
448 : : extern JuliaOJIT *jl_ExecutionEngine;
449 : : orc::ThreadSafeModule jl_create_llvm_module(StringRef name, orc::ThreadSafeContext ctx, bool imaging_mode, const DataLayout &DL = jl_ExecutionEngine->getDataLayout(), const Triple &triple = jl_ExecutionEngine->getTargetTriple());
450 : :
451 : 71023 : orc::ThreadSafeModule &jl_codegen_params_t::shared_module(Module &from) {
452 [ + + ]: 71023 : if (!_shared_module) {
453 : 2084 : _shared_module = jl_create_llvm_module("globals", tsctx, imaging, from.getDataLayout(), Triple(from.getTargetTriple()));
454 : : assert(&from.getContext() == tsctx.getContext() && "Module context differs from codegen_params context!");
455 : : } else {
456 : : assert(&from.getContext() == _shared_module.getContext().getContext() && "Module context differs from shared module context!");
457 : : assert(from.getDataLayout() == _shared_module.getModuleUnlocked()->getDataLayout() && "Module data layout differs from shared module data layout!");
458 : : assert(from.getTargetTriple() == _shared_module.getModuleUnlocked()->getTargetTriple() && "Module target triple differs from shared module target triple!");
459 : : }
460 : 71023 : return _shared_module;
461 : : }
462 : :
463 : : Pass *createLowerPTLSPass(bool imaging_mode);
464 : : Pass *createCombineMulAddPass();
465 : : Pass *createFinalLowerGCPass();
466 : : Pass *createLateLowerGCFramePass();
467 : : Pass *createLowerExcHandlersPass();
468 : : Pass *createGCInvariantVerifierPass(bool Strong);
469 : : Pass *createPropagateJuliaAddrspaces();
470 : : Pass *createRemoveJuliaAddrspacesPass();
471 : : Pass *createRemoveNIPass();
472 : : Pass *createJuliaLICMPass();
473 : : Pass *createMultiVersioningPass(bool external_use);
474 : : Pass *createAllocOptPass();
475 : : Pass *createDemoteFloat16Pass();
476 : : Pass *createCPUFeaturesPass();
477 : : Pass *createLowerSimdLoopPass();
478 : :
479 : : // NewPM
480 : : #include "passes.h"
481 : :
482 : : // Whether the Function is an llvm or julia intrinsic.
483 : 346075 : static inline bool isIntrinsicFunction(Function *F)
484 : : {
485 [ + + + + ]: 346075 : return F->isIntrinsic() || F->getName().startswith("julia.");
486 : : }
487 : :
488 : : CodeGenOpt::Level CodeGenOptLevelFor(int optlevel);
|