Branch data Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * llvmjit.c
4 : : * Core part of the LLVM JIT provider.
5 : : *
6 : : * Copyright (c) 2016-2026, PostgreSQL Global Development Group
7 : : *
8 : : * IDENTIFICATION
9 : : * src/backend/jit/llvm/llvmjit.c
10 : : *
11 : : *-------------------------------------------------------------------------
12 : : */
13 : :
14 : : #include "postgres.h"
15 : :
16 : : #include <llvm-c/Analysis.h>
17 : : #include <llvm-c/BitReader.h>
18 : : #include <llvm-c/BitWriter.h>
19 : : #include <llvm-c/Core.h>
20 : : #include <llvm-c/ExecutionEngine.h>
21 : : #if LLVM_VERSION_MAJOR > 16
22 : : #include <llvm-c/Transforms/PassBuilder.h>
23 : : #endif
24 : : #include <llvm-c/Orc.h>
25 : : #include <llvm-c/OrcEE.h>
26 : : #include <llvm-c/LLJIT.h>
27 : : #include <llvm-c/Support.h>
28 : : #include <llvm-c/Target.h>
29 : : #if LLVM_VERSION_MAJOR < 17
30 : : #include <llvm-c/Transforms/IPO.h>
31 : : #include <llvm-c/Transforms/PassManagerBuilder.h>
32 : : #include <llvm-c/Transforms/Scalar.h>
33 : : #include <llvm-c/Transforms/Utils.h>
34 : : #endif
35 : :
36 : : #include "jit/llvmjit.h"
37 : : #include "jit/llvmjit_backport.h"
38 : : #include "jit/llvmjit_emit.h"
39 : : #include "miscadmin.h"
40 : : #include "portability/instr_time.h"
41 : : #include "storage/ipc.h"
42 : : #include "utils/memutils.h"
43 : : #include "utils/resowner.h"
44 : :
45 : : #define LLVMJIT_LLVM_CONTEXT_REUSE_MAX 100
46 : :
47 : : /* Handle of a module emitted via ORC JIT */
48 : : typedef struct LLVMJitHandle
49 : : {
50 : : LLVMOrcLLJITRef lljit;
51 : : LLVMOrcResourceTrackerRef resource_tracker;
52 : : } LLVMJitHandle;
53 : :
54 : :
55 : : /* types & functions commonly needed for JITing */
56 : : LLVMTypeRef TypeSizeT;
57 : : LLVMTypeRef TypeDatum;
58 : : LLVMTypeRef TypeParamBool;
59 : : LLVMTypeRef TypeStorageBool;
60 : : LLVMTypeRef TypePGFunction;
61 : : LLVMTypeRef StructNullableDatum;
62 : : LLVMTypeRef StructHeapTupleData;
63 : : LLVMTypeRef StructMinimalTupleData;
64 : : LLVMTypeRef StructTupleDescData;
65 : : LLVMTypeRef StructTupleTableSlot;
66 : : LLVMTypeRef StructHeapTupleHeaderData;
67 : : LLVMTypeRef StructHeapTupleTableSlot;
68 : : LLVMTypeRef StructMinimalTupleTableSlot;
69 : : LLVMTypeRef StructMemoryContextData;
70 : : LLVMTypeRef StructFunctionCallInfoData;
71 : : LLVMTypeRef StructExprContext;
72 : : LLVMTypeRef StructExprEvalStep;
73 : : LLVMTypeRef StructExprState;
74 : : LLVMTypeRef StructAggState;
75 : : LLVMTypeRef StructAggStatePerGroupData;
76 : : LLVMTypeRef StructAggStatePerTransData;
77 : : LLVMTypeRef StructPlanState;
78 : :
79 : : LLVMValueRef AttributeTemplate;
80 : : LLVMValueRef ExecEvalSubroutineTemplate;
81 : : LLVMValueRef ExecEvalBoolSubroutineTemplate;
82 : :
83 : : static LLVMModuleRef llvm_types_module = NULL;
84 : :
85 : : static bool llvm_session_initialized = false;
86 : : static size_t llvm_generation = 0;
87 : :
88 : : /* number of LLVMJitContexts that currently are in use */
89 : : static size_t llvm_jit_context_in_use_count = 0;
90 : :
91 : : /* how many times has the current LLVMContextRef been used */
92 : : static size_t llvm_llvm_context_reuse_count = 0;
93 : : static const char *llvm_triple = NULL;
94 : : static const char *llvm_layout = NULL;
95 : : static LLVMContextRef llvm_context;
96 : :
97 : :
98 : : static LLVMTargetRef llvm_targetref;
99 : : static LLVMOrcThreadSafeContextRef llvm_ts_context;
100 : : static LLVMOrcLLJITRef llvm_opt0_orc;
101 : : static LLVMOrcLLJITRef llvm_opt3_orc;
102 : :
103 : :
104 : : static void llvm_release_context(JitContext *context);
105 : : static void llvm_session_initialize(void);
106 : : static void llvm_shutdown(int code, Datum arg);
107 : : static void llvm_compile_module(LLVMJitContext *context);
108 : : static void llvm_optimize_module(LLVMJitContext *context, LLVMModuleRef module);
109 : :
110 : : static void llvm_create_types(void);
111 : : static void llvm_set_target(void);
112 : : static void llvm_recreate_llvm_context(void);
113 : : static uint64_t llvm_resolve_symbol(const char *name, void *ctx);
114 : :
115 : : static LLVMOrcLLJITRef llvm_create_jit_instance(LLVMTargetMachineRef tm);
116 : : static char *llvm_error_message(LLVMErrorRef error);
117 : :
118 : : /* ResourceOwner callbacks to hold JitContexts */
119 : : static void ResOwnerReleaseJitContext(Datum res);
120 : :
121 : : static const ResourceOwnerDesc jit_resowner_desc =
122 : : {
123 : : .name = "LLVM JIT context",
124 : : .release_phase = RESOURCE_RELEASE_BEFORE_LOCKS,
125 : : .release_priority = RELEASE_PRIO_JIT_CONTEXTS,
126 : : .ReleaseResource = ResOwnerReleaseJitContext,
127 : : .DebugPrint = NULL /* the default message is fine */
128 : : };
129 : :
130 : : /* Convenience wrappers over ResourceOwnerRemember/Forget */
131 : : static inline void
132 : 0 : ResourceOwnerRememberJIT(ResourceOwner owner, LLVMJitContext *handle)
133 : : {
134 : 0 : ResourceOwnerRemember(owner, PointerGetDatum(handle), &jit_resowner_desc);
135 : 0 : }
136 : : static inline void
137 : 0 : ResourceOwnerForgetJIT(ResourceOwner owner, LLVMJitContext *handle)
138 : : {
139 : 0 : ResourceOwnerForget(owner, PointerGetDatum(handle), &jit_resowner_desc);
140 : 0 : }
141 : :
142 : 0 : PG_MODULE_MAGIC_EXT(
143 : : .name = "llvmjit",
144 : : .version = PG_VERSION
145 : : );
146 : :
147 : :
148 : : /*
149 : : * Initialize LLVM JIT provider.
150 : : */
151 : : void
152 : 0 : _PG_jit_provider_init(JitProviderCallbacks *cb)
153 : : {
154 : 0 : cb->reset_after_error = llvm_reset_after_error;
155 : 0 : cb->release_context = llvm_release_context;
156 : 0 : cb->compile_expr = llvm_compile_expr;
157 : 0 : }
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 : 0 : llvm_recreate_llvm_context(void)
175 : : {
176 [ # # ]: 0 : 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 [ # # ]: 0 : if (llvm_jit_context_in_use_count > 0)
184 : : {
185 : 0 : llvm_llvm_context_reuse_count++;
186 : 0 : return;
187 : : }
188 : :
189 [ # # ]: 0 : if (llvm_llvm_context_reuse_count <= LLVMJIT_LLVM_CONTEXT_REUSE_MAX)
190 : : {
191 : 0 : llvm_llvm_context_reuse_count++;
192 : 0 : 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 : 0 : llvm_create_context(int jitFlags)
225 : : {
226 : : LLVMJitContext *context;
227 : :
228 : 0 : llvm_assert_in_fatal_section();
229 : :
230 : 0 : llvm_session_initialize();
231 : :
232 : 0 : llvm_recreate_llvm_context();
233 : :
234 : 0 : ResourceOwnerEnlarge(CurrentResourceOwner);
235 : :
236 : 0 : context = MemoryContextAllocZero(TopMemoryContext,
237 : : sizeof(LLVMJitContext));
238 : 0 : context->base.flags = jitFlags;
239 : :
240 : : /* ensure cleanup */
241 : 0 : context->resowner = CurrentResourceOwner;
242 : 0 : ResourceOwnerRememberJIT(CurrentResourceOwner, context);
243 : :
244 : 0 : llvm_jit_context_in_use_count++;
245 : :
246 : 0 : return context;
247 : : }
248 : :
249 : : /*
250 : : * Release resources required by one llvm context.
251 : : */
252 : : static void
253 : 0 : llvm_release_context(JitContext *context)
254 : : {
255 : 0 : 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 : 0 : 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 [ # # ]: 0 : if (proc_exit_inprogress)
270 : 0 : return;
271 : :
272 : 0 : llvm_enter_fatal_on_oom();
273 : :
274 [ # # ]: 0 : if (llvm_jit_context->module)
275 : : {
276 : 0 : LLVMDisposeModule(llvm_jit_context->module);
277 : 0 : llvm_jit_context->module = NULL;
278 : : }
279 : :
280 [ # # # # : 0 : foreach(lc, llvm_jit_context->handles)
# # ]
281 : : {
282 : 0 : LLVMJitHandle *jit_handle = (LLVMJitHandle *) lfirst(lc);
283 : :
284 : : {
285 : : LLVMOrcExecutionSessionRef ee;
286 : : LLVMOrcSymbolStringPoolRef sp;
287 : :
288 : 0 : LLVMOrcResourceTrackerRemove(jit_handle->resource_tracker);
289 : 0 : 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 : 0 : ee = LLVMOrcLLJITGetExecutionSession(jit_handle->lljit);
298 : 0 : sp = LLVMOrcExecutionSessionGetSymbolStringPool(ee);
299 : 0 : LLVMOrcSymbolStringPoolClearDeadEntries(sp);
300 : : }
301 : :
302 : 0 : pfree(jit_handle);
303 : : }
304 : 0 : list_free(llvm_jit_context->handles);
305 : 0 : llvm_jit_context->handles = NIL;
306 : :
307 : 0 : llvm_leave_fatal_on_oom();
308 : :
309 [ # # ]: 0 : if (llvm_jit_context->resowner)
310 : 0 : 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 : 0 : llvm_mutable_module(LLVMJitContext *context)
318 : : {
319 : 0 : llvm_assert_in_fatal_section();
320 : :
321 : : /*
322 : : * If there's no in-progress module, create a new one.
323 : : */
324 [ # # ]: 0 : if (!context->module)
325 : : {
326 : 0 : context->compiled = false;
327 : 0 : context->module_generation = llvm_generation++;
328 : 0 : context->module = LLVMModuleCreateWithNameInContext("pg", llvm_context);
329 : 0 : LLVMSetTarget(context->module, llvm_triple);
330 : 0 : LLVMSetDataLayout(context->module, llvm_layout);
331 : : }
332 : :
333 : 0 : 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 : 0 : llvm_expand_funcname(struct LLVMJitContext *context, const char *basename)
343 : : {
344 : : Assert(context->module != NULL);
345 : :
346 : 0 : 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 : 0 : return psprintf("%s_%zu_%d",
353 : : basename,
354 : : context->module_generation,
355 : 0 : 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 : 0 : llvm_get_function(LLVMJitContext *context, const char *funcname)
364 : : {
365 : : ListCell *lc;
366 : :
367 : 0 : 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 [ # # ]: 0 : if (!context->compiled)
374 : : {
375 : 0 : 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 [ # # # # : 0 : foreach(lc, context->handles)
# # ]
384 : : {
385 : 0 : LLVMJitHandle *handle = (LLVMJitHandle *) lfirst(lc);
386 : : instr_time starttime;
387 : : instr_time endtime;
388 : : LLVMErrorRef error;
389 : : LLVMOrcJITTargetAddress addr;
390 : :
391 : 0 : INSTR_TIME_SET_CURRENT(starttime);
392 : :
393 : 0 : addr = 0;
394 : 0 : error = LLVMOrcLLJITLookup(handle->lljit, &addr, funcname);
395 [ # # ]: 0 : 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 : 0 : INSTR_TIME_SET_CURRENT(endtime);
406 : 0 : INSTR_TIME_ACCUM_DIFF(context->base.instr.emission_counter,
407 : : endtime, starttime);
408 : :
409 [ # # ]: 0 : if (addr)
410 : 0 : 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 : 0 : 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 : 0 : v_srcvar = LLVMGetNamedGlobal(llvm_types_module, varname);
430 [ # # ]: 0 : if (!v_srcvar)
431 [ # # ]: 0 : elog(ERROR, "variable %s not in llvmjit_types.c", varname);
432 : :
433 : 0 : typ = LLVMGlobalGetValueType(v_srcvar);
434 : :
435 : 0 : 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 : 0 : llvm_pg_var_func_type(const char *varname)
444 : : {
445 : : LLVMValueRef v_srcvar;
446 : : LLVMTypeRef typ;
447 : :
448 : 0 : v_srcvar = LLVMGetNamedFunction(llvm_types_module, varname);
449 [ # # ]: 0 : if (!v_srcvar)
450 [ # # ]: 0 : elog(ERROR, "function %s not in llvmjit_types.c", varname);
451 : :
452 : 0 : typ = LLVMGetFunctionType(v_srcvar);
453 : :
454 : 0 : 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 : 0 : 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 : 0 : v_fn = LLVMGetNamedFunction(mod, funcname);
472 [ # # ]: 0 : if (v_fn)
473 : 0 : return v_fn;
474 : :
475 : 0 : v_srcfn = LLVMGetNamedFunction(llvm_types_module, funcname);
476 : :
477 [ # # ]: 0 : if (!v_srcfn)
478 [ # # ]: 0 : elog(ERROR, "function %s not in llvmjit_types.c", funcname);
479 : :
480 : 0 : v_fn = LLVMAddFunction(mod,
481 : : funcname,
482 : : LLVMGetFunctionType(v_srcfn));
483 : 0 : llvm_copy_attributes(v_srcfn, v_fn);
484 : :
485 : 0 : 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 : 0 : llvm_copy_attributes_at_index(LLVMValueRef v_from, LLVMValueRef v_to, uint32 index)
494 : : {
495 : : int num_attributes;
496 : : LLVMAttributeRef *attrs;
497 : :
498 : 0 : num_attributes = LLVMGetAttributeCountAtIndex(v_from, index);
499 : :
500 [ # # ]: 0 : if (num_attributes == 0)
501 : 0 : return;
502 : :
503 : 0 : attrs = palloc_array(LLVMAttributeRef, num_attributes);
504 : 0 : LLVMGetAttributesAtIndex(v_from, index, attrs);
505 : :
506 [ # # ]: 0 : for (int attno = 0; attno < num_attributes; attno++)
507 : 0 : LLVMAddAttributeAtIndex(v_to, index, attrs[attno]);
508 : :
509 : 0 : 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 : 0 : llvm_copy_attributes(LLVMValueRef v_from, LLVMValueRef v_to)
518 : : {
519 : : uint32 param_count;
520 : :
521 : : /* copy function attributes */
522 : 0 : llvm_copy_attributes_at_index(v_from, v_to, LLVMAttributeFunctionIndex);
523 : :
524 [ # # ]: 0 : if (LLVMGetTypeKind(LLVMGetFunctionReturnType(v_to)) != LLVMVoidTypeKind)
525 : : {
526 : : /* and the return value attributes */
527 : 0 : llvm_copy_attributes_at_index(v_from, v_to, LLVMAttributeReturnIndex);
528 : : }
529 : :
530 : : /* and each function parameter's attribute */
531 : 0 : param_count = LLVMCountParams(v_from);
532 : :
533 [ # # ]: 0 : for (int paramidx = 1; paramidx <= param_count; paramidx++)
534 : 0 : llvm_copy_attributes_at_index(v_from, v_to, paramidx);
535 : 0 : }
536 : :
537 : : /*
538 : : * Return a callable LLVMValueRef for fcinfo.
539 : : */
540 : : LLVMValueRef
541 : 0 : 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 : 0 : fmgr_symbol(fcinfo->flinfo->fn_oid, &modname, &basename);
553 : :
554 [ # # # # ]: 0 : if (modname != NULL && basename != NULL)
555 : : {
556 : : /* external function in loadable library */
557 : 0 : funcname = psprintf("pgextern.%s.%s", modname, basename);
558 : : }
559 [ # # ]: 0 : else if (basename != NULL)
560 : : {
561 : : /* internal function */
562 : 0 : 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 : 0 : funcname = psprintf("pgoidextern.%u",
574 : 0 : fcinfo->flinfo->fn_oid);
575 : 0 : v_fn = LLVMGetNamedGlobal(mod, funcname);
576 [ # # ]: 0 : if (v_fn != 0)
577 : 0 : return l_load(builder, TypePGFunction, v_fn, "");
578 : :
579 : 0 : v_fn_addr = l_ptr_const(fcinfo->flinfo->fn_addr, TypePGFunction);
580 : :
581 : 0 : v_fn = LLVMAddGlobal(mod, TypePGFunction, funcname);
582 : 0 : LLVMSetInitializer(v_fn, v_fn_addr);
583 : 0 : LLVMSetGlobalConstant(v_fn, true);
584 : 0 : LLVMSetLinkage(v_fn, LLVMPrivateLinkage);
585 : 0 : LLVMSetUnnamedAddr(v_fn, true);
586 : :
587 : 0 : return l_load(builder, TypePGFunction, v_fn, "");
588 : : }
589 : :
590 : : /* check if function already has been added */
591 : 0 : v_fn = LLVMGetNamedFunction(mod, funcname);
592 [ # # ]: 0 : if (v_fn != 0)
593 : 0 : return v_fn;
594 : :
595 : 0 : v_fn = LLVMAddFunction(mod, funcname, LLVMGetFunctionType(AttributeTemplate));
596 : :
597 : 0 : return v_fn;
598 : : }
599 : :
600 : : /*
601 : : * Optimize code in module using the flags set in context.
602 : : */
603 : : static void
604 : 0 : 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 [ # # ]: 0 : if (context->base.flags & PGJIT_OPT3)
676 : 0 : passes = "default<O3>";
677 [ # # ]: 0 : else if (context->base.flags & PGJIT_INLINE)
678 : : /* if doing inlining, but no expensive optimization, add inline pass */
679 : 0 : passes = "default<O0>,mem2reg,inline";
680 : : else
681 : : /* default<O0> includes always-inline pass */
682 : 0 : passes = "default<O0>,mem2reg";
683 : :
684 : 0 : options = LLVMCreatePassBuilderOptions();
685 : :
686 : : #ifdef LLVM_PASS_DEBUG
687 : : LLVMPassBuilderOptionsSetDebugLogging(options, 1);
688 : : #endif
689 : :
690 : : /* In assertion builds, run the LLVM verify pass. */
691 : : #ifdef USE_ASSERT_CHECKING
692 : : LLVMPassBuilderOptionsSetVerifyEach(options, true);
693 : : #endif
694 : :
695 : 0 : LLVMPassBuilderOptionsSetInlinerThreshold(options, 512);
696 : :
697 : 0 : err = LLVMRunPasses(module, passes, NULL, options);
698 : :
699 [ # # ]: 0 : if (err)
700 [ # # ]: 0 : elog(ERROR, "failed to JIT module: %s", llvm_error_message(err));
701 : :
702 : 0 : LLVMDisposePassBuilderOptions(options);
703 : : #endif
704 : 0 : }
705 : :
706 : : /*
707 : : * Emit code for the currently pending module.
708 : : */
709 : : static void
710 : 0 : llvm_compile_module(LLVMJitContext *context)
711 : : {
712 : : LLVMJitHandle *handle;
713 : : MemoryContext oldcontext;
714 : : instr_time starttime;
715 : : instr_time endtime;
716 : : LLVMOrcLLJITRef compile_orc;
717 : :
718 [ # # ]: 0 : if (context->base.flags & PGJIT_OPT3)
719 : 0 : compile_orc = llvm_opt3_orc;
720 : : else
721 : 0 : compile_orc = llvm_opt0_orc;
722 : :
723 : : /* perform inlining */
724 [ # # ]: 0 : if (context->base.flags & PGJIT_INLINE)
725 : : {
726 : 0 : INSTR_TIME_SET_CURRENT(starttime);
727 : 0 : llvm_inline(context->module);
728 : 0 : INSTR_TIME_SET_CURRENT(endtime);
729 : 0 : INSTR_TIME_ACCUM_DIFF(context->base.instr.inlining_counter,
730 : : endtime, starttime);
731 : : }
732 : :
733 [ # # ]: 0 : if (jit_dump_bitcode)
734 : : {
735 : : char *filename;
736 : :
737 : 0 : filename = psprintf("%d.%zu.bc",
738 : : MyProcPid,
739 : : context->module_generation);
740 : 0 : LLVMWriteBitcodeToFile(context->module, filename);
741 : 0 : pfree(filename);
742 : : }
743 : :
744 : :
745 : : /* optimize according to the chosen optimization settings */
746 : 0 : INSTR_TIME_SET_CURRENT(starttime);
747 : 0 : llvm_optimize_module(context, context->module);
748 : 0 : INSTR_TIME_SET_CURRENT(endtime);
749 : 0 : INSTR_TIME_ACCUM_DIFF(context->base.instr.optimization_counter,
750 : : endtime, starttime);
751 : :
752 [ # # ]: 0 : if (jit_dump_bitcode)
753 : : {
754 : : char *filename;
755 : :
756 : 0 : filename = psprintf("%d.%zu.optimized.bc",
757 : : MyProcPid,
758 : : context->module_generation);
759 : 0 : LLVMWriteBitcodeToFile(context->module, filename);
760 : 0 : pfree(filename);
761 : : }
762 : :
763 : : handle = (LLVMJitHandle *)
764 : 0 : MemoryContextAlloc(TopMemoryContext, sizeof(LLVMJitHandle));
765 : :
766 : : /*
767 : : * Emit the code. Note that this can, depending on the optimization
768 : : * settings, take noticeable resources as code emission executes low-level
769 : : * instruction combining/selection passes etc. Without optimization a
770 : : * faster instruction selection mechanism is used.
771 : : */
772 : 0 : INSTR_TIME_SET_CURRENT(starttime);
773 : : {
774 : : LLVMOrcThreadSafeModuleRef ts_module;
775 : : LLVMErrorRef error;
776 : 0 : LLVMOrcJITDylibRef jd = LLVMOrcLLJITGetMainJITDylib(compile_orc);
777 : :
778 : 0 : ts_module = LLVMOrcCreateNewThreadSafeModule(context->module, llvm_ts_context);
779 : :
780 : 0 : handle->lljit = compile_orc;
781 : 0 : handle->resource_tracker = LLVMOrcJITDylibCreateResourceTracker(jd);
782 : :
783 : : /*
784 : : * NB: This doesn't actually emit code. That happens lazily the first
785 : : * time a symbol defined in the module is requested. Due to that
786 : : * llvm_get_function() also accounts for emission time.
787 : : */
788 : :
789 : 0 : context->module = NULL; /* will be owned by LLJIT */
790 : 0 : error = LLVMOrcLLJITAddLLVMIRModuleWithRT(compile_orc,
791 : : handle->resource_tracker,
792 : : ts_module);
793 : :
794 [ # # ]: 0 : if (error)
795 [ # # ]: 0 : elog(ERROR, "failed to JIT module: %s",
796 : : llvm_error_message(error));
797 : :
798 : : /* LLVMOrcLLJITAddLLVMIRModuleWithRT takes ownership of the module */
799 : : }
800 : :
801 : 0 : INSTR_TIME_SET_CURRENT(endtime);
802 : 0 : INSTR_TIME_ACCUM_DIFF(context->base.instr.emission_counter,
803 : : endtime, starttime);
804 : :
805 : 0 : context->module = NULL;
806 : 0 : context->compiled = true;
807 : :
808 : : /* remember emitted code for cleanup and lookups */
809 : 0 : oldcontext = MemoryContextSwitchTo(TopMemoryContext);
810 : 0 : context->handles = lappend(context->handles, handle);
811 : 0 : MemoryContextSwitchTo(oldcontext);
812 : :
813 [ # # ]: 0 : ereport(DEBUG1,
814 : : (errmsg_internal("time to inline: %.3fs, opt: %.3fs, emit: %.3fs",
815 : : INSTR_TIME_GET_DOUBLE(context->base.instr.inlining_counter),
816 : : INSTR_TIME_GET_DOUBLE(context->base.instr.optimization_counter),
817 : : INSTR_TIME_GET_DOUBLE(context->base.instr.emission_counter)),
818 : : errhidestmt(true),
819 : : errhidecontext(true)));
820 : 0 : }
821 : :
822 : : /*
823 : : * Per session initialization.
824 : : */
825 : : static void
826 : 0 : llvm_session_initialize(void)
827 : : {
828 : : MemoryContext oldcontext;
829 : 0 : char *error = NULL;
830 : 0 : char *cpu = NULL;
831 : 0 : char *features = NULL;
832 : : LLVMTargetMachineRef opt0_tm;
833 : : LLVMTargetMachineRef opt3_tm;
834 : :
835 [ # # ]: 0 : if (llvm_session_initialized)
836 : 0 : return;
837 : :
838 : 0 : oldcontext = MemoryContextSwitchTo(TopMemoryContext);
839 : :
840 : 0 : LLVMInitializeNativeTarget();
841 : 0 : LLVMInitializeNativeAsmPrinter();
842 : 0 : LLVMInitializeNativeAsmParser();
843 : :
844 [ # # ]: 0 : if (llvm_context == NULL)
845 : : {
846 : 0 : llvm_context = LLVMContextCreate();
847 : :
848 : 0 : llvm_jit_context_in_use_count = 0;
849 : 0 : llvm_llvm_context_reuse_count = 0;
850 : : }
851 : :
852 : : /*
853 : : * Synchronize types early, as that also includes inferring the target
854 : : * triple.
855 : : */
856 : 0 : llvm_create_types();
857 : :
858 : : /*
859 : : * Extract target information from loaded module.
860 : : */
861 : 0 : llvm_set_target();
862 : :
863 [ # # ]: 0 : if (LLVMGetTargetFromTriple(llvm_triple, &llvm_targetref, &error) != 0)
864 : : {
865 [ # # ]: 0 : elog(FATAL, "failed to query triple %s", error);
866 : : }
867 : :
868 : : /*
869 : : * We want the generated code to use all available features. Therefore
870 : : * grab the host CPU string and detect features of the current CPU. The
871 : : * latter is needed because some CPU architectures default to enabling
872 : : * features not all CPUs have (weird, huh).
873 : : */
874 : 0 : cpu = LLVMGetHostCPUName();
875 : 0 : features = LLVMGetHostCPUFeatures();
876 [ # # ]: 0 : elog(DEBUG2, "LLVMJIT detected CPU \"%s\", with features \"%s\"",
877 : : cpu, features);
878 : :
879 : : opt0_tm =
880 : 0 : LLVMCreateTargetMachine(llvm_targetref, llvm_triple, cpu, features,
881 : : LLVMCodeGenLevelNone,
882 : : LLVMRelocDefault,
883 : : LLVMCodeModelJITDefault);
884 : : opt3_tm =
885 : 0 : LLVMCreateTargetMachine(llvm_targetref, llvm_triple, cpu, features,
886 : : LLVMCodeGenLevelAggressive,
887 : : LLVMRelocDefault,
888 : : LLVMCodeModelJITDefault);
889 : :
890 : 0 : LLVMDisposeMessage(cpu);
891 : 0 : cpu = NULL;
892 : 0 : LLVMDisposeMessage(features);
893 : 0 : features = NULL;
894 : :
895 : : /* force symbols in main binary to be loaded */
896 : 0 : LLVMLoadLibraryPermanently(NULL);
897 : :
898 : : {
899 : 0 : llvm_ts_context = LLVMOrcCreateNewThreadSafeContext();
900 : :
901 : 0 : llvm_opt0_orc = llvm_create_jit_instance(opt0_tm);
902 : 0 : opt0_tm = 0;
903 : :
904 : 0 : llvm_opt3_orc = llvm_create_jit_instance(opt3_tm);
905 : 0 : opt3_tm = 0;
906 : : }
907 : :
908 : 0 : on_proc_exit(llvm_shutdown, 0);
909 : :
910 : 0 : llvm_session_initialized = true;
911 : :
912 : 0 : MemoryContextSwitchTo(oldcontext);
913 : : }
914 : :
915 : : static void
916 : 0 : llvm_shutdown(int code, Datum arg)
917 : : {
918 : : /*
919 : : * If llvm_shutdown() is reached while in a fatal-on-oom section an error
920 : : * has occurred in the middle of LLVM code. It is not safe to call back
921 : : * into LLVM (which is why a FATAL error was thrown).
922 : : *
923 : : * We do need to shutdown LLVM in other shutdown cases, otherwise e.g.
924 : : * profiling data won't be written out.
925 : : */
926 [ # # ]: 0 : if (llvm_in_fatal_on_oom())
927 : : {
928 : : Assert(proc_exit_inprogress);
929 : 0 : return;
930 : : }
931 : :
932 [ # # ]: 0 : if (llvm_jit_context_in_use_count != 0)
933 [ # # ]: 0 : elog(PANIC, "LLVMJitContext in use count not 0 at exit (is %zu)",
934 : : llvm_jit_context_in_use_count);
935 : :
936 : : {
937 [ # # ]: 0 : if (llvm_opt3_orc)
938 : : {
939 : 0 : LLVMOrcDisposeLLJIT(llvm_opt3_orc);
940 : 0 : llvm_opt3_orc = NULL;
941 : : }
942 [ # # ]: 0 : if (llvm_opt0_orc)
943 : : {
944 : 0 : LLVMOrcDisposeLLJIT(llvm_opt0_orc);
945 : 0 : llvm_opt0_orc = NULL;
946 : : }
947 [ # # ]: 0 : if (llvm_ts_context)
948 : : {
949 : 0 : LLVMOrcDisposeThreadSafeContext(llvm_ts_context);
950 : 0 : llvm_ts_context = NULL;
951 : : }
952 : : }
953 : : }
954 : :
955 : : /* helper for llvm_create_types, returning a function's return type */
956 : : static LLVMTypeRef
957 : 0 : load_return_type(LLVMModuleRef mod, const char *name)
958 : : {
959 : : LLVMValueRef value;
960 : : LLVMTypeRef typ;
961 : :
962 : : /* this'll return a *pointer* to the function */
963 : 0 : value = LLVMGetNamedFunction(mod, name);
964 [ # # ]: 0 : if (!value)
965 [ # # ]: 0 : elog(ERROR, "function %s is unknown", name);
966 : :
967 : 0 : typ = LLVMGetFunctionReturnType(value); /* in llvmjit_wrap.cpp */
968 : :
969 : 0 : return typ;
970 : : }
971 : :
972 : : /*
973 : : * Load triple & layout from clang emitted file so we're guaranteed to be
974 : : * compatible.
975 : : */
976 : : static void
977 : 0 : llvm_set_target(void)
978 : : {
979 [ # # ]: 0 : if (!llvm_types_module)
980 [ # # ]: 0 : elog(ERROR, "failed to extract target information, llvmjit_types.c not loaded");
981 : :
982 [ # # ]: 0 : if (llvm_triple == NULL)
983 : 0 : llvm_triple = pstrdup(LLVMGetTarget(llvm_types_module));
984 : :
985 [ # # ]: 0 : if (llvm_layout == NULL)
986 : 0 : llvm_layout = pstrdup(LLVMGetDataLayoutStr(llvm_types_module));
987 : 0 : }
988 : :
989 : : /*
990 : : * Load required information, types, function signatures from llvmjit_types.c
991 : : * and make them available in global variables.
992 : : *
993 : : * Those global variables are then used while emitting code.
994 : : */
995 : : static void
996 : 0 : llvm_create_types(void)
997 : : {
998 : : char path[MAXPGPATH];
999 : : LLVMMemoryBufferRef buf;
1000 : : char *msg;
1001 : :
1002 : 0 : snprintf(path, MAXPGPATH, "%s/%s", pkglib_path, "llvmjit_types.bc");
1003 : :
1004 : : /* open file */
1005 [ # # ]: 0 : if (LLVMCreateMemoryBufferWithContentsOfFile(path, &buf, &msg))
1006 : : {
1007 [ # # ]: 0 : elog(ERROR, "LLVMCreateMemoryBufferWithContentsOfFile(%s) failed: %s",
1008 : : path, msg);
1009 : : }
1010 : :
1011 : : /* eagerly load contents, going to need it all */
1012 [ # # ]: 0 : if (LLVMParseBitcodeInContext2(llvm_context, buf, &llvm_types_module))
1013 : : {
1014 [ # # ]: 0 : elog(ERROR, "LLVMParseBitcodeInContext2 of %s failed", path);
1015 : : }
1016 : 0 : LLVMDisposeMemoryBuffer(buf);
1017 : :
1018 : 0 : TypeSizeT = llvm_pg_var_type("TypeSizeT");
1019 : 0 : TypeDatum = llvm_pg_var_type("TypeDatum");
1020 : 0 : TypeParamBool = load_return_type(llvm_types_module, "FunctionReturningBool");
1021 : 0 : TypeStorageBool = llvm_pg_var_type("TypeStorageBool");
1022 : 0 : TypePGFunction = llvm_pg_var_type("TypePGFunction");
1023 : 0 : StructNullableDatum = llvm_pg_var_type("StructNullableDatum");
1024 : 0 : StructExprContext = llvm_pg_var_type("StructExprContext");
1025 : 0 : StructExprEvalStep = llvm_pg_var_type("StructExprEvalStep");
1026 : 0 : StructExprState = llvm_pg_var_type("StructExprState");
1027 : 0 : StructFunctionCallInfoData = llvm_pg_var_type("StructFunctionCallInfoData");
1028 : 0 : StructMemoryContextData = llvm_pg_var_type("StructMemoryContextData");
1029 : 0 : StructTupleTableSlot = llvm_pg_var_type("StructTupleTableSlot");
1030 : 0 : StructHeapTupleTableSlot = llvm_pg_var_type("StructHeapTupleTableSlot");
1031 : 0 : StructMinimalTupleTableSlot = llvm_pg_var_type("StructMinimalTupleTableSlot");
1032 : 0 : StructHeapTupleData = llvm_pg_var_type("StructHeapTupleData");
1033 : 0 : StructHeapTupleHeaderData = llvm_pg_var_type("StructHeapTupleHeaderData");
1034 : 0 : StructTupleDescData = llvm_pg_var_type("StructTupleDescData");
1035 : 0 : StructAggState = llvm_pg_var_type("StructAggState");
1036 : 0 : StructAggStatePerGroupData = llvm_pg_var_type("StructAggStatePerGroupData");
1037 : 0 : StructAggStatePerTransData = llvm_pg_var_type("StructAggStatePerTransData");
1038 : 0 : StructPlanState = llvm_pg_var_type("StructPlanState");
1039 : 0 : StructMinimalTupleData = llvm_pg_var_type("StructMinimalTupleData");
1040 : :
1041 : 0 : AttributeTemplate = LLVMGetNamedFunction(llvm_types_module, "AttributeTemplate");
1042 : 0 : ExecEvalSubroutineTemplate = LLVMGetNamedFunction(llvm_types_module, "ExecEvalSubroutineTemplate");
1043 : 0 : ExecEvalBoolSubroutineTemplate = LLVMGetNamedFunction(llvm_types_module, "ExecEvalBoolSubroutineTemplate");
1044 : 0 : }
1045 : :
1046 : : /*
1047 : : * Split a symbol into module / function parts. If the function is in the
1048 : : * main binary (or an external library) *modname will be NULL.
1049 : : */
1050 : : void
1051 : 0 : llvm_split_symbol_name(const char *name, char **modname, char **funcname)
1052 : : {
1053 : : /*
1054 : : * Module function names are pgextern.$module.$funcname
1055 : : */
1056 [ # # ]: 0 : if (strncmp(name, "pgextern.", strlen("pgextern.")) == 0)
1057 : : {
1058 : : /*
1059 : : * Symbol names cannot contain a ., therefore we can split based on
1060 : : * first and last occurrence of one.
1061 : : */
1062 : : const char *lastdot;
1063 : :
1064 : 0 : name += strlen("pgextern.");
1065 : 0 : lastdot = strrchr(name, '.');
1066 [ # # ]: 0 : if (lastdot)
1067 : : {
1068 : 0 : *modname = pnstrdup(name, lastdot - name);
1069 : 0 : *funcname = pstrdup(lastdot + 1);
1070 : : }
1071 : : else
1072 : : {
1073 : : /* hmm, no second dot? */
1074 : 0 : *modname = NULL;
1075 : 0 : *funcname = pstrdup(name);
1076 : : }
1077 : : }
1078 : : else
1079 : : {
1080 : 0 : *modname = NULL;
1081 : 0 : *funcname = pstrdup(name);
1082 : : }
1083 : 0 : }
1084 : :
1085 : : /*
1086 : : * Attempt to resolve symbol, so LLVM can emit a reference to it.
1087 : : */
1088 : : static uint64_t
1089 : 0 : llvm_resolve_symbol(const char *symname, void *ctx)
1090 : : {
1091 : : uintptr_t addr;
1092 : : char *funcname;
1093 : : char *modname;
1094 : :
1095 : : /*
1096 : : * macOS prefixes all object level symbols with an underscore. But neither
1097 : : * dlsym() nor PG's inliner expect that. So undo.
1098 : : */
1099 : : #if defined(__darwin__)
1100 : : if (symname[0] != '_')
1101 : : elog(ERROR, "expected prefixed symbol name, but got \"%s\"", symname);
1102 : : symname++;
1103 : : #endif
1104 : :
1105 : 0 : llvm_split_symbol_name(symname, &modname, &funcname);
1106 : :
1107 : : /* functions that aren't resolved to names shouldn't ever get here */
1108 : : Assert(funcname);
1109 : :
1110 [ # # ]: 0 : if (modname)
1111 : 0 : addr = (uintptr_t) load_external_function(modname, funcname,
1112 : : true, NULL);
1113 : : else
1114 : 0 : addr = (uintptr_t) LLVMSearchForAddressOfSymbol(symname);
1115 : :
1116 : 0 : pfree(funcname);
1117 [ # # ]: 0 : if (modname)
1118 : 0 : pfree(modname);
1119 : :
1120 : : /* let LLVM will error out - should never happen */
1121 [ # # ]: 0 : if (!addr)
1122 [ # # ]: 0 : elog(WARNING, "failed to resolve name %s", symname);
1123 : :
1124 : 0 : return (uint64_t) addr;
1125 : : }
1126 : :
1127 : : static LLVMErrorRef
1128 : 0 : llvm_resolve_symbols(LLVMOrcDefinitionGeneratorRef GeneratorObj, void *Ctx,
1129 : : LLVMOrcLookupStateRef *LookupState, LLVMOrcLookupKind Kind,
1130 : : LLVMOrcJITDylibRef JD, LLVMOrcJITDylibLookupFlags JDLookupFlags,
1131 : : LLVMOrcCLookupSet LookupSet, size_t LookupSetSize)
1132 : : {
1133 : : #if LLVM_VERSION_MAJOR > 14
1134 : 0 : LLVMOrcCSymbolMapPairs symbols = palloc0_array(LLVMOrcCSymbolMapPair, LookupSetSize);
1135 : : #else
1136 : : LLVMOrcCSymbolMapPairs symbols = palloc0_array(LLVMJITCSymbolMapPair, LookupSetSize);
1137 : : #endif
1138 : : LLVMErrorRef error;
1139 : : LLVMOrcMaterializationUnitRef mu;
1140 : :
1141 [ # # ]: 0 : for (int i = 0; i < LookupSetSize; i++)
1142 : : {
1143 : 0 : const char *name = LLVMOrcSymbolStringPoolEntryStr(LookupSet[i].Name);
1144 : :
1145 : 0 : LLVMOrcRetainSymbolStringPoolEntry(LookupSet[i].Name);
1146 : 0 : symbols[i].Name = LookupSet[i].Name;
1147 : 0 : symbols[i].Sym.Address = llvm_resolve_symbol(name, NULL);
1148 : 0 : symbols[i].Sym.Flags.GenericFlags = LLVMJITSymbolGenericFlagsExported;
1149 : : }
1150 : :
1151 : 0 : mu = LLVMOrcAbsoluteSymbols(symbols, LookupSetSize);
1152 : 0 : error = LLVMOrcJITDylibDefine(JD, mu);
1153 [ # # ]: 0 : if (error != LLVMErrorSuccess)
1154 : 0 : LLVMOrcDisposeMaterializationUnit(mu);
1155 : :
1156 : 0 : pfree(symbols);
1157 : :
1158 : 0 : return error;
1159 : : }
1160 : :
1161 : : /*
1162 : : * We cannot throw errors through LLVM (without causing a FATAL at least), so
1163 : : * just use WARNING here. That's OK anyway, as the error is also reported at
1164 : : * the top level action (with less detail) and there might be multiple
1165 : : * invocations of errors with details.
1166 : : *
1167 : : * This doesn't really happen during normal operation, but in cases like
1168 : : * symbol resolution breakage. So just using elog(WARNING) is fine.
1169 : : */
1170 : : static void
1171 : 0 : llvm_log_jit_error(void *ctx, LLVMErrorRef error)
1172 : : {
1173 [ # # ]: 0 : elog(WARNING, "error during JITing: %s",
1174 : : llvm_error_message(error));
1175 : 0 : }
1176 : :
1177 : : /*
1178 : : * Create our own object layer, so we can add event listeners.
1179 : : */
1180 : : static LLVMOrcObjectLayerRef
1181 : 0 : llvm_create_object_layer(void *Ctx, LLVMOrcExecutionSessionRef ES, const char *Triple)
1182 : : {
1183 : : #if LLVM_VERSION_MAJOR >= 22
1184 : : LLVMOrcObjectLayerRef objlayer =
1185 : : LLVMOrcCreateRTDyldObjectLinkingLayerWithSectionMemoryManagerReserveAlloc(ES, true);
1186 : : #elif defined(USE_LLVM_BACKPORT_SECTION_MEMORY_MANAGER)
1187 : : LLVMOrcObjectLayerRef objlayer =
1188 : : LLVMOrcCreateRTDyldObjectLinkingLayerWithSafeSectionMemoryManager(ES);
1189 : : #else
1190 : : LLVMOrcObjectLayerRef objlayer =
1191 : 0 : LLVMOrcCreateRTDyldObjectLinkingLayerWithSectionMemoryManager(ES);
1192 : : #endif
1193 : :
1194 [ # # ]: 0 : if (jit_debugging_support)
1195 : : {
1196 : 0 : LLVMJITEventListenerRef l = LLVMCreateGDBRegistrationListener();
1197 : :
1198 : 0 : LLVMOrcRTDyldObjectLinkingLayerRegisterJITEventListener(objlayer, l);
1199 : : }
1200 : :
1201 [ # # ]: 0 : if (jit_profiling_support)
1202 : : {
1203 : 0 : LLVMJITEventListenerRef l = LLVMCreatePerfJITEventListener();
1204 : :
1205 [ # # ]: 0 : if (l)
1206 : 0 : LLVMOrcRTDyldObjectLinkingLayerRegisterJITEventListener(objlayer, l);
1207 : : }
1208 : :
1209 : 0 : return objlayer;
1210 : : }
1211 : :
1212 : : /*
1213 : : * Create LLJIT instance, using the passed in target machine. Note that the
1214 : : * target machine afterwards is owned by the LLJIT instance.
1215 : : */
1216 : : static LLVMOrcLLJITRef
1217 : 0 : llvm_create_jit_instance(LLVMTargetMachineRef tm)
1218 : : {
1219 : : LLVMOrcLLJITRef lljit;
1220 : : LLVMOrcJITTargetMachineBuilderRef tm_builder;
1221 : : LLVMOrcLLJITBuilderRef lljit_builder;
1222 : : LLVMErrorRef error;
1223 : : LLVMOrcDefinitionGeneratorRef main_gen;
1224 : : LLVMOrcDefinitionGeneratorRef ref_gen;
1225 : :
1226 : 0 : lljit_builder = LLVMOrcCreateLLJITBuilder();
1227 : 0 : tm_builder = LLVMOrcJITTargetMachineBuilderCreateFromTargetMachine(tm);
1228 : 0 : LLVMOrcLLJITBuilderSetJITTargetMachineBuilder(lljit_builder, tm_builder);
1229 : :
1230 : 0 : LLVMOrcLLJITBuilderSetObjectLinkingLayerCreator(lljit_builder,
1231 : : llvm_create_object_layer,
1232 : : NULL);
1233 : :
1234 : 0 : error = LLVMOrcCreateLLJIT(&lljit, lljit_builder);
1235 [ # # ]: 0 : if (error)
1236 [ # # ]: 0 : elog(ERROR, "failed to create lljit instance: %s",
1237 : : llvm_error_message(error));
1238 : :
1239 : 0 : LLVMOrcExecutionSessionSetErrorReporter(LLVMOrcLLJITGetExecutionSession(lljit),
1240 : : llvm_log_jit_error, NULL);
1241 : :
1242 : : /*
1243 : : * Symbol resolution support for symbols in the postgres binary /
1244 : : * libraries already loaded.
1245 : : */
1246 : 0 : error = LLVMOrcCreateDynamicLibrarySearchGeneratorForProcess(&main_gen,
1247 : 0 : LLVMOrcLLJITGetGlobalPrefix(lljit),
1248 : : 0, NULL);
1249 [ # # ]: 0 : if (error)
1250 [ # # ]: 0 : elog(ERROR, "failed to create generator: %s",
1251 : : llvm_error_message(error));
1252 : 0 : LLVMOrcJITDylibAddGenerator(LLVMOrcLLJITGetMainJITDylib(lljit), main_gen);
1253 : :
1254 : : /*
1255 : : * Symbol resolution support for "special" functions, e.g. a call into an
1256 : : * SQL callable function.
1257 : : */
1258 : : #if LLVM_VERSION_MAJOR > 14
1259 : 0 : ref_gen = LLVMOrcCreateCustomCAPIDefinitionGenerator(llvm_resolve_symbols, NULL, NULL);
1260 : : #else
1261 : : ref_gen = LLVMOrcCreateCustomCAPIDefinitionGenerator(llvm_resolve_symbols, NULL);
1262 : : #endif
1263 : 0 : LLVMOrcJITDylibAddGenerator(LLVMOrcLLJITGetMainJITDylib(lljit), ref_gen);
1264 : :
1265 : 0 : return lljit;
1266 : : }
1267 : :
1268 : : static char *
1269 : 0 : llvm_error_message(LLVMErrorRef error)
1270 : : {
1271 : 0 : char *orig = LLVMGetErrorMessage(error);
1272 : 0 : char *msg = pstrdup(orig);
1273 : :
1274 : 0 : LLVMDisposeErrorMessage(orig);
1275 : :
1276 : 0 : return msg;
1277 : : }
1278 : :
1279 : : /*
1280 : : * ResourceOwner callbacks
1281 : : */
1282 : : static void
1283 : 0 : ResOwnerReleaseJitContext(Datum res)
1284 : : {
1285 : 0 : LLVMJitContext *context = (LLVMJitContext *) DatumGetPointer(res);
1286 : :
1287 : 0 : context->resowner = NULL;
1288 : 0 : jit_release_context(&context->base);
1289 : 0 : }
|