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 1218 : ResourceOwnerRememberJIT(ResourceOwner owner, LLVMJitContext *handle)
132 : {
133 1218 : ResourceOwnerRemember(owner, PointerGetDatum(handle), &jit_resowner_desc);
134 1218 : }
135 : static inline void
136 1202 : ResourceOwnerForgetJIT(ResourceOwner owner, LLVMJitContext *handle)
137 : {
138 1202 : ResourceOwnerForget(owner, PointerGetDatum(handle), &jit_resowner_desc);
139 1202 : }
140 :
141 1958 : PG_MODULE_MAGIC_EXT(
142 : .name = "llvmjit",
143 : .version = PG_VERSION
144 : );
145 :
146 :
147 : /*
148 : * Initialize LLVM JIT provider.
149 : */
150 : void
151 472 : _PG_jit_provider_init(JitProviderCallbacks *cb)
152 : {
153 472 : cb->reset_after_error = llvm_reset_after_error;
154 472 : cb->release_context = llvm_release_context;
155 472 : cb->compile_expr = llvm_compile_expr;
156 472 : }
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 1218 : llvm_recreate_llvm_context(void)
174 : {
175 1218 : 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 1218 : if (llvm_jit_context_in_use_count > 0)
183 : {
184 0 : llvm_llvm_context_reuse_count++;
185 0 : return;
186 : }
187 :
188 1218 : if (llvm_llvm_context_reuse_count <= LLVMJIT_LLVM_CONTEXT_REUSE_MAX)
189 : {
190 1218 : llvm_llvm_context_reuse_count++;
191 1218 : 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 1218 : llvm_create_context(int jitFlags)
224 : {
225 : LLVMJitContext *context;
226 :
227 1218 : llvm_assert_in_fatal_section();
228 :
229 1218 : llvm_session_initialize();
230 :
231 1218 : llvm_recreate_llvm_context();
232 :
233 1218 : ResourceOwnerEnlarge(CurrentResourceOwner);
234 :
235 1218 : context = MemoryContextAllocZero(TopMemoryContext,
236 : sizeof(LLVMJitContext));
237 1218 : context->base.flags = jitFlags;
238 :
239 : /* ensure cleanup */
240 1218 : context->resowner = CurrentResourceOwner;
241 1218 : ResourceOwnerRememberJIT(CurrentResourceOwner, context);
242 :
243 1218 : llvm_jit_context_in_use_count++;
244 :
245 1218 : return context;
246 : }
247 :
248 : /*
249 : * Release resources required by one llvm context.
250 : */
251 : static void
252 1218 : llvm_release_context(JitContext *context)
253 : {
254 1218 : 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 1218 : 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 1218 : if (proc_exit_inprogress)
269 0 : return;
270 :
271 1218 : llvm_enter_fatal_on_oom();
272 :
273 1218 : if (llvm_jit_context->module)
274 : {
275 348 : LLVMDisposeModule(llvm_jit_context->module);
276 348 : llvm_jit_context->module = NULL;
277 : }
278 :
279 2172 : foreach(lc, llvm_jit_context->handles)
280 : {
281 954 : LLVMJitHandle *jit_handle = (LLVMJitHandle *) lfirst(lc);
282 :
283 : {
284 : LLVMOrcExecutionSessionRef ee;
285 : LLVMOrcSymbolStringPoolRef sp;
286 :
287 954 : LLVMOrcResourceTrackerRemove(jit_handle->resource_tracker);
288 954 : 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 954 : ee = LLVMOrcLLJITGetExecutionSession(jit_handle->lljit);
297 954 : sp = LLVMOrcExecutionSessionGetSymbolStringPool(ee);
298 954 : LLVMOrcSymbolStringPoolClearDeadEntries(sp);
299 : }
300 :
301 954 : pfree(jit_handle);
302 : }
303 1218 : list_free(llvm_jit_context->handles);
304 1218 : llvm_jit_context->handles = NIL;
305 :
306 1218 : llvm_leave_fatal_on_oom();
307 :
308 1218 : if (llvm_jit_context->resowner)
309 1202 : 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 14262 : llvm_mutable_module(LLVMJitContext *context)
317 : {
318 14262 : llvm_assert_in_fatal_section();
319 :
320 : /*
321 : * If there's no in-progress module, create a new one.
322 : */
323 14262 : if (!context->module)
324 : {
325 1302 : context->compiled = false;
326 1302 : context->module_generation = llvm_generation++;
327 1302 : context->module = LLVMModuleCreateWithNameInContext("pg", llvm_context);
328 1302 : LLVMSetTarget(context->module, llvm_triple);
329 1302 : LLVMSetDataLayout(context->module, llvm_layout);
330 : }
331 :
332 14262 : 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 14262 : llvm_expand_funcname(struct LLVMJitContext *context, const char *basename)
342 : {
343 : Assert(context->module != NULL);
344 :
345 14262 : 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 28524 : return psprintf("%s_%zu_%d",
352 : basename,
353 : context->module_generation,
354 14262 : 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 5286 : llvm_get_function(LLVMJitContext *context, const char *funcname)
363 : {
364 : ListCell *lc;
365 :
366 5286 : 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 5286 : if (!context->compiled)
373 : {
374 954 : 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 5286 : foreach(lc, context->handles)
383 : {
384 5286 : LLVMJitHandle *handle = (LLVMJitHandle *) lfirst(lc);
385 : instr_time starttime;
386 : instr_time endtime;
387 : LLVMErrorRef error;
388 : LLVMOrcJITTargetAddress addr;
389 :
390 5286 : INSTR_TIME_SET_CURRENT(starttime);
391 :
392 5286 : addr = 0;
393 5286 : error = LLVMOrcLLJITLookup(handle->lljit, &addr, funcname);
394 5286 : 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 5286 : INSTR_TIME_SET_CURRENT(endtime);
405 5286 : INSTR_TIME_ACCUM_DIFF(context->base.instr.emission_counter,
406 : endtime, starttime);
407 :
408 5286 : if (addr)
409 5286 : 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 9500 : 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 9500 : v_srcvar = LLVMGetNamedGlobal(llvm_types_module, varname);
429 9500 : if (!v_srcvar)
430 0 : elog(ERROR, "variable %s not in llvmjit_types.c", varname);
431 :
432 9500 : typ = LLVMGlobalGetValueType(v_srcvar);
433 :
434 9500 : 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 12150 : llvm_pg_var_func_type(const char *varname)
443 : {
444 : LLVMValueRef v_srcvar;
445 : LLVMTypeRef typ;
446 :
447 12150 : v_srcvar = LLVMGetNamedFunction(llvm_types_module, varname);
448 12150 : if (!v_srcvar)
449 0 : elog(ERROR, "function %s not in llvmjit_types.c", varname);
450 :
451 12150 : typ = LLVMGetFunctionType(v_srcvar);
452 :
453 12150 : 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 12284 : 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 12284 : v_fn = LLVMGetNamedFunction(mod, funcname);
471 12284 : if (v_fn)
472 9090 : return v_fn;
473 :
474 3194 : v_srcfn = LLVMGetNamedFunction(llvm_types_module, funcname);
475 :
476 3194 : if (!v_srcfn)
477 0 : elog(ERROR, "function %s not in llvmjit_types.c", funcname);
478 :
479 3194 : v_fn = LLVMAddFunction(mod,
480 : funcname,
481 : LLVMGetFunctionType(v_srcfn));
482 3194 : llvm_copy_attributes(v_srcfn, v_fn);
483 :
484 3194 : 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 49328 : llvm_copy_attributes_at_index(LLVMValueRef v_from, LLVMValueRef v_to, uint32 index)
493 : {
494 : int num_attributes;
495 : LLVMAttributeRef *attrs;
496 :
497 49328 : num_attributes = LLVMGetAttributeCountAtIndex(v_from, index);
498 :
499 49328 : if (num_attributes == 0)
500 17538 : return;
501 :
502 31790 : attrs = palloc(sizeof(LLVMAttributeRef) * num_attributes);
503 31790 : LLVMGetAttributesAtIndex(v_from, index, attrs);
504 :
505 372886 : for (int attno = 0; attno < num_attributes; attno++)
506 341096 : LLVMAddAttributeAtIndex(v_to, index, attrs[attno]);
507 :
508 31790 : 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 17456 : llvm_copy_attributes(LLVMValueRef v_from, LLVMValueRef v_to)
517 : {
518 : uint32 param_count;
519 :
520 : /* copy function attributes */
521 17456 : llvm_copy_attributes_at_index(v_from, v_to, LLVMAttributeFunctionIndex);
522 :
523 17456 : if (LLVMGetTypeKind(LLVMGetFunctionReturnType(v_to)) != LLVMVoidTypeKind)
524 : {
525 : /* and the return value attributes */
526 9396 : llvm_copy_attributes_at_index(v_from, v_to, LLVMAttributeReturnIndex);
527 : }
528 :
529 : /* and each function parameter's attribute */
530 17456 : param_count = LLVMCountParams(v_from);
531 :
532 39932 : for (int paramidx = 1; paramidx <= param_count; paramidx++)
533 22476 : llvm_copy_attributes_at_index(v_from, v_to, paramidx);
534 17456 : }
535 :
536 : /*
537 : * Return a callable LLVMValueRef for fcinfo.
538 : */
539 : LLVMValueRef
540 6398 : 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 6398 : fmgr_symbol(fcinfo->flinfo->fn_oid, &modname, &basename);
552 :
553 6398 : if (modname != NULL && basename != NULL)
554 : {
555 : /* external function in loadable library */
556 0 : funcname = psprintf("pgextern.%s.%s", modname, basename);
557 : }
558 6398 : else if (basename != NULL)
559 : {
560 : /* internal function */
561 6386 : 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 6386 : v_fn = LLVMGetNamedFunction(mod, funcname);
591 6386 : if (v_fn != 0)
592 3244 : return v_fn;
593 :
594 3142 : v_fn = LLVMAddFunction(mod, funcname, LLVMGetFunctionType(AttributeTemplate));
595 :
596 3142 : return v_fn;
597 : }
598 :
599 : /*
600 : * Optimize code in module using the flags set in context.
601 : */
602 : static void
603 954 : 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 954 : if (context->base.flags & PGJIT_OPT3)
613 548 : compile_optlevel = 3;
614 : else
615 406 : 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 954 : llvm_pmb = LLVMPassManagerBuilderCreate();
623 954 : LLVMPassManagerBuilderSetOptLevel(llvm_pmb, compile_optlevel);
624 954 : llvm_fpm = LLVMCreateFunctionPassManagerForModule(module);
625 :
626 954 : if (context->base.flags & PGJIT_OPT3)
627 : {
628 : /* TODO: Unscientifically determined threshold */
629 548 : LLVMPassManagerBuilderUseInlinerWithThreshold(llvm_pmb, 512);
630 : }
631 : else
632 : {
633 : /* we rely on mem2reg heavily, so emit even in the O0 case */
634 406 : LLVMAddPromoteMemoryToRegisterPass(llvm_fpm);
635 : }
636 :
637 954 : 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 954 : LLVMInitializeFunctionPassManager(llvm_fpm);
644 23450 : for (func = LLVMGetFirstFunction(context->module);
645 : func != NULL;
646 22496 : func = LLVMGetNextFunction(func))
647 22496 : LLVMRunFunctionPassManager(llvm_fpm, func);
648 954 : LLVMFinalizeFunctionPassManager(llvm_fpm);
649 954 : 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 954 : llvm_mpm = LLVMCreatePassManager();
656 954 : LLVMPassManagerBuilderPopulateModulePassManager(llvm_pmb,
657 : llvm_mpm);
658 : /* always use always-inliner pass */
659 954 : if (!(context->base.flags & PGJIT_OPT3))
660 406 : LLVMAddAlwaysInlinerPass(llvm_mpm);
661 : /* if doing inlining, but no expensive optimization, add inlining pass */
662 954 : if (context->base.flags & PGJIT_INLINE
663 548 : && !(context->base.flags & PGJIT_OPT3))
664 0 : LLVMAddFunctionInliningPass(llvm_mpm);
665 954 : LLVMRunPassManager(llvm_mpm, context->module);
666 954 : LLVMDisposePassManager(llvm_mpm);
667 :
668 954 : 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 954 : }
700 :
701 : /*
702 : * Emit code for the currently pending module.
703 : */
704 : static void
705 954 : 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 954 : if (context->base.flags & PGJIT_OPT3)
714 548 : compile_orc = llvm_opt3_orc;
715 : else
716 406 : compile_orc = llvm_opt0_orc;
717 :
718 : /* perform inlining */
719 954 : if (context->base.flags & PGJIT_INLINE)
720 : {
721 548 : INSTR_TIME_SET_CURRENT(starttime);
722 548 : llvm_inline(context->module);
723 548 : INSTR_TIME_SET_CURRENT(endtime);
724 548 : INSTR_TIME_ACCUM_DIFF(context->base.instr.inlining_counter,
725 : endtime, starttime);
726 : }
727 :
728 954 : 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 954 : INSTR_TIME_SET_CURRENT(starttime);
742 954 : llvm_optimize_module(context, context->module);
743 954 : INSTR_TIME_SET_CURRENT(endtime);
744 954 : INSTR_TIME_ACCUM_DIFF(context->base.instr.optimization_counter,
745 : endtime, starttime);
746 :
747 954 : 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 954 : 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 954 : INSTR_TIME_SET_CURRENT(starttime);
768 : {
769 : LLVMOrcThreadSafeModuleRef ts_module;
770 : LLVMErrorRef error;
771 954 : LLVMOrcJITDylibRef jd = LLVMOrcLLJITGetMainJITDylib(compile_orc);
772 :
773 954 : ts_module = LLVMOrcCreateNewThreadSafeModule(context->module, llvm_ts_context);
774 :
775 954 : handle->lljit = compile_orc;
776 954 : 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 954 : context->module = NULL; /* will be owned by LLJIT */
785 954 : error = LLVMOrcLLJITAddLLVMIRModuleWithRT(compile_orc,
786 : handle->resource_tracker,
787 : ts_module);
788 :
789 954 : 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 954 : INSTR_TIME_SET_CURRENT(endtime);
797 954 : INSTR_TIME_ACCUM_DIFF(context->base.instr.emission_counter,
798 : endtime, starttime);
799 :
800 954 : context->module = NULL;
801 954 : context->compiled = true;
802 :
803 : /* remember emitted code for cleanup and lookups */
804 954 : oldcontext = MemoryContextSwitchTo(TopMemoryContext);
805 954 : context->handles = lappend(context->handles, handle);
806 954 : MemoryContextSwitchTo(oldcontext);
807 :
808 954 : 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 954 : }
816 :
817 : /*
818 : * Per session initialization.
819 : */
820 : static void
821 1218 : llvm_session_initialize(void)
822 : {
823 : MemoryContext oldcontext;
824 1218 : char *error = NULL;
825 1218 : char *cpu = NULL;
826 1218 : char *features = NULL;
827 : LLVMTargetMachineRef opt0_tm;
828 : LLVMTargetMachineRef opt3_tm;
829 :
830 1218 : if (llvm_session_initialized)
831 746 : return;
832 :
833 472 : oldcontext = MemoryContextSwitchTo(TopMemoryContext);
834 :
835 472 : LLVMInitializeNativeTarget();
836 472 : LLVMInitializeNativeAsmPrinter();
837 472 : LLVMInitializeNativeAsmParser();
838 :
839 472 : if (llvm_context == NULL)
840 : {
841 472 : llvm_context = LLVMContextCreate();
842 :
843 472 : llvm_jit_context_in_use_count = 0;
844 472 : llvm_llvm_context_reuse_count = 0;
845 : }
846 :
847 : /*
848 : * Synchronize types early, as that also includes inferring the target
849 : * triple.
850 : */
851 472 : llvm_create_types();
852 :
853 : /*
854 : * Extract target information from loaded module.
855 : */
856 472 : llvm_set_target();
857 :
858 472 : 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 472 : cpu = LLVMGetHostCPUName();
870 472 : features = LLVMGetHostCPUFeatures();
871 472 : elog(DEBUG2, "LLVMJIT detected CPU \"%s\", with features \"%s\"",
872 : cpu, features);
873 :
874 : opt0_tm =
875 472 : LLVMCreateTargetMachine(llvm_targetref, llvm_triple, cpu, features,
876 : LLVMCodeGenLevelNone,
877 : LLVMRelocDefault,
878 : LLVMCodeModelJITDefault);
879 : opt3_tm =
880 472 : LLVMCreateTargetMachine(llvm_targetref, llvm_triple, cpu, features,
881 : LLVMCodeGenLevelAggressive,
882 : LLVMRelocDefault,
883 : LLVMCodeModelJITDefault);
884 :
885 472 : LLVMDisposeMessage(cpu);
886 472 : cpu = NULL;
887 472 : LLVMDisposeMessage(features);
888 472 : features = NULL;
889 :
890 : /* force symbols in main binary to be loaded */
891 472 : LLVMLoadLibraryPermanently(NULL);
892 :
893 : {
894 472 : llvm_ts_context = LLVMOrcCreateNewThreadSafeContext();
895 :
896 472 : llvm_opt0_orc = llvm_create_jit_instance(opt0_tm);
897 472 : opt0_tm = 0;
898 :
899 472 : llvm_opt3_orc = llvm_create_jit_instance(opt3_tm);
900 472 : opt3_tm = 0;
901 : }
902 :
903 472 : on_proc_exit(llvm_shutdown, 0);
904 :
905 472 : llvm_session_initialized = true;
906 :
907 472 : MemoryContextSwitchTo(oldcontext);
908 : }
909 :
910 : static void
911 472 : 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 472 : if (llvm_in_fatal_on_oom())
922 : {
923 : Assert(proc_exit_inprogress);
924 0 : return;
925 : }
926 :
927 472 : 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 472 : if (llvm_opt3_orc)
933 : {
934 472 : LLVMOrcDisposeLLJIT(llvm_opt3_orc);
935 472 : llvm_opt3_orc = NULL;
936 : }
937 472 : if (llvm_opt0_orc)
938 : {
939 472 : LLVMOrcDisposeLLJIT(llvm_opt0_orc);
940 472 : llvm_opt0_orc = NULL;
941 : }
942 472 : if (llvm_ts_context)
943 : {
944 472 : LLVMOrcDisposeThreadSafeContext(llvm_ts_context);
945 472 : llvm_ts_context = NULL;
946 : }
947 : }
948 : }
949 :
950 : /* helper for llvm_create_types, returning a function's return type */
951 : static LLVMTypeRef
952 472 : 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 472 : value = LLVMGetNamedFunction(mod, name);
959 472 : if (!value)
960 0 : elog(ERROR, "function %s is unknown", name);
961 :
962 472 : typ = LLVMGetFunctionReturnType(value); /* in llvmjit_wrap.cpp */
963 :
964 472 : 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 472 : llvm_set_target(void)
973 : {
974 472 : if (!llvm_types_module)
975 0 : elog(ERROR, "failed to extract target information, llvmjit_types.c not loaded");
976 :
977 472 : if (llvm_triple == NULL)
978 472 : llvm_triple = pstrdup(LLVMGetTarget(llvm_types_module));
979 :
980 472 : if (llvm_layout == NULL)
981 472 : llvm_layout = pstrdup(LLVMGetDataLayoutStr(llvm_types_module));
982 472 : }
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 472 : llvm_create_types(void)
992 : {
993 : char path[MAXPGPATH];
994 : LLVMMemoryBufferRef buf;
995 : char *msg;
996 :
997 472 : snprintf(path, MAXPGPATH, "%s/%s", pkglib_path, "llvmjit_types.bc");
998 :
999 : /* open file */
1000 472 : 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 472 : if (LLVMParseBitcodeInContext2(llvm_context, buf, &llvm_types_module))
1008 : {
1009 0 : elog(ERROR, "LLVMParseBitcodeInContext2 of %s failed", path);
1010 : }
1011 472 : LLVMDisposeMemoryBuffer(buf);
1012 :
1013 472 : TypeSizeT = llvm_pg_var_type("TypeSizeT");
1014 472 : TypeParamBool = load_return_type(llvm_types_module, "FunctionReturningBool");
1015 472 : TypeStorageBool = llvm_pg_var_type("TypeStorageBool");
1016 472 : TypePGFunction = llvm_pg_var_type("TypePGFunction");
1017 472 : StructNullableDatum = llvm_pg_var_type("StructNullableDatum");
1018 472 : StructExprContext = llvm_pg_var_type("StructExprContext");
1019 472 : StructExprEvalStep = llvm_pg_var_type("StructExprEvalStep");
1020 472 : StructExprState = llvm_pg_var_type("StructExprState");
1021 472 : StructFunctionCallInfoData = llvm_pg_var_type("StructFunctionCallInfoData");
1022 472 : StructMemoryContextData = llvm_pg_var_type("StructMemoryContextData");
1023 472 : StructTupleTableSlot = llvm_pg_var_type("StructTupleTableSlot");
1024 472 : StructHeapTupleTableSlot = llvm_pg_var_type("StructHeapTupleTableSlot");
1025 472 : StructMinimalTupleTableSlot = llvm_pg_var_type("StructMinimalTupleTableSlot");
1026 472 : StructHeapTupleData = llvm_pg_var_type("StructHeapTupleData");
1027 472 : StructHeapTupleHeaderData = llvm_pg_var_type("StructHeapTupleHeaderData");
1028 472 : StructTupleDescData = llvm_pg_var_type("StructTupleDescData");
1029 472 : StructAggState = llvm_pg_var_type("StructAggState");
1030 472 : StructAggStatePerGroupData = llvm_pg_var_type("StructAggStatePerGroupData");
1031 472 : StructAggStatePerTransData = llvm_pg_var_type("StructAggStatePerTransData");
1032 472 : StructPlanState = llvm_pg_var_type("StructPlanState");
1033 472 : StructMinimalTupleData = llvm_pg_var_type("StructMinimalTupleData");
1034 :
1035 472 : AttributeTemplate = LLVMGetNamedFunction(llvm_types_module, "AttributeTemplate");
1036 472 : ExecEvalSubroutineTemplate = LLVMGetNamedFunction(llvm_types_module, "ExecEvalSubroutineTemplate");
1037 472 : ExecEvalBoolSubroutineTemplate = LLVMGetNamedFunction(llvm_types_module, "ExecEvalBoolSubroutineTemplate");
1038 472 : }
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 16506 : llvm_split_symbol_name(const char *name, char **modname, char **funcname)
1046 : {
1047 16506 : *modname = NULL;
1048 16506 : *funcname = NULL;
1049 :
1050 : /*
1051 : * Module function names are pgextern.$module.$funcname
1052 : */
1053 16506 : 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 16506 : *modname = NULL;
1071 16506 : *funcname = pstrdup(name);
1072 : }
1073 16506 : }
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 944 : 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 944 : LLVMOrcCreateRTDyldObjectLinkingLayerWithSectionMemoryManager(ES);
1179 : #endif
1180 :
1181 :
1182 : #if defined(HAVE_DECL_LLVMCREATEGDBREGISTRATIONLISTENER) && HAVE_DECL_LLVMCREATEGDBREGISTRATIONLISTENER
1183 944 : 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 944 : if (jit_profiling_support)
1193 : {
1194 0 : LLVMJITEventListenerRef l = LLVMCreatePerfJITEventListener();
1195 :
1196 0 : LLVMOrcRTDyldObjectLinkingLayerRegisterJITEventListener(objlayer, l);
1197 : }
1198 : #endif
1199 :
1200 944 : 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 944 : 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 944 : lljit_builder = LLVMOrcCreateLLJITBuilder();
1218 944 : tm_builder = LLVMOrcJITTargetMachineBuilderCreateFromTargetMachine(tm);
1219 944 : LLVMOrcLLJITBuilderSetJITTargetMachineBuilder(lljit_builder, tm_builder);
1220 :
1221 944 : LLVMOrcLLJITBuilderSetObjectLinkingLayerCreator(lljit_builder,
1222 : llvm_create_object_layer,
1223 : NULL);
1224 :
1225 944 : error = LLVMOrcCreateLLJIT(&lljit, lljit_builder);
1226 944 : if (error)
1227 0 : elog(ERROR, "failed to create lljit instance: %s",
1228 : llvm_error_message(error));
1229 :
1230 944 : 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 944 : error = LLVMOrcCreateDynamicLibrarySearchGeneratorForProcess(&main_gen,
1238 944 : LLVMOrcLLJITGetGlobalPrefix(lljit),
1239 : 0, NULL);
1240 944 : if (error)
1241 0 : elog(ERROR, "failed to create generator: %s",
1242 : llvm_error_message(error));
1243 944 : 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 944 : ref_gen = LLVMOrcCreateCustomCAPIDefinitionGenerator(llvm_resolve_symbols, NULL, NULL);
1251 : #else
1252 : ref_gen = LLVMOrcCreateCustomCAPIDefinitionGenerator(llvm_resolve_symbols, NULL);
1253 : #endif
1254 944 : LLVMOrcJITDylibAddGenerator(LLVMOrcLLJITGetMainJITDylib(lljit), ref_gen);
1255 :
1256 944 : 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 : }
|