Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * llvmjit.c
4 : * Core part of the LLVM JIT provider.
5 : *
6 : * Copyright (c) 2016-2024, PostgreSQL Global Development Group
7 : *
8 : * IDENTIFICATION
9 : * src/backend/jit/llvm/llvmjit.c
10 : *
11 : *-------------------------------------------------------------------------
12 : */
13 :
14 : #include "postgres.h"
15 :
16 : #include <llvm-c/Analysis.h>
17 : #include <llvm-c/BitReader.h>
18 : #include <llvm-c/BitWriter.h>
19 : #include <llvm-c/Core.h>
20 : #include <llvm-c/ExecutionEngine.h>
21 : #if LLVM_VERSION_MAJOR > 16
22 : #include <llvm-c/Transforms/PassBuilder.h>
23 : #endif
24 : #include <llvm-c/Orc.h>
25 : #include <llvm-c/OrcEE.h>
26 : #include <llvm-c/LLJIT.h>
27 : #include <llvm-c/Support.h>
28 : #include <llvm-c/Target.h>
29 : #if LLVM_VERSION_MAJOR < 17
30 : #include <llvm-c/Transforms/IPO.h>
31 : #include <llvm-c/Transforms/PassManagerBuilder.h>
32 : #include <llvm-c/Transforms/Scalar.h>
33 : #include <llvm-c/Transforms/Utils.h>
34 : #endif
35 :
36 : #include "jit/llvmjit.h"
37 : #include "jit/llvmjit_backport.h"
38 : #include "jit/llvmjit_emit.h"
39 : #include "miscadmin.h"
40 : #include "portability/instr_time.h"
41 : #include "storage/ipc.h"
42 : #include "utils/memutils.h"
43 : #include "utils/resowner.h"
44 :
45 : #define LLVMJIT_LLVM_CONTEXT_REUSE_MAX 100
46 :
47 : /* Handle of a module emitted via ORC JIT */
48 : typedef struct LLVMJitHandle
49 : {
50 : LLVMOrcLLJITRef lljit;
51 : LLVMOrcResourceTrackerRef resource_tracker;
52 : } LLVMJitHandle;
53 :
54 :
55 : /* types & functions commonly needed for JITing */
56 : LLVMTypeRef TypeSizeT;
57 : LLVMTypeRef TypeParamBool;
58 : LLVMTypeRef TypeStorageBool;
59 : LLVMTypeRef TypePGFunction;
60 : LLVMTypeRef StructNullableDatum;
61 : LLVMTypeRef StructHeapTupleData;
62 : LLVMTypeRef StructMinimalTupleData;
63 : LLVMTypeRef StructTupleDescData;
64 : LLVMTypeRef StructTupleTableSlot;
65 : LLVMTypeRef StructHeapTupleHeaderData;
66 : LLVMTypeRef StructHeapTupleTableSlot;
67 : LLVMTypeRef StructMinimalTupleTableSlot;
68 : LLVMTypeRef StructMemoryContextData;
69 : LLVMTypeRef StructFunctionCallInfoData;
70 : LLVMTypeRef StructExprContext;
71 : LLVMTypeRef StructExprEvalStep;
72 : LLVMTypeRef StructExprState;
73 : LLVMTypeRef StructAggState;
74 : LLVMTypeRef StructAggStatePerGroupData;
75 : LLVMTypeRef StructAggStatePerTransData;
76 : LLVMTypeRef StructPlanState;
77 :
78 : LLVMValueRef AttributeTemplate;
79 : LLVMValueRef ExecEvalSubroutineTemplate;
80 : LLVMValueRef ExecEvalBoolSubroutineTemplate;
81 :
82 : static LLVMModuleRef llvm_types_module = NULL;
83 :
84 : static bool llvm_session_initialized = false;
85 : static size_t llvm_generation = 0;
86 :
87 : /* number of LLVMJitContexts that currently are in use */
88 : static size_t llvm_jit_context_in_use_count = 0;
89 :
90 : /* how many times has the current LLVMContextRef been used */
91 : static size_t llvm_llvm_context_reuse_count = 0;
92 : static const char *llvm_triple = NULL;
93 : static const char *llvm_layout = NULL;
94 : static LLVMContextRef llvm_context;
95 :
96 :
97 : static LLVMTargetRef llvm_targetref;
98 : static LLVMOrcThreadSafeContextRef llvm_ts_context;
99 : static LLVMOrcLLJITRef llvm_opt0_orc;
100 : static LLVMOrcLLJITRef llvm_opt3_orc;
101 :
102 :
103 : static void llvm_release_context(JitContext *context);
104 : static void llvm_session_initialize(void);
105 : static void llvm_shutdown(int code, Datum arg);
106 : static void llvm_compile_module(LLVMJitContext *context);
107 : static void llvm_optimize_module(LLVMJitContext *context, LLVMModuleRef module);
108 :
109 : static void llvm_create_types(void);
110 : static void llvm_set_target(void);
111 : static void llvm_recreate_llvm_context(void);
112 : static uint64_t llvm_resolve_symbol(const char *name, void *ctx);
113 :
114 : static LLVMOrcLLJITRef llvm_create_jit_instance(LLVMTargetMachineRef tm);
115 : static char *llvm_error_message(LLVMErrorRef error);
116 :
117 : /* ResourceOwner callbacks to hold JitContexts */
118 : static void ResOwnerReleaseJitContext(Datum res);
119 :
120 : static const ResourceOwnerDesc jit_resowner_desc =
121 : {
122 : .name = "LLVM JIT context",
123 : .release_phase = RESOURCE_RELEASE_BEFORE_LOCKS,
124 : .release_priority = RELEASE_PRIO_JIT_CONTEXTS,
125 : .ReleaseResource = ResOwnerReleaseJitContext,
126 : .DebugPrint = NULL /* the default message is fine */
127 : };
128 :
129 : /* Convenience wrappers over ResourceOwnerRemember/Forget */
130 : static inline void
131 1216 : ResourceOwnerRememberJIT(ResourceOwner owner, LLVMJitContext *handle)
132 : {
133 1216 : ResourceOwnerRemember(owner, PointerGetDatum(handle), &jit_resowner_desc);
134 1216 : }
135 : static inline void
136 1200 : ResourceOwnerForgetJIT(ResourceOwner owner, LLVMJitContext *handle)
137 : {
138 1200 : ResourceOwnerForget(owner, PointerGetDatum(handle), &jit_resowner_desc);
139 1200 : }
140 :
141 1942 : PG_MODULE_MAGIC;
142 :
143 :
144 : /*
145 : * Initialize LLVM JIT provider.
146 : */
147 : void
148 470 : _PG_jit_provider_init(JitProviderCallbacks *cb)
149 : {
150 470 : cb->reset_after_error = llvm_reset_after_error;
151 470 : cb->release_context = llvm_release_context;
152 470 : cb->compile_expr = llvm_compile_expr;
153 470 : }
154 :
155 :
156 : /*
157 : * Every now and then create a new LLVMContextRef. Unfortunately, during every
158 : * round of inlining, types may "leak" (they can still be found/used via the
159 : * context, but new types will be created the next time in inlining is
160 : * performed). To prevent that from slowly accumulating problematic amounts of
161 : * memory, recreate the LLVMContextRef we use. We don't want to do so too
162 : * often, as that implies some overhead (particularly re-loading the module
163 : * summaries / modules is fairly expensive). A future TODO would be to make
164 : * this more finegrained and only drop/recreate the LLVMContextRef when we know
165 : * there has been inlining. If we can get the size of the context from LLVM
166 : * then that might be a better way to determine when to drop/recreate rather
167 : * then the usagecount heuristic currently employed.
168 : */
169 : static void
170 1216 : llvm_recreate_llvm_context(void)
171 : {
172 1216 : if (!llvm_context)
173 0 : elog(ERROR, "Trying to recreate a non-existing context");
174 :
175 : /*
176 : * We can only safely recreate the LLVM context if no other code is being
177 : * JITed, otherwise we'd release the types in use for that.
178 : */
179 1216 : if (llvm_jit_context_in_use_count > 0)
180 : {
181 0 : llvm_llvm_context_reuse_count++;
182 0 : return;
183 : }
184 :
185 1216 : if (llvm_llvm_context_reuse_count <= LLVMJIT_LLVM_CONTEXT_REUSE_MAX)
186 : {
187 1216 : llvm_llvm_context_reuse_count++;
188 1216 : return;
189 : }
190 :
191 : /*
192 : * Need to reset the modules that the inlining code caches before
193 : * disposing of the context. LLVM modules exist within a specific LLVM
194 : * context, therefore disposing of the context before resetting the cache
195 : * would lead to dangling pointers to modules.
196 : */
197 0 : llvm_inline_reset_caches();
198 :
199 0 : LLVMContextDispose(llvm_context);
200 0 : llvm_context = LLVMContextCreate();
201 0 : llvm_llvm_context_reuse_count = 0;
202 :
203 : /*
204 : * Re-build cached type information, so code generation code can rely on
205 : * that information to be present (also prevents the variables to be
206 : * dangling references).
207 : */
208 0 : llvm_create_types();
209 : }
210 :
211 :
212 : /*
213 : * Create a context for JITing work.
214 : *
215 : * The context, including subsidiary resources, will be cleaned up either when
216 : * the context is explicitly released, or when the lifetime of
217 : * CurrentResourceOwner ends (usually the end of the current [sub]xact).
218 : */
219 : LLVMJitContext *
220 1216 : llvm_create_context(int jitFlags)
221 : {
222 : LLVMJitContext *context;
223 :
224 1216 : llvm_assert_in_fatal_section();
225 :
226 1216 : llvm_session_initialize();
227 :
228 1216 : llvm_recreate_llvm_context();
229 :
230 1216 : ResourceOwnerEnlarge(CurrentResourceOwner);
231 :
232 1216 : context = MemoryContextAllocZero(TopMemoryContext,
233 : sizeof(LLVMJitContext));
234 1216 : context->base.flags = jitFlags;
235 :
236 : /* ensure cleanup */
237 1216 : context->resowner = CurrentResourceOwner;
238 1216 : ResourceOwnerRememberJIT(CurrentResourceOwner, context);
239 :
240 1216 : llvm_jit_context_in_use_count++;
241 :
242 1216 : return context;
243 : }
244 :
245 : /*
246 : * Release resources required by one llvm context.
247 : */
248 : static void
249 1216 : llvm_release_context(JitContext *context)
250 : {
251 1216 : LLVMJitContext *llvm_jit_context = (LLVMJitContext *) context;
252 : ListCell *lc;
253 :
254 : /*
255 : * Consider as cleaned up even if we skip doing so below, that way we can
256 : * verify the tracking is correct (see llvm_shutdown()).
257 : */
258 1216 : llvm_jit_context_in_use_count--;
259 :
260 : /*
261 : * When this backend is exiting, don't clean up LLVM. As an error might
262 : * have occurred from within LLVM, we do not want to risk reentering. All
263 : * resource cleanup is going to happen through process exit.
264 : */
265 1216 : if (proc_exit_inprogress)
266 0 : return;
267 :
268 1216 : llvm_enter_fatal_on_oom();
269 :
270 1216 : if (llvm_jit_context->module)
271 : {
272 346 : LLVMDisposeModule(llvm_jit_context->module);
273 346 : llvm_jit_context->module = NULL;
274 : }
275 :
276 2164 : foreach(lc, llvm_jit_context->handles)
277 : {
278 948 : LLVMJitHandle *jit_handle = (LLVMJitHandle *) lfirst(lc);
279 :
280 : {
281 : LLVMOrcExecutionSessionRef ee;
282 : LLVMOrcSymbolStringPoolRef sp;
283 :
284 948 : LLVMOrcResourceTrackerRemove(jit_handle->resource_tracker);
285 948 : LLVMOrcReleaseResourceTracker(jit_handle->resource_tracker);
286 :
287 : /*
288 : * Without triggering cleanup of the string pool, we'd leak
289 : * memory. It'd be sufficient to do this far less often, but in
290 : * experiments the required time was small enough to just always
291 : * do it.
292 : */
293 948 : ee = LLVMOrcLLJITGetExecutionSession(jit_handle->lljit);
294 948 : sp = LLVMOrcExecutionSessionGetSymbolStringPool(ee);
295 948 : LLVMOrcSymbolStringPoolClearDeadEntries(sp);
296 : }
297 :
298 948 : pfree(jit_handle);
299 : }
300 1216 : list_free(llvm_jit_context->handles);
301 1216 : llvm_jit_context->handles = NIL;
302 :
303 1216 : llvm_leave_fatal_on_oom();
304 :
305 1216 : if (llvm_jit_context->resowner)
306 1200 : ResourceOwnerForgetJIT(llvm_jit_context->resowner, llvm_jit_context);
307 : }
308 :
309 : /*
310 : * Return module which may be modified, e.g. by creating new functions.
311 : */
312 : LLVMModuleRef
313 14162 : llvm_mutable_module(LLVMJitContext *context)
314 : {
315 14162 : llvm_assert_in_fatal_section();
316 :
317 : /*
318 : * If there's no in-progress module, create a new one.
319 : */
320 14162 : if (!context->module)
321 : {
322 1294 : context->compiled = false;
323 1294 : context->module_generation = llvm_generation++;
324 1294 : context->module = LLVMModuleCreateWithNameInContext("pg", llvm_context);
325 1294 : LLVMSetTarget(context->module, llvm_triple);
326 1294 : LLVMSetDataLayout(context->module, llvm_layout);
327 : }
328 :
329 14162 : return context->module;
330 : }
331 :
332 : /*
333 : * Expand function name to be non-conflicting. This should be used by code
334 : * generating code, when adding new externally visible function definitions to
335 : * a Module.
336 : */
337 : char *
338 14162 : llvm_expand_funcname(struct LLVMJitContext *context, const char *basename)
339 : {
340 : Assert(context->module != NULL);
341 :
342 14162 : context->base.instr.created_functions++;
343 :
344 : /*
345 : * Previously we used dots to separate, but turns out some tools, e.g.
346 : * GDB, don't like that and truncate name.
347 : */
348 28324 : return psprintf("%s_%zu_%d",
349 : basename,
350 : context->module_generation,
351 14162 : context->counter++);
352 : }
353 :
354 : /*
355 : * Return pointer to function funcname, which has to exist. If there's pending
356 : * code to be optimized and emitted, do so first.
357 : */
358 : void *
359 5160 : llvm_get_function(LLVMJitContext *context, const char *funcname)
360 : {
361 : ListCell *lc;
362 :
363 5160 : llvm_assert_in_fatal_section();
364 :
365 : /*
366 : * If there is a pending / not emitted module, compile and emit now.
367 : * Otherwise we might not find the [correct] function.
368 : */
369 5160 : if (!context->compiled)
370 : {
371 948 : llvm_compile_module(context);
372 : }
373 :
374 : /*
375 : * ORC's symbol table is of *unmangled* symbols. Therefore we don't need
376 : * to mangle here.
377 : */
378 :
379 5160 : foreach(lc, context->handles)
380 : {
381 5160 : LLVMJitHandle *handle = (LLVMJitHandle *) lfirst(lc);
382 : instr_time starttime;
383 : instr_time endtime;
384 : LLVMErrorRef error;
385 : LLVMOrcJITTargetAddress addr;
386 :
387 5160 : INSTR_TIME_SET_CURRENT(starttime);
388 :
389 5160 : addr = 0;
390 5160 : error = LLVMOrcLLJITLookup(handle->lljit, &addr, funcname);
391 5160 : if (error)
392 0 : elog(ERROR, "failed to look up symbol \"%s\": %s",
393 : funcname, llvm_error_message(error));
394 :
395 : /*
396 : * LLJIT only actually emits code the first time a symbol is
397 : * referenced. Thus add lookup time to emission time. That's counting
398 : * a bit more than with older LLVM versions, but unlikely to ever
399 : * matter.
400 : */
401 5160 : INSTR_TIME_SET_CURRENT(endtime);
402 5160 : INSTR_TIME_ACCUM_DIFF(context->base.instr.emission_counter,
403 : endtime, starttime);
404 :
405 5160 : if (addr)
406 5160 : return (void *) (uintptr_t) addr;
407 : }
408 :
409 0 : elog(ERROR, "failed to JIT: %s", funcname);
410 :
411 : return NULL;
412 : }
413 :
414 : /*
415 : * Return type of a variable in llvmjit_types.c. This is useful to keep types
416 : * in sync between plain C and JIT related code.
417 : */
418 : LLVMTypeRef
419 9460 : llvm_pg_var_type(const char *varname)
420 : {
421 : LLVMValueRef v_srcvar;
422 : LLVMTypeRef typ;
423 :
424 : /* this'll return a *pointer* to the global */
425 9460 : v_srcvar = LLVMGetNamedGlobal(llvm_types_module, varname);
426 9460 : if (!v_srcvar)
427 0 : elog(ERROR, "variable %s not in llvmjit_types.c", varname);
428 :
429 9460 : typ = LLVMGlobalGetValueType(v_srcvar);
430 :
431 9460 : return typ;
432 : }
433 :
434 : /*
435 : * Return function type of a variable in llvmjit_types.c. This is useful to
436 : * keep function types in sync between C and JITed code.
437 : */
438 : LLVMTypeRef
439 12032 : llvm_pg_var_func_type(const char *varname)
440 : {
441 : LLVMValueRef v_srcvar;
442 : LLVMTypeRef typ;
443 :
444 12032 : v_srcvar = LLVMGetNamedFunction(llvm_types_module, varname);
445 12032 : if (!v_srcvar)
446 0 : elog(ERROR, "function %s not in llvmjit_types.c", varname);
447 :
448 12032 : typ = LLVMGetFunctionType(v_srcvar);
449 :
450 12032 : return typ;
451 : }
452 :
453 : /*
454 : * Return declaration for a function referenced in llvmjit_types.c, adding it
455 : * to the module if necessary.
456 : *
457 : * This is used to make functions discovered via llvm_create_types() known to
458 : * the module that's currently being worked on.
459 : */
460 : LLVMValueRef
461 12126 : llvm_pg_func(LLVMModuleRef mod, const char *funcname)
462 : {
463 : LLVMValueRef v_srcfn;
464 : LLVMValueRef v_fn;
465 :
466 : /* don't repeatedly add function */
467 12126 : v_fn = LLVMGetNamedFunction(mod, funcname);
468 12126 : if (v_fn)
469 8950 : return v_fn;
470 :
471 3176 : v_srcfn = LLVMGetNamedFunction(llvm_types_module, funcname);
472 :
473 3176 : if (!v_srcfn)
474 0 : elog(ERROR, "function %s not in llvmjit_types.c", funcname);
475 :
476 3176 : v_fn = LLVMAddFunction(mod,
477 : funcname,
478 : LLVMGetFunctionType(v_srcfn));
479 3176 : llvm_copy_attributes(v_srcfn, v_fn);
480 :
481 3176 : return v_fn;
482 : }
483 :
484 : /*
485 : * Copy attributes from one function to another, for a specific index (an
486 : * index can reference return value, function and parameter attributes).
487 : */
488 : static void
489 48880 : llvm_copy_attributes_at_index(LLVMValueRef v_from, LLVMValueRef v_to, uint32 index)
490 : {
491 : int num_attributes;
492 : LLVMAttributeRef *attrs;
493 :
494 48880 : num_attributes = LLVMGetAttributeCountAtIndex(v_from, index);
495 :
496 48880 : if (num_attributes == 0)
497 17320 : return;
498 :
499 31560 : attrs = palloc(sizeof(LLVMAttributeRef) * num_attributes);
500 31560 : LLVMGetAttributesAtIndex(v_from, index, attrs);
501 :
502 370310 : for (int attno = 0; attno < num_attributes; attno++)
503 338750 : LLVMAddAttributeAtIndex(v_to, index, attrs[attno]);
504 :
505 31560 : pfree(attrs);
506 : }
507 :
508 : /*
509 : * Copy all attributes from one function to another. I.e. function, return and
510 : * parameters will be copied.
511 : */
512 : void
513 17338 : llvm_copy_attributes(LLVMValueRef v_from, LLVMValueRef v_to)
514 : {
515 : uint32 param_count;
516 :
517 : /* copy function attributes */
518 17338 : llvm_copy_attributes_at_index(v_from, v_to, LLVMAttributeFunctionIndex);
519 :
520 17338 : if (LLVMGetTypeKind(LLVMGetFunctionReturnType(v_to)) != LLVMVoidTypeKind)
521 : {
522 : /* and the return value attributes */
523 9272 : llvm_copy_attributes_at_index(v_from, v_to, LLVMAttributeReturnIndex);
524 : }
525 :
526 : /* and each function parameter's attribute */
527 17338 : param_count = LLVMCountParams(v_from);
528 :
529 39608 : for (int paramidx = 1; paramidx <= param_count; paramidx++)
530 22270 : llvm_copy_attributes_at_index(v_from, v_to, paramidx);
531 17338 : }
532 :
533 : /*
534 : * Return a callable LLVMValueRef for fcinfo.
535 : */
536 : LLVMValueRef
537 6022 : llvm_function_reference(LLVMJitContext *context,
538 : LLVMBuilderRef builder,
539 : LLVMModuleRef mod,
540 : FunctionCallInfo fcinfo)
541 : {
542 : char *modname;
543 : char *basename;
544 : char *funcname;
545 :
546 : LLVMValueRef v_fn;
547 :
548 6022 : fmgr_symbol(fcinfo->flinfo->fn_oid, &modname, &basename);
549 :
550 6022 : if (modname != NULL && basename != NULL)
551 : {
552 : /* external function in loadable library */
553 0 : funcname = psprintf("pgextern.%s.%s", modname, basename);
554 : }
555 6022 : else if (basename != NULL)
556 : {
557 : /* internal function */
558 6010 : funcname = pstrdup(basename);
559 : }
560 : else
561 : {
562 : /*
563 : * Function we don't know to handle, return pointer. We do so by
564 : * creating a global constant containing a pointer to the function.
565 : * Makes IR more readable.
566 : */
567 : LLVMValueRef v_fn_addr;
568 :
569 12 : funcname = psprintf("pgoidextern.%u",
570 12 : fcinfo->flinfo->fn_oid);
571 12 : v_fn = LLVMGetNamedGlobal(mod, funcname);
572 12 : if (v_fn != 0)
573 0 : return l_load(builder, TypePGFunction, v_fn, "");
574 :
575 12 : v_fn_addr = l_ptr_const(fcinfo->flinfo->fn_addr, TypePGFunction);
576 :
577 12 : v_fn = LLVMAddGlobal(mod, TypePGFunction, funcname);
578 12 : LLVMSetInitializer(v_fn, v_fn_addr);
579 12 : LLVMSetGlobalConstant(v_fn, true);
580 12 : LLVMSetLinkage(v_fn, LLVMPrivateLinkage);
581 12 : LLVMSetUnnamedAddr(v_fn, true);
582 :
583 12 : return l_load(builder, TypePGFunction, v_fn, "");
584 : }
585 :
586 : /* check if function already has been added */
587 6010 : v_fn = LLVMGetNamedFunction(mod, funcname);
588 6010 : if (v_fn != 0)
589 3090 : return v_fn;
590 :
591 2920 : v_fn = LLVMAddFunction(mod, funcname, LLVMGetFunctionType(AttributeTemplate));
592 :
593 2920 : return v_fn;
594 : }
595 :
596 : /*
597 : * Optimize code in module using the flags set in context.
598 : */
599 : static void
600 948 : llvm_optimize_module(LLVMJitContext *context, LLVMModuleRef module)
601 : {
602 : #if LLVM_VERSION_MAJOR < 17
603 : LLVMPassManagerBuilderRef llvm_pmb;
604 : LLVMPassManagerRef llvm_mpm;
605 : LLVMPassManagerRef llvm_fpm;
606 : LLVMValueRef func;
607 : int compile_optlevel;
608 :
609 948 : if (context->base.flags & PGJIT_OPT3)
610 550 : compile_optlevel = 3;
611 : else
612 398 : compile_optlevel = 0;
613 :
614 : /*
615 : * Have to create a new pass manager builder every pass through, as the
616 : * inliner has some per-builder state. Otherwise one ends up only inlining
617 : * a function the first time though.
618 : */
619 948 : llvm_pmb = LLVMPassManagerBuilderCreate();
620 948 : LLVMPassManagerBuilderSetOptLevel(llvm_pmb, compile_optlevel);
621 948 : llvm_fpm = LLVMCreateFunctionPassManagerForModule(module);
622 :
623 948 : if (context->base.flags & PGJIT_OPT3)
624 : {
625 : /* TODO: Unscientifically determined threshold */
626 550 : LLVMPassManagerBuilderUseInlinerWithThreshold(llvm_pmb, 512);
627 : }
628 : else
629 : {
630 : /* we rely on mem2reg heavily, so emit even in the O0 case */
631 398 : LLVMAddPromoteMemoryToRegisterPass(llvm_fpm);
632 : }
633 :
634 948 : LLVMPassManagerBuilderPopulateFunctionPassManager(llvm_pmb, llvm_fpm);
635 :
636 : /*
637 : * Do function level optimization. This could be moved to the point where
638 : * functions are emitted, to reduce memory usage a bit.
639 : */
640 948 : LLVMInitializeFunctionPassManager(llvm_fpm);
641 23064 : for (func = LLVMGetFirstFunction(context->module);
642 : func != NULL;
643 22116 : func = LLVMGetNextFunction(func))
644 22116 : LLVMRunFunctionPassManager(llvm_fpm, func);
645 948 : LLVMFinalizeFunctionPassManager(llvm_fpm);
646 948 : LLVMDisposePassManager(llvm_fpm);
647 :
648 : /*
649 : * Perform module level optimization. We do so even in the non-optimized
650 : * case, so always-inline functions etc get inlined. It's cheap enough.
651 : */
652 948 : llvm_mpm = LLVMCreatePassManager();
653 948 : LLVMPassManagerBuilderPopulateModulePassManager(llvm_pmb,
654 : llvm_mpm);
655 : /* always use always-inliner pass */
656 948 : if (!(context->base.flags & PGJIT_OPT3))
657 398 : LLVMAddAlwaysInlinerPass(llvm_mpm);
658 : /* if doing inlining, but no expensive optimization, add inlining pass */
659 948 : if (context->base.flags & PGJIT_INLINE
660 550 : && !(context->base.flags & PGJIT_OPT3))
661 0 : LLVMAddFunctionInliningPass(llvm_mpm);
662 948 : LLVMRunPassManager(llvm_mpm, context->module);
663 948 : LLVMDisposePassManager(llvm_mpm);
664 :
665 948 : LLVMPassManagerBuilderDispose(llvm_pmb);
666 : #else
667 : LLVMPassBuilderOptionsRef options;
668 : LLVMErrorRef err;
669 : const char *passes;
670 :
671 : if (context->base.flags & PGJIT_OPT3)
672 : passes = "default<O3>";
673 : else
674 : passes = "default<O0>,mem2reg";
675 :
676 : options = LLVMCreatePassBuilderOptions();
677 :
678 : #ifdef LLVM_PASS_DEBUG
679 : LLVMPassBuilderOptionsSetDebugLogging(options, 1);
680 : #endif
681 :
682 : /* In assertion builds, run the LLVM verify pass. */
683 : #ifdef USE_ASSERT_CHECKING
684 : LLVMPassBuilderOptionsSetVerifyEach(options, true);
685 : #endif
686 :
687 : LLVMPassBuilderOptionsSetInlinerThreshold(options, 512);
688 :
689 : err = LLVMRunPasses(module, passes, NULL, options);
690 :
691 : if (err)
692 : elog(ERROR, "failed to JIT module: %s", llvm_error_message(err));
693 :
694 : LLVMDisposePassBuilderOptions(options);
695 : #endif
696 948 : }
697 :
698 : /*
699 : * Emit code for the currently pending module.
700 : */
701 : static void
702 948 : llvm_compile_module(LLVMJitContext *context)
703 : {
704 : LLVMJitHandle *handle;
705 : MemoryContext oldcontext;
706 : instr_time starttime;
707 : instr_time endtime;
708 : LLVMOrcLLJITRef compile_orc;
709 :
710 948 : if (context->base.flags & PGJIT_OPT3)
711 550 : compile_orc = llvm_opt3_orc;
712 : else
713 398 : compile_orc = llvm_opt0_orc;
714 :
715 : /* perform inlining */
716 948 : if (context->base.flags & PGJIT_INLINE)
717 : {
718 550 : INSTR_TIME_SET_CURRENT(starttime);
719 550 : llvm_inline(context->module);
720 550 : INSTR_TIME_SET_CURRENT(endtime);
721 550 : INSTR_TIME_ACCUM_DIFF(context->base.instr.inlining_counter,
722 : endtime, starttime);
723 : }
724 :
725 948 : if (jit_dump_bitcode)
726 : {
727 : char *filename;
728 :
729 0 : filename = psprintf("%d.%zu.bc",
730 : MyProcPid,
731 : context->module_generation);
732 0 : LLVMWriteBitcodeToFile(context->module, filename);
733 0 : pfree(filename);
734 : }
735 :
736 :
737 : /* optimize according to the chosen optimization settings */
738 948 : INSTR_TIME_SET_CURRENT(starttime);
739 948 : llvm_optimize_module(context, context->module);
740 948 : INSTR_TIME_SET_CURRENT(endtime);
741 948 : INSTR_TIME_ACCUM_DIFF(context->base.instr.optimization_counter,
742 : endtime, starttime);
743 :
744 948 : if (jit_dump_bitcode)
745 : {
746 : char *filename;
747 :
748 0 : filename = psprintf("%d.%zu.optimized.bc",
749 : MyProcPid,
750 : context->module_generation);
751 0 : LLVMWriteBitcodeToFile(context->module, filename);
752 0 : pfree(filename);
753 : }
754 :
755 : handle = (LLVMJitHandle *)
756 948 : MemoryContextAlloc(TopMemoryContext, sizeof(LLVMJitHandle));
757 :
758 : /*
759 : * Emit the code. Note that this can, depending on the optimization
760 : * settings, take noticeable resources as code emission executes low-level
761 : * instruction combining/selection passes etc. Without optimization a
762 : * faster instruction selection mechanism is used.
763 : */
764 948 : INSTR_TIME_SET_CURRENT(starttime);
765 : {
766 : LLVMOrcThreadSafeModuleRef ts_module;
767 : LLVMErrorRef error;
768 948 : LLVMOrcJITDylibRef jd = LLVMOrcLLJITGetMainJITDylib(compile_orc);
769 :
770 948 : ts_module = LLVMOrcCreateNewThreadSafeModule(context->module, llvm_ts_context);
771 :
772 948 : handle->lljit = compile_orc;
773 948 : handle->resource_tracker = LLVMOrcJITDylibCreateResourceTracker(jd);
774 :
775 : /*
776 : * NB: This doesn't actually emit code. That happens lazily the first
777 : * time a symbol defined in the module is requested. Due to that
778 : * llvm_get_function() also accounts for emission time.
779 : */
780 :
781 948 : context->module = NULL; /* will be owned by LLJIT */
782 948 : error = LLVMOrcLLJITAddLLVMIRModuleWithRT(compile_orc,
783 : handle->resource_tracker,
784 : ts_module);
785 :
786 948 : if (error)
787 0 : elog(ERROR, "failed to JIT module: %s",
788 : llvm_error_message(error));
789 :
790 : /* LLVMOrcLLJITAddLLVMIRModuleWithRT takes ownership of the module */
791 : }
792 :
793 948 : INSTR_TIME_SET_CURRENT(endtime);
794 948 : INSTR_TIME_ACCUM_DIFF(context->base.instr.emission_counter,
795 : endtime, starttime);
796 :
797 948 : context->module = NULL;
798 948 : context->compiled = true;
799 :
800 : /* remember emitted code for cleanup and lookups */
801 948 : oldcontext = MemoryContextSwitchTo(TopMemoryContext);
802 948 : context->handles = lappend(context->handles, handle);
803 948 : MemoryContextSwitchTo(oldcontext);
804 :
805 948 : ereport(DEBUG1,
806 : (errmsg_internal("time to inline: %.3fs, opt: %.3fs, emit: %.3fs",
807 : INSTR_TIME_GET_DOUBLE(context->base.instr.inlining_counter),
808 : INSTR_TIME_GET_DOUBLE(context->base.instr.optimization_counter),
809 : INSTR_TIME_GET_DOUBLE(context->base.instr.emission_counter)),
810 : errhidestmt(true),
811 : errhidecontext(true)));
812 948 : }
813 :
814 : /*
815 : * Per session initialization.
816 : */
817 : static void
818 1216 : llvm_session_initialize(void)
819 : {
820 : MemoryContext oldcontext;
821 1216 : char *error = NULL;
822 1216 : char *cpu = NULL;
823 1216 : char *features = NULL;
824 : LLVMTargetMachineRef opt0_tm;
825 : LLVMTargetMachineRef opt3_tm;
826 :
827 1216 : if (llvm_session_initialized)
828 746 : return;
829 :
830 470 : oldcontext = MemoryContextSwitchTo(TopMemoryContext);
831 :
832 470 : LLVMInitializeNativeTarget();
833 470 : LLVMInitializeNativeAsmPrinter();
834 470 : LLVMInitializeNativeAsmParser();
835 :
836 470 : if (llvm_context == NULL)
837 : {
838 470 : llvm_context = LLVMContextCreate();
839 :
840 470 : llvm_jit_context_in_use_count = 0;
841 470 : llvm_llvm_context_reuse_count = 0;
842 : }
843 :
844 : /*
845 : * Synchronize types early, as that also includes inferring the target
846 : * triple.
847 : */
848 470 : llvm_create_types();
849 :
850 : /*
851 : * Extract target information from loaded module.
852 : */
853 470 : llvm_set_target();
854 :
855 470 : if (LLVMGetTargetFromTriple(llvm_triple, &llvm_targetref, &error) != 0)
856 : {
857 0 : elog(FATAL, "failed to query triple %s", error);
858 : }
859 :
860 : /*
861 : * We want the generated code to use all available features. Therefore
862 : * grab the host CPU string and detect features of the current CPU. The
863 : * latter is needed because some CPU architectures default to enabling
864 : * features not all CPUs have (weird, huh).
865 : */
866 470 : cpu = LLVMGetHostCPUName();
867 470 : features = LLVMGetHostCPUFeatures();
868 470 : elog(DEBUG2, "LLVMJIT detected CPU \"%s\", with features \"%s\"",
869 : cpu, features);
870 :
871 : opt0_tm =
872 470 : LLVMCreateTargetMachine(llvm_targetref, llvm_triple, cpu, features,
873 : LLVMCodeGenLevelNone,
874 : LLVMRelocDefault,
875 : LLVMCodeModelJITDefault);
876 : opt3_tm =
877 470 : LLVMCreateTargetMachine(llvm_targetref, llvm_triple, cpu, features,
878 : LLVMCodeGenLevelAggressive,
879 : LLVMRelocDefault,
880 : LLVMCodeModelJITDefault);
881 :
882 470 : LLVMDisposeMessage(cpu);
883 470 : cpu = NULL;
884 470 : LLVMDisposeMessage(features);
885 470 : features = NULL;
886 :
887 : /* force symbols in main binary to be loaded */
888 470 : LLVMLoadLibraryPermanently(NULL);
889 :
890 : {
891 470 : llvm_ts_context = LLVMOrcCreateNewThreadSafeContext();
892 :
893 470 : llvm_opt0_orc = llvm_create_jit_instance(opt0_tm);
894 470 : opt0_tm = 0;
895 :
896 470 : llvm_opt3_orc = llvm_create_jit_instance(opt3_tm);
897 470 : opt3_tm = 0;
898 : }
899 :
900 470 : on_proc_exit(llvm_shutdown, 0);
901 :
902 470 : llvm_session_initialized = true;
903 :
904 470 : MemoryContextSwitchTo(oldcontext);
905 : }
906 :
907 : static void
908 470 : llvm_shutdown(int code, Datum arg)
909 : {
910 : /*
911 : * If llvm_shutdown() is reached while in a fatal-on-oom section an error
912 : * has occurred in the middle of LLVM code. It is not safe to call back
913 : * into LLVM (which is why a FATAL error was thrown).
914 : *
915 : * We do need to shutdown LLVM in other shutdown cases, otherwise e.g.
916 : * profiling data won't be written out.
917 : */
918 470 : if (llvm_in_fatal_on_oom())
919 : {
920 : Assert(proc_exit_inprogress);
921 0 : return;
922 : }
923 :
924 470 : if (llvm_jit_context_in_use_count != 0)
925 0 : elog(PANIC, "LLVMJitContext in use count not 0 at exit (is %zu)",
926 : llvm_jit_context_in_use_count);
927 :
928 : {
929 470 : if (llvm_opt3_orc)
930 : {
931 470 : LLVMOrcDisposeLLJIT(llvm_opt3_orc);
932 470 : llvm_opt3_orc = NULL;
933 : }
934 470 : if (llvm_opt0_orc)
935 : {
936 470 : LLVMOrcDisposeLLJIT(llvm_opt0_orc);
937 470 : llvm_opt0_orc = NULL;
938 : }
939 470 : if (llvm_ts_context)
940 : {
941 470 : LLVMOrcDisposeThreadSafeContext(llvm_ts_context);
942 470 : llvm_ts_context = NULL;
943 : }
944 : }
945 : }
946 :
947 : /* helper for llvm_create_types, returning a function's return type */
948 : static LLVMTypeRef
949 470 : load_return_type(LLVMModuleRef mod, const char *name)
950 : {
951 : LLVMValueRef value;
952 : LLVMTypeRef typ;
953 :
954 : /* this'll return a *pointer* to the function */
955 470 : value = LLVMGetNamedFunction(mod, name);
956 470 : if (!value)
957 0 : elog(ERROR, "function %s is unknown", name);
958 :
959 470 : typ = LLVMGetFunctionReturnType(value); /* in llvmjit_wrap.cpp */
960 :
961 470 : return typ;
962 : }
963 :
964 : /*
965 : * Load triple & layout from clang emitted file so we're guaranteed to be
966 : * compatible.
967 : */
968 : static void
969 470 : llvm_set_target(void)
970 : {
971 470 : if (!llvm_types_module)
972 0 : elog(ERROR, "failed to extract target information, llvmjit_types.c not loaded");
973 :
974 470 : if (llvm_triple == NULL)
975 470 : llvm_triple = pstrdup(LLVMGetTarget(llvm_types_module));
976 :
977 470 : if (llvm_layout == NULL)
978 470 : llvm_layout = pstrdup(LLVMGetDataLayoutStr(llvm_types_module));
979 470 : }
980 :
981 : /*
982 : * Load required information, types, function signatures from llvmjit_types.c
983 : * and make them available in global variables.
984 : *
985 : * Those global variables are then used while emitting code.
986 : */
987 : static void
988 470 : llvm_create_types(void)
989 : {
990 : char path[MAXPGPATH];
991 : LLVMMemoryBufferRef buf;
992 : char *msg;
993 :
994 470 : snprintf(path, MAXPGPATH, "%s/%s", pkglib_path, "llvmjit_types.bc");
995 :
996 : /* open file */
997 470 : if (LLVMCreateMemoryBufferWithContentsOfFile(path, &buf, &msg))
998 : {
999 0 : elog(ERROR, "LLVMCreateMemoryBufferWithContentsOfFile(%s) failed: %s",
1000 : path, msg);
1001 : }
1002 :
1003 : /* eagerly load contents, going to need it all */
1004 470 : if (LLVMParseBitcodeInContext2(llvm_context, buf, &llvm_types_module))
1005 : {
1006 0 : elog(ERROR, "LLVMParseBitcodeInContext2 of %s failed", path);
1007 : }
1008 470 : LLVMDisposeMemoryBuffer(buf);
1009 :
1010 470 : TypeSizeT = llvm_pg_var_type("TypeSizeT");
1011 470 : TypeParamBool = load_return_type(llvm_types_module, "FunctionReturningBool");
1012 470 : TypeStorageBool = llvm_pg_var_type("TypeStorageBool");
1013 470 : TypePGFunction = llvm_pg_var_type("TypePGFunction");
1014 470 : StructNullableDatum = llvm_pg_var_type("StructNullableDatum");
1015 470 : StructExprContext = llvm_pg_var_type("StructExprContext");
1016 470 : StructExprEvalStep = llvm_pg_var_type("StructExprEvalStep");
1017 470 : StructExprState = llvm_pg_var_type("StructExprState");
1018 470 : StructFunctionCallInfoData = llvm_pg_var_type("StructFunctionCallInfoData");
1019 470 : StructMemoryContextData = llvm_pg_var_type("StructMemoryContextData");
1020 470 : StructTupleTableSlot = llvm_pg_var_type("StructTupleTableSlot");
1021 470 : StructHeapTupleTableSlot = llvm_pg_var_type("StructHeapTupleTableSlot");
1022 470 : StructMinimalTupleTableSlot = llvm_pg_var_type("StructMinimalTupleTableSlot");
1023 470 : StructHeapTupleData = llvm_pg_var_type("StructHeapTupleData");
1024 470 : StructHeapTupleHeaderData = llvm_pg_var_type("StructHeapTupleHeaderData");
1025 470 : StructTupleDescData = llvm_pg_var_type("StructTupleDescData");
1026 470 : StructAggState = llvm_pg_var_type("StructAggState");
1027 470 : StructAggStatePerGroupData = llvm_pg_var_type("StructAggStatePerGroupData");
1028 470 : StructAggStatePerTransData = llvm_pg_var_type("StructAggStatePerTransData");
1029 470 : StructPlanState = llvm_pg_var_type("StructPlanState");
1030 470 : StructMinimalTupleData = llvm_pg_var_type("StructMinimalTupleData");
1031 :
1032 470 : AttributeTemplate = LLVMGetNamedFunction(llvm_types_module, "AttributeTemplate");
1033 470 : ExecEvalSubroutineTemplate = LLVMGetNamedFunction(llvm_types_module, "ExecEvalSubroutineTemplate");
1034 470 : ExecEvalBoolSubroutineTemplate = LLVMGetNamedFunction(llvm_types_module, "ExecEvalBoolSubroutineTemplate");
1035 470 : }
1036 :
1037 : /*
1038 : * Split a symbol into module / function parts. If the function is in the
1039 : * main binary (or an external library) *modname will be NULL.
1040 : */
1041 : void
1042 16452 : llvm_split_symbol_name(const char *name, char **modname, char **funcname)
1043 : {
1044 16452 : *modname = NULL;
1045 16452 : *funcname = NULL;
1046 :
1047 : /*
1048 : * Module function names are pgextern.$module.$funcname
1049 : */
1050 16452 : if (strncmp(name, "pgextern.", strlen("pgextern.")) == 0)
1051 : {
1052 : /*
1053 : * Symbol names cannot contain a ., therefore we can split based on
1054 : * first and last occurrence of one.
1055 : */
1056 0 : *funcname = rindex(name, '.');
1057 0 : (*funcname)++; /* jump over . */
1058 :
1059 0 : *modname = pnstrdup(name + strlen("pgextern."),
1060 0 : *funcname - name - strlen("pgextern.") - 1);
1061 : Assert(funcname);
1062 :
1063 0 : *funcname = pstrdup(*funcname);
1064 : }
1065 : else
1066 : {
1067 16452 : *modname = NULL;
1068 16452 : *funcname = pstrdup(name);
1069 : }
1070 16452 : }
1071 :
1072 : /*
1073 : * Attempt to resolve symbol, so LLVM can emit a reference to it.
1074 : */
1075 : static uint64_t
1076 0 : llvm_resolve_symbol(const char *symname, void *ctx)
1077 : {
1078 : uintptr_t addr;
1079 : char *funcname;
1080 : char *modname;
1081 :
1082 : /*
1083 : * macOS prefixes all object level symbols with an underscore. But neither
1084 : * dlsym() nor PG's inliner expect that. So undo.
1085 : */
1086 : #if defined(__darwin__)
1087 : if (symname[0] != '_')
1088 : elog(ERROR, "expected prefixed symbol name, but got \"%s\"", symname);
1089 : symname++;
1090 : #endif
1091 :
1092 0 : llvm_split_symbol_name(symname, &modname, &funcname);
1093 :
1094 : /* functions that aren't resolved to names shouldn't ever get here */
1095 : Assert(funcname);
1096 :
1097 0 : if (modname)
1098 0 : addr = (uintptr_t) load_external_function(modname, funcname,
1099 : true, NULL);
1100 : else
1101 0 : addr = (uintptr_t) LLVMSearchForAddressOfSymbol(symname);
1102 :
1103 0 : pfree(funcname);
1104 0 : if (modname)
1105 0 : pfree(modname);
1106 :
1107 : /* let LLVM will error out - should never happen */
1108 0 : if (!addr)
1109 0 : elog(WARNING, "failed to resolve name %s", symname);
1110 :
1111 0 : return (uint64_t) addr;
1112 : }
1113 :
1114 : static LLVMErrorRef
1115 0 : llvm_resolve_symbols(LLVMOrcDefinitionGeneratorRef GeneratorObj, void *Ctx,
1116 : LLVMOrcLookupStateRef *LookupState, LLVMOrcLookupKind Kind,
1117 : LLVMOrcJITDylibRef JD, LLVMOrcJITDylibLookupFlags JDLookupFlags,
1118 : LLVMOrcCLookupSet LookupSet, size_t LookupSetSize)
1119 : {
1120 : #if LLVM_VERSION_MAJOR > 14
1121 0 : LLVMOrcCSymbolMapPairs symbols = palloc0(sizeof(LLVMOrcCSymbolMapPair) * LookupSetSize);
1122 : #else
1123 : LLVMOrcCSymbolMapPairs symbols = palloc0(sizeof(LLVMJITCSymbolMapPair) * LookupSetSize);
1124 : #endif
1125 : LLVMErrorRef error;
1126 : LLVMOrcMaterializationUnitRef mu;
1127 :
1128 0 : for (int i = 0; i < LookupSetSize; i++)
1129 : {
1130 0 : const char *name = LLVMOrcSymbolStringPoolEntryStr(LookupSet[i].Name);
1131 :
1132 0 : LLVMOrcRetainSymbolStringPoolEntry(LookupSet[i].Name);
1133 0 : symbols[i].Name = LookupSet[i].Name;
1134 0 : symbols[i].Sym.Address = llvm_resolve_symbol(name, NULL);
1135 0 : symbols[i].Sym.Flags.GenericFlags = LLVMJITSymbolGenericFlagsExported;
1136 : }
1137 :
1138 0 : mu = LLVMOrcAbsoluteSymbols(symbols, LookupSetSize);
1139 0 : error = LLVMOrcJITDylibDefine(JD, mu);
1140 0 : if (error != LLVMErrorSuccess)
1141 0 : LLVMOrcDisposeMaterializationUnit(mu);
1142 :
1143 0 : pfree(symbols);
1144 :
1145 0 : return error;
1146 : }
1147 :
1148 : /*
1149 : * We cannot throw errors through LLVM (without causing a FATAL at least), so
1150 : * just use WARNING here. That's OK anyway, as the error is also reported at
1151 : * the top level action (with less detail) and there might be multiple
1152 : * invocations of errors with details.
1153 : *
1154 : * This doesn't really happen during normal operation, but in cases like
1155 : * symbol resolution breakage. So just using elog(WARNING) is fine.
1156 : */
1157 : static void
1158 0 : llvm_log_jit_error(void *ctx, LLVMErrorRef error)
1159 : {
1160 0 : elog(WARNING, "error during JITing: %s",
1161 : llvm_error_message(error));
1162 0 : }
1163 :
1164 : /*
1165 : * Create our own object layer, so we can add event listeners.
1166 : */
1167 : static LLVMOrcObjectLayerRef
1168 940 : llvm_create_object_layer(void *Ctx, LLVMOrcExecutionSessionRef ES, const char *Triple)
1169 : {
1170 : #ifdef USE_LLVM_BACKPORT_SECTION_MEMORY_MANAGER
1171 : LLVMOrcObjectLayerRef objlayer =
1172 : LLVMOrcCreateRTDyldObjectLinkingLayerWithSafeSectionMemoryManager(ES);
1173 : #else
1174 : LLVMOrcObjectLayerRef objlayer =
1175 940 : LLVMOrcCreateRTDyldObjectLinkingLayerWithSectionMemoryManager(ES);
1176 : #endif
1177 :
1178 :
1179 : #if defined(HAVE_DECL_LLVMCREATEGDBREGISTRATIONLISTENER) && HAVE_DECL_LLVMCREATEGDBREGISTRATIONLISTENER
1180 940 : if (jit_debugging_support)
1181 : {
1182 0 : LLVMJITEventListenerRef l = LLVMCreateGDBRegistrationListener();
1183 :
1184 0 : LLVMOrcRTDyldObjectLinkingLayerRegisterJITEventListener(objlayer, l);
1185 : }
1186 : #endif
1187 :
1188 : #if defined(HAVE_DECL_LLVMCREATEPERFJITEVENTLISTENER) && HAVE_DECL_LLVMCREATEPERFJITEVENTLISTENER
1189 940 : if (jit_profiling_support)
1190 : {
1191 0 : LLVMJITEventListenerRef l = LLVMCreatePerfJITEventListener();
1192 :
1193 0 : LLVMOrcRTDyldObjectLinkingLayerRegisterJITEventListener(objlayer, l);
1194 : }
1195 : #endif
1196 :
1197 940 : return objlayer;
1198 : }
1199 :
1200 : /*
1201 : * Create LLJIT instance, using the passed in target machine. Note that the
1202 : * target machine afterwards is owned by the LLJIT instance.
1203 : */
1204 : static LLVMOrcLLJITRef
1205 940 : llvm_create_jit_instance(LLVMTargetMachineRef tm)
1206 : {
1207 : LLVMOrcLLJITRef lljit;
1208 : LLVMOrcJITTargetMachineBuilderRef tm_builder;
1209 : LLVMOrcLLJITBuilderRef lljit_builder;
1210 : LLVMErrorRef error;
1211 : LLVMOrcDefinitionGeneratorRef main_gen;
1212 : LLVMOrcDefinitionGeneratorRef ref_gen;
1213 :
1214 940 : lljit_builder = LLVMOrcCreateLLJITBuilder();
1215 940 : tm_builder = LLVMOrcJITTargetMachineBuilderCreateFromTargetMachine(tm);
1216 940 : LLVMOrcLLJITBuilderSetJITTargetMachineBuilder(lljit_builder, tm_builder);
1217 :
1218 940 : LLVMOrcLLJITBuilderSetObjectLinkingLayerCreator(lljit_builder,
1219 : llvm_create_object_layer,
1220 : NULL);
1221 :
1222 940 : error = LLVMOrcCreateLLJIT(&lljit, lljit_builder);
1223 940 : if (error)
1224 0 : elog(ERROR, "failed to create lljit instance: %s",
1225 : llvm_error_message(error));
1226 :
1227 940 : LLVMOrcExecutionSessionSetErrorReporter(LLVMOrcLLJITGetExecutionSession(lljit),
1228 : llvm_log_jit_error, NULL);
1229 :
1230 : /*
1231 : * Symbol resolution support for symbols in the postgres binary /
1232 : * libraries already loaded.
1233 : */
1234 940 : error = LLVMOrcCreateDynamicLibrarySearchGeneratorForProcess(&main_gen,
1235 940 : LLVMOrcLLJITGetGlobalPrefix(lljit),
1236 : 0, NULL);
1237 940 : if (error)
1238 0 : elog(ERROR, "failed to create generator: %s",
1239 : llvm_error_message(error));
1240 940 : LLVMOrcJITDylibAddGenerator(LLVMOrcLLJITGetMainJITDylib(lljit), main_gen);
1241 :
1242 : /*
1243 : * Symbol resolution support for "special" functions, e.g. a call into an
1244 : * SQL callable function.
1245 : */
1246 : #if LLVM_VERSION_MAJOR > 14
1247 940 : ref_gen = LLVMOrcCreateCustomCAPIDefinitionGenerator(llvm_resolve_symbols, NULL, NULL);
1248 : #else
1249 : ref_gen = LLVMOrcCreateCustomCAPIDefinitionGenerator(llvm_resolve_symbols, NULL);
1250 : #endif
1251 940 : LLVMOrcJITDylibAddGenerator(LLVMOrcLLJITGetMainJITDylib(lljit), ref_gen);
1252 :
1253 940 : return lljit;
1254 : }
1255 :
1256 : static char *
1257 0 : llvm_error_message(LLVMErrorRef error)
1258 : {
1259 0 : char *orig = LLVMGetErrorMessage(error);
1260 0 : char *msg = pstrdup(orig);
1261 :
1262 0 : LLVMDisposeErrorMessage(orig);
1263 :
1264 0 : return msg;
1265 : }
1266 :
1267 : /*
1268 : * ResourceOwner callbacks
1269 : */
1270 : static void
1271 16 : ResOwnerReleaseJitContext(Datum res)
1272 : {
1273 16 : LLVMJitContext *context = (LLVMJitContext *) DatumGetPointer(res);
1274 :
1275 16 : context->resowner = NULL;
1276 16 : jit_release_context(&context->base);
1277 16 : }
|