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