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