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