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