LCOV - code coverage report
Current view: top level - src/backend/jit/llvm - llvmjit.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 79.6 % 377 300
Test Date: 2026-02-17 17:20:33 Functions: 87.1 % 31 27
Legend: Lines:     hit not hit

            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          464 : ResourceOwnerRememberJIT(ResourceOwner owner, LLVMJitContext *handle)
     133              : {
     134          464 :     ResourceOwnerRemember(owner, PointerGetDatum(handle), &jit_resowner_desc);
     135          464 : }
     136              : static inline void
     137          456 : ResourceOwnerForgetJIT(ResourceOwner owner, LLVMJitContext *handle)
     138              : {
     139          456 :     ResourceOwnerForget(owner, PointerGetDatum(handle), &jit_resowner_desc);
     140          456 : }
     141              : 
     142          809 : PG_MODULE_MAGIC_EXT(
     143              :                     .name = "llvmjit",
     144              :                     .version = PG_VERSION
     145              : );
     146              : 
     147              : 
     148              : /*
     149              :  * Initialize LLVM JIT provider.
     150              :  */
     151              : void
     152           95 : _PG_jit_provider_init(JitProviderCallbacks *cb)
     153              : {
     154           95 :     cb->reset_after_error = llvm_reset_after_error;
     155           95 :     cb->release_context = llvm_release_context;
     156           95 :     cb->compile_expr = llvm_compile_expr;
     157           95 : }
     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          464 : llvm_recreate_llvm_context(void)
     175              : {
     176          464 :     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          464 :     if (llvm_jit_context_in_use_count > 0)
     184              :     {
     185            0 :         llvm_llvm_context_reuse_count++;
     186            0 :         return;
     187              :     }
     188              : 
     189          464 :     if (llvm_llvm_context_reuse_count <= LLVMJIT_LLVM_CONTEXT_REUSE_MAX)
     190              :     {
     191          464 :         llvm_llvm_context_reuse_count++;
     192          464 :         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          464 : llvm_create_context(int jitFlags)
     225              : {
     226              :     LLVMJitContext *context;
     227              : 
     228          464 :     llvm_assert_in_fatal_section();
     229              : 
     230          464 :     llvm_session_initialize();
     231              : 
     232          464 :     llvm_recreate_llvm_context();
     233              : 
     234          464 :     ResourceOwnerEnlarge(CurrentResourceOwner);
     235              : 
     236          464 :     context = MemoryContextAllocZero(TopMemoryContext,
     237              :                                      sizeof(LLVMJitContext));
     238          464 :     context->base.flags = jitFlags;
     239              : 
     240              :     /* ensure cleanup */
     241          464 :     context->resowner = CurrentResourceOwner;
     242          464 :     ResourceOwnerRememberJIT(CurrentResourceOwner, context);
     243              : 
     244          464 :     llvm_jit_context_in_use_count++;
     245              : 
     246          464 :     return context;
     247              : }
     248              : 
     249              : /*
     250              :  * Release resources required by one llvm context.
     251              :  */
     252              : static void
     253          464 : llvm_release_context(JitContext *context)
     254              : {
     255          464 :     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          464 :     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          464 :     if (proc_exit_inprogress)
     270            0 :         return;
     271              : 
     272          464 :     llvm_enter_fatal_on_oom();
     273              : 
     274          464 :     if (llvm_jit_context->module)
     275              :     {
     276          182 :         LLVMDisposeModule(llvm_jit_context->module);
     277          182 :         llvm_jit_context->module = NULL;
     278              :     }
     279              : 
     280          788 :     foreach(lc, llvm_jit_context->handles)
     281              :     {
     282          324 :         LLVMJitHandle *jit_handle = (LLVMJitHandle *) lfirst(lc);
     283              : 
     284              :         {
     285              :             LLVMOrcExecutionSessionRef ee;
     286              :             LLVMOrcSymbolStringPoolRef sp;
     287              : 
     288          324 :             LLVMOrcResourceTrackerRemove(jit_handle->resource_tracker);
     289          324 :             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          324 :             ee = LLVMOrcLLJITGetExecutionSession(jit_handle->lljit);
     298          324 :             sp = LLVMOrcExecutionSessionGetSymbolStringPool(ee);
     299          324 :             LLVMOrcSymbolStringPoolClearDeadEntries(sp);
     300              :         }
     301              : 
     302          324 :         pfree(jit_handle);
     303              :     }
     304          464 :     list_free(llvm_jit_context->handles);
     305          464 :     llvm_jit_context->handles = NIL;
     306              : 
     307          464 :     llvm_leave_fatal_on_oom();
     308              : 
     309          464 :     if (llvm_jit_context->resowner)
     310          456 :         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         5839 : llvm_mutable_module(LLVMJitContext *context)
     318              : {
     319         5839 :     llvm_assert_in_fatal_section();
     320              : 
     321              :     /*
     322              :      * If there's no in-progress module, create a new one.
     323              :      */
     324         5839 :     if (!context->module)
     325              :     {
     326          506 :         context->compiled = false;
     327          506 :         context->module_generation = llvm_generation++;
     328          506 :         context->module = LLVMModuleCreateWithNameInContext("pg", llvm_context);
     329          506 :         LLVMSetTarget(context->module, llvm_triple);
     330          506 :         LLVMSetDataLayout(context->module, llvm_layout);
     331              :     }
     332              : 
     333         5839 :     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         5839 : llvm_expand_funcname(struct LLVMJitContext *context, const char *basename)
     343              : {
     344              :     Assert(context->module != NULL);
     345              : 
     346         5839 :     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        11678 :     return psprintf("%s_%zu_%d",
     353              :                     basename,
     354              :                     context->module_generation,
     355         5839 :                     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         1953 : llvm_get_function(LLVMJitContext *context, const char *funcname)
     364              : {
     365              :     ListCell   *lc;
     366              : 
     367         1953 :     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         1953 :     if (!context->compiled)
     374              :     {
     375          324 :         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         1953 :     foreach(lc, context->handles)
     384              :     {
     385         1953 :         LLVMJitHandle *handle = (LLVMJitHandle *) lfirst(lc);
     386              :         instr_time  starttime;
     387              :         instr_time  endtime;
     388              :         LLVMErrorRef error;
     389              :         LLVMOrcJITTargetAddress addr;
     390              : 
     391         1953 :         INSTR_TIME_SET_CURRENT(starttime);
     392              : 
     393         1953 :         addr = 0;
     394         1953 :         error = LLVMOrcLLJITLookup(handle->lljit, &addr, funcname);
     395         1953 :         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         1953 :         INSTR_TIME_SET_CURRENT(endtime);
     406         1953 :         INSTR_TIME_ACCUM_DIFF(context->base.instr.emission_counter,
     407              :                               endtime, starttime);
     408              : 
     409         1953 :         if (addr)
     410         1953 :             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         2025 : 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         2025 :     v_srcvar = LLVMGetNamedGlobal(llvm_types_module, varname);
     430         2025 :     if (!v_srcvar)
     431            0 :         elog(ERROR, "variable %s not in llvmjit_types.c", varname);
     432              : 
     433         2025 :     typ = LLVMGlobalGetValueType(v_srcvar);
     434              : 
     435         2025 :     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         5255 : llvm_pg_var_func_type(const char *varname)
     444              : {
     445              :     LLVMValueRef v_srcvar;
     446              :     LLVMTypeRef typ;
     447              : 
     448         5255 :     v_srcvar = LLVMGetNamedFunction(llvm_types_module, varname);
     449         5255 :     if (!v_srcvar)
     450            0 :         elog(ERROR, "function %s not in llvmjit_types.c", varname);
     451              : 
     452         5255 :     typ = LLVMGetFunctionType(v_srcvar);
     453              : 
     454         5255 :     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         5618 : 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         5618 :     v_fn = LLVMGetNamedFunction(mod, funcname);
     472         5618 :     if (v_fn)
     473         4182 :         return v_fn;
     474              : 
     475         1436 :     v_srcfn = LLVMGetNamedFunction(llvm_types_module, funcname);
     476              : 
     477         1436 :     if (!v_srcfn)
     478            0 :         elog(ERROR, "function %s not in llvmjit_types.c", funcname);
     479              : 
     480         1436 :     v_fn = LLVMAddFunction(mod,
     481              :                            funcname,
     482              :                            LLVMGetFunctionType(v_srcfn));
     483         1436 :     llvm_copy_attributes(v_srcfn, v_fn);
     484              : 
     485         1436 :     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        20671 : llvm_copy_attributes_at_index(LLVMValueRef v_from, LLVMValueRef v_to, uint32 index)
     494              : {
     495              :     int         num_attributes;
     496              :     LLVMAttributeRef *attrs;
     497              : 
     498        20671 :     num_attributes = LLVMGetAttributeCountAtIndex(v_from, index);
     499              : 
     500        20671 :     if (num_attributes == 0)
     501          282 :         return;
     502              : 
     503        20389 :     attrs = palloc_array(LLVMAttributeRef, num_attributes);
     504        20389 :     LLVMGetAttributesAtIndex(v_from, index, attrs);
     505              : 
     506       134143 :     for (int attno = 0; attno < num_attributes; attno++)
     507       113754 :         LLVMAddAttributeAtIndex(v_to, index, attrs[attno]);
     508              : 
     509        20389 :     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         7275 : llvm_copy_attributes(LLVMValueRef v_from, LLVMValueRef v_to)
     518              : {
     519              :     uint32      param_count;
     520              : 
     521              :     /* copy function attributes */
     522         7275 :     llvm_copy_attributes_at_index(v_from, v_to, LLVMAttributeFunctionIndex);
     523              : 
     524         7275 :     if (LLVMGetTypeKind(LLVMGetFunctionReturnType(v_to)) != LLVMVoidTypeKind)
     525              :     {
     526              :         /* and the return value attributes */
     527         3912 :         llvm_copy_attributes_at_index(v_from, v_to, LLVMAttributeReturnIndex);
     528              :     }
     529              : 
     530              :     /* and each function parameter's attribute */
     531         7275 :     param_count = LLVMCountParams(v_from);
     532              : 
     533        16759 :     for (int paramidx = 1; paramidx <= param_count; paramidx++)
     534         9484 :         llvm_copy_attributes_at_index(v_from, v_to, paramidx);
     535         7275 : }
     536              : 
     537              : /*
     538              :  * Return a callable LLVMValueRef for fcinfo.
     539              :  */
     540              : LLVMValueRef
     541         2651 : 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         2651 :     fmgr_symbol(fcinfo->flinfo->fn_oid, &modname, &basename);
     553              : 
     554         2651 :     if (modname != NULL && basename != NULL)
     555              :     {
     556              :         /* external function in loadable library */
     557            0 :         funcname = psprintf("pgextern.%s.%s", modname, basename);
     558              :     }
     559         2651 :     else if (basename != NULL)
     560              :     {
     561              :         /* internal function */
     562         2645 :         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            6 :         funcname = psprintf("pgoidextern.%u",
     574            6 :                             fcinfo->flinfo->fn_oid);
     575            6 :         v_fn = LLVMGetNamedGlobal(mod, funcname);
     576            6 :         if (v_fn != 0)
     577            0 :             return l_load(builder, TypePGFunction, v_fn, "");
     578              : 
     579            6 :         v_fn_addr = l_ptr_const(fcinfo->flinfo->fn_addr, TypePGFunction);
     580              : 
     581            6 :         v_fn = LLVMAddGlobal(mod, TypePGFunction, funcname);
     582            6 :         LLVMSetInitializer(v_fn, v_fn_addr);
     583            6 :         LLVMSetGlobalConstant(v_fn, true);
     584            6 :         LLVMSetLinkage(v_fn, LLVMPrivateLinkage);
     585            6 :         LLVMSetUnnamedAddr(v_fn, true);
     586              : 
     587            6 :         return l_load(builder, TypePGFunction, v_fn, "");
     588              :     }
     589              : 
     590              :     /* check if function already has been added */
     591         2645 :     v_fn = LLVMGetNamedFunction(mod, funcname);
     592         2645 :     if (v_fn != 0)
     593         1543 :         return v_fn;
     594              : 
     595         1102 :     v_fn = LLVMAddFunction(mod, funcname, LLVMGetFunctionType(AttributeTemplate));
     596              : 
     597         1102 :     return v_fn;
     598              : }
     599              : 
     600              : /*
     601              :  * Optimize code in module using the flags set in context.
     602              :  */
     603              : static void
     604          324 : 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          324 :     if (context->base.flags & PGJIT_OPT3)
     676          108 :         passes = "default<O3>";
     677          216 :     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          216 :         passes = "default<O0>,mem2reg";
     683              : 
     684          324 :     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          324 :     LLVMPassBuilderOptionsSetInlinerThreshold(options, 512);
     696              : 
     697          324 :     err = LLVMRunPasses(module, passes, NULL, options);
     698              : 
     699          324 :     if (err)
     700            0 :         elog(ERROR, "failed to JIT module: %s", llvm_error_message(err));
     701              : 
     702          324 :     LLVMDisposePassBuilderOptions(options);
     703              : #endif
     704          324 : }
     705              : 
     706              : /*
     707              :  * Emit code for the currently pending module.
     708              :  */
     709              : static void
     710          324 : 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          324 :     if (context->base.flags & PGJIT_OPT3)
     719          108 :         compile_orc = llvm_opt3_orc;
     720              :     else
     721          216 :         compile_orc = llvm_opt0_orc;
     722              : 
     723              :     /* perform inlining */
     724          324 :     if (context->base.flags & PGJIT_INLINE)
     725              :     {
     726          108 :         INSTR_TIME_SET_CURRENT(starttime);
     727          108 :         llvm_inline(context->module);
     728          108 :         INSTR_TIME_SET_CURRENT(endtime);
     729          108 :         INSTR_TIME_ACCUM_DIFF(context->base.instr.inlining_counter,
     730              :                               endtime, starttime);
     731              :     }
     732              : 
     733          324 :     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          324 :     INSTR_TIME_SET_CURRENT(starttime);
     747          324 :     llvm_optimize_module(context, context->module);
     748          324 :     INSTR_TIME_SET_CURRENT(endtime);
     749          324 :     INSTR_TIME_ACCUM_DIFF(context->base.instr.optimization_counter,
     750              :                           endtime, starttime);
     751              : 
     752          324 :     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          324 :         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          324 :     INSTR_TIME_SET_CURRENT(starttime);
     773              :     {
     774              :         LLVMOrcThreadSafeModuleRef ts_module;
     775              :         LLVMErrorRef error;
     776          324 :         LLVMOrcJITDylibRef jd = LLVMOrcLLJITGetMainJITDylib(compile_orc);
     777              : 
     778          324 :         ts_module = LLVMOrcCreateNewThreadSafeModule(context->module, llvm_ts_context);
     779              : 
     780          324 :         handle->lljit = compile_orc;
     781          324 :         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          324 :         context->module = NULL; /* will be owned by LLJIT */
     790          324 :         error = LLVMOrcLLJITAddLLVMIRModuleWithRT(compile_orc,
     791              :                                                   handle->resource_tracker,
     792              :                                                   ts_module);
     793              : 
     794          324 :         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          324 :     INSTR_TIME_SET_CURRENT(endtime);
     802          324 :     INSTR_TIME_ACCUM_DIFF(context->base.instr.emission_counter,
     803              :                           endtime, starttime);
     804              : 
     805          324 :     context->module = NULL;
     806          324 :     context->compiled = true;
     807              : 
     808              :     /* remember emitted code for cleanup and lookups */
     809          324 :     oldcontext = MemoryContextSwitchTo(TopMemoryContext);
     810          324 :     context->handles = lappend(context->handles, handle);
     811          324 :     MemoryContextSwitchTo(oldcontext);
     812              : 
     813          324 :     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          324 : }
     821              : 
     822              : /*
     823              :  * Per session initialization.
     824              :  */
     825              : static void
     826          464 : llvm_session_initialize(void)
     827              : {
     828              :     MemoryContext oldcontext;
     829          464 :     char       *error = NULL;
     830          464 :     char       *cpu = NULL;
     831          464 :     char       *features = NULL;
     832              :     LLVMTargetMachineRef opt0_tm;
     833              :     LLVMTargetMachineRef opt3_tm;
     834              : 
     835          464 :     if (llvm_session_initialized)
     836          369 :         return;
     837              : 
     838           95 :     oldcontext = MemoryContextSwitchTo(TopMemoryContext);
     839              : 
     840           95 :     LLVMInitializeNativeTarget();
     841           95 :     LLVMInitializeNativeAsmPrinter();
     842           95 :     LLVMInitializeNativeAsmParser();
     843              : 
     844           95 :     if (llvm_context == NULL)
     845              :     {
     846           95 :         llvm_context = LLVMContextCreate();
     847              : 
     848           95 :         llvm_jit_context_in_use_count = 0;
     849           95 :         llvm_llvm_context_reuse_count = 0;
     850              :     }
     851              : 
     852              :     /*
     853              :      * Synchronize types early, as that also includes inferring the target
     854              :      * triple.
     855              :      */
     856           95 :     llvm_create_types();
     857              : 
     858              :     /*
     859              :      * Extract target information from loaded module.
     860              :      */
     861           95 :     llvm_set_target();
     862              : 
     863           95 :     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           95 :     cpu = LLVMGetHostCPUName();
     875           95 :     features = LLVMGetHostCPUFeatures();
     876           95 :     elog(DEBUG2, "LLVMJIT detected CPU \"%s\", with features \"%s\"",
     877              :          cpu, features);
     878              : 
     879              :     opt0_tm =
     880           95 :         LLVMCreateTargetMachine(llvm_targetref, llvm_triple, cpu, features,
     881              :                                 LLVMCodeGenLevelNone,
     882              :                                 LLVMRelocDefault,
     883              :                                 LLVMCodeModelJITDefault);
     884              :     opt3_tm =
     885           95 :         LLVMCreateTargetMachine(llvm_targetref, llvm_triple, cpu, features,
     886              :                                 LLVMCodeGenLevelAggressive,
     887              :                                 LLVMRelocDefault,
     888              :                                 LLVMCodeModelJITDefault);
     889              : 
     890           95 :     LLVMDisposeMessage(cpu);
     891           95 :     cpu = NULL;
     892           95 :     LLVMDisposeMessage(features);
     893           95 :     features = NULL;
     894              : 
     895              :     /* force symbols in main binary to be loaded */
     896           95 :     LLVMLoadLibraryPermanently(NULL);
     897              : 
     898              :     {
     899           95 :         llvm_ts_context = LLVMOrcCreateNewThreadSafeContext();
     900              : 
     901           95 :         llvm_opt0_orc = llvm_create_jit_instance(opt0_tm);
     902           95 :         opt0_tm = 0;
     903              : 
     904           95 :         llvm_opt3_orc = llvm_create_jit_instance(opt3_tm);
     905           95 :         opt3_tm = 0;
     906              :     }
     907              : 
     908           95 :     on_proc_exit(llvm_shutdown, 0);
     909              : 
     910           95 :     llvm_session_initialized = true;
     911              : 
     912           95 :     MemoryContextSwitchTo(oldcontext);
     913              : }
     914              : 
     915              : static void
     916           95 : 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           95 :     if (llvm_in_fatal_on_oom())
     927              :     {
     928              :         Assert(proc_exit_inprogress);
     929            0 :         return;
     930              :     }
     931              : 
     932           95 :     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           95 :         if (llvm_opt3_orc)
     938              :         {
     939           95 :             LLVMOrcDisposeLLJIT(llvm_opt3_orc);
     940           95 :             llvm_opt3_orc = NULL;
     941              :         }
     942           95 :         if (llvm_opt0_orc)
     943              :         {
     944           95 :             LLVMOrcDisposeLLJIT(llvm_opt0_orc);
     945           95 :             llvm_opt0_orc = NULL;
     946              :         }
     947           95 :         if (llvm_ts_context)
     948              :         {
     949           95 :             LLVMOrcDisposeThreadSafeContext(llvm_ts_context);
     950           95 :             llvm_ts_context = NULL;
     951              :         }
     952              :     }
     953              : }
     954              : 
     955              : /* helper for llvm_create_types, returning a function's return type */
     956              : static LLVMTypeRef
     957           95 : 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           95 :     value = LLVMGetNamedFunction(mod, name);
     964           95 :     if (!value)
     965            0 :         elog(ERROR, "function %s is unknown", name);
     966              : 
     967           95 :     typ = LLVMGetFunctionReturnType(value); /* in llvmjit_wrap.cpp */
     968              : 
     969           95 :     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           95 : llvm_set_target(void)
     978              : {
     979           95 :     if (!llvm_types_module)
     980            0 :         elog(ERROR, "failed to extract target information, llvmjit_types.c not loaded");
     981              : 
     982           95 :     if (llvm_triple == NULL)
     983           95 :         llvm_triple = pstrdup(LLVMGetTarget(llvm_types_module));
     984              : 
     985           95 :     if (llvm_layout == NULL)
     986           95 :         llvm_layout = pstrdup(LLVMGetDataLayoutStr(llvm_types_module));
     987           95 : }
     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           95 : llvm_create_types(void)
     997              : {
     998              :     char        path[MAXPGPATH];
     999              :     LLVMMemoryBufferRef buf;
    1000              :     char       *msg;
    1001              : 
    1002           95 :     snprintf(path, MAXPGPATH, "%s/%s", pkglib_path, "llvmjit_types.bc");
    1003              : 
    1004              :     /* open file */
    1005           95 :     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           95 :     if (LLVMParseBitcodeInContext2(llvm_context, buf, &llvm_types_module))
    1013              :     {
    1014            0 :         elog(ERROR, "LLVMParseBitcodeInContext2 of %s failed", path);
    1015              :     }
    1016           95 :     LLVMDisposeMemoryBuffer(buf);
    1017              : 
    1018           95 :     TypeSizeT = llvm_pg_var_type("TypeSizeT");
    1019           95 :     TypeDatum = llvm_pg_var_type("TypeDatum");
    1020           95 :     TypeParamBool = load_return_type(llvm_types_module, "FunctionReturningBool");
    1021           95 :     TypeStorageBool = llvm_pg_var_type("TypeStorageBool");
    1022           95 :     TypePGFunction = llvm_pg_var_type("TypePGFunction");
    1023           95 :     StructNullableDatum = llvm_pg_var_type("StructNullableDatum");
    1024           95 :     StructExprContext = llvm_pg_var_type("StructExprContext");
    1025           95 :     StructExprEvalStep = llvm_pg_var_type("StructExprEvalStep");
    1026           95 :     StructExprState = llvm_pg_var_type("StructExprState");
    1027           95 :     StructFunctionCallInfoData = llvm_pg_var_type("StructFunctionCallInfoData");
    1028           95 :     StructMemoryContextData = llvm_pg_var_type("StructMemoryContextData");
    1029           95 :     StructTupleTableSlot = llvm_pg_var_type("StructTupleTableSlot");
    1030           95 :     StructHeapTupleTableSlot = llvm_pg_var_type("StructHeapTupleTableSlot");
    1031           95 :     StructMinimalTupleTableSlot = llvm_pg_var_type("StructMinimalTupleTableSlot");
    1032           95 :     StructHeapTupleData = llvm_pg_var_type("StructHeapTupleData");
    1033           95 :     StructHeapTupleHeaderData = llvm_pg_var_type("StructHeapTupleHeaderData");
    1034           95 :     StructTupleDescData = llvm_pg_var_type("StructTupleDescData");
    1035           95 :     StructAggState = llvm_pg_var_type("StructAggState");
    1036           95 :     StructAggStatePerGroupData = llvm_pg_var_type("StructAggStatePerGroupData");
    1037           95 :     StructAggStatePerTransData = llvm_pg_var_type("StructAggStatePerTransData");
    1038           95 :     StructPlanState = llvm_pg_var_type("StructPlanState");
    1039           95 :     StructMinimalTupleData = llvm_pg_var_type("StructMinimalTupleData");
    1040              : 
    1041           95 :     AttributeTemplate = LLVMGetNamedFunction(llvm_types_module, "AttributeTemplate");
    1042           95 :     ExecEvalSubroutineTemplate = LLVMGetNamedFunction(llvm_types_module, "ExecEvalSubroutineTemplate");
    1043           95 :     ExecEvalBoolSubroutineTemplate = LLVMGetNamedFunction(llvm_types_module, "ExecEvalBoolSubroutineTemplate");
    1044           95 : }
    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         6373 : llvm_split_symbol_name(const char *name, char **modname, char **funcname)
    1052              : {
    1053         6373 :     *modname = NULL;
    1054         6373 :     *funcname = NULL;
    1055              : 
    1056              :     /*
    1057              :      * Module function names are pgextern.$module.$funcname
    1058              :      */
    1059         6373 :     if (strncmp(name, "pgextern.", strlen("pgextern.")) == 0)
    1060              :     {
    1061              :         /*
    1062              :          * Symbol names cannot contain a ., therefore we can split based on
    1063              :          * first and last occurrence of one.
    1064              :          */
    1065            0 :         *funcname = strrchr(name, '.');
    1066            0 :         (*funcname)++;          /* jump over . */
    1067              : 
    1068            0 :         *modname = pnstrdup(name + strlen("pgextern."),
    1069            0 :                             *funcname - name - strlen("pgextern.") - 1);
    1070              :         Assert(funcname);
    1071              : 
    1072            0 :         *funcname = pstrdup(*funcname);
    1073              :     }
    1074              :     else
    1075              :     {
    1076         6373 :         *modname = NULL;
    1077         6373 :         *funcname = pstrdup(name);
    1078              :     }
    1079         6373 : }
    1080              : 
    1081              : /*
    1082              :  * Attempt to resolve symbol, so LLVM can emit a reference to it.
    1083              :  */
    1084              : static uint64_t
    1085            0 : llvm_resolve_symbol(const char *symname, void *ctx)
    1086              : {
    1087              :     uintptr_t   addr;
    1088              :     char       *funcname;
    1089              :     char       *modname;
    1090              : 
    1091              :     /*
    1092              :      * macOS prefixes all object level symbols with an underscore. But neither
    1093              :      * dlsym() nor PG's inliner expect that. So undo.
    1094              :      */
    1095              : #if defined(__darwin__)
    1096              :     if (symname[0] != '_')
    1097              :         elog(ERROR, "expected prefixed symbol name, but got \"%s\"", symname);
    1098              :     symname++;
    1099              : #endif
    1100              : 
    1101            0 :     llvm_split_symbol_name(symname, &modname, &funcname);
    1102              : 
    1103              :     /* functions that aren't resolved to names shouldn't ever get here */
    1104              :     Assert(funcname);
    1105              : 
    1106            0 :     if (modname)
    1107            0 :         addr = (uintptr_t) load_external_function(modname, funcname,
    1108              :                                                   true, NULL);
    1109              :     else
    1110            0 :         addr = (uintptr_t) LLVMSearchForAddressOfSymbol(symname);
    1111              : 
    1112            0 :     pfree(funcname);
    1113            0 :     if (modname)
    1114            0 :         pfree(modname);
    1115              : 
    1116              :     /* let LLVM will error out - should never happen */
    1117            0 :     if (!addr)
    1118            0 :         elog(WARNING, "failed to resolve name %s", symname);
    1119              : 
    1120            0 :     return (uint64_t) addr;
    1121              : }
    1122              : 
    1123              : static LLVMErrorRef
    1124            0 : llvm_resolve_symbols(LLVMOrcDefinitionGeneratorRef GeneratorObj, void *Ctx,
    1125              :                      LLVMOrcLookupStateRef *LookupState, LLVMOrcLookupKind Kind,
    1126              :                      LLVMOrcJITDylibRef JD, LLVMOrcJITDylibLookupFlags JDLookupFlags,
    1127              :                      LLVMOrcCLookupSet LookupSet, size_t LookupSetSize)
    1128              : {
    1129              : #if LLVM_VERSION_MAJOR > 14
    1130            0 :     LLVMOrcCSymbolMapPairs symbols = palloc0_array(LLVMOrcCSymbolMapPair, LookupSetSize);
    1131              : #else
    1132              :     LLVMOrcCSymbolMapPairs symbols = palloc0_array(LLVMJITCSymbolMapPair, LookupSetSize);
    1133              : #endif
    1134              :     LLVMErrorRef error;
    1135              :     LLVMOrcMaterializationUnitRef mu;
    1136              : 
    1137            0 :     for (int i = 0; i < LookupSetSize; i++)
    1138              :     {
    1139            0 :         const char *name = LLVMOrcSymbolStringPoolEntryStr(LookupSet[i].Name);
    1140              : 
    1141            0 :         LLVMOrcRetainSymbolStringPoolEntry(LookupSet[i].Name);
    1142            0 :         symbols[i].Name = LookupSet[i].Name;
    1143            0 :         symbols[i].Sym.Address = llvm_resolve_symbol(name, NULL);
    1144            0 :         symbols[i].Sym.Flags.GenericFlags = LLVMJITSymbolGenericFlagsExported;
    1145              :     }
    1146              : 
    1147            0 :     mu = LLVMOrcAbsoluteSymbols(symbols, LookupSetSize);
    1148            0 :     error = LLVMOrcJITDylibDefine(JD, mu);
    1149            0 :     if (error != LLVMErrorSuccess)
    1150            0 :         LLVMOrcDisposeMaterializationUnit(mu);
    1151              : 
    1152            0 :     pfree(symbols);
    1153              : 
    1154            0 :     return error;
    1155              : }
    1156              : 
    1157              : /*
    1158              :  * We cannot throw errors through LLVM (without causing a FATAL at least), so
    1159              :  * just use WARNING here. That's OK anyway, as the error is also reported at
    1160              :  * the top level action (with less detail) and there might be multiple
    1161              :  * invocations of errors with details.
    1162              :  *
    1163              :  * This doesn't really happen during normal operation, but in cases like
    1164              :  * symbol resolution breakage. So just using elog(WARNING) is fine.
    1165              :  */
    1166              : static void
    1167            0 : llvm_log_jit_error(void *ctx, LLVMErrorRef error)
    1168              : {
    1169            0 :     elog(WARNING, "error during JITing: %s",
    1170              :          llvm_error_message(error));
    1171            0 : }
    1172              : 
    1173              : /*
    1174              :  * Create our own object layer, so we can add event listeners.
    1175              :  */
    1176              : static LLVMOrcObjectLayerRef
    1177          190 : llvm_create_object_layer(void *Ctx, LLVMOrcExecutionSessionRef ES, const char *Triple)
    1178              : {
    1179              : #ifdef USE_LLVM_BACKPORT_SECTION_MEMORY_MANAGER
    1180              :     LLVMOrcObjectLayerRef objlayer =
    1181              :         LLVMOrcCreateRTDyldObjectLinkingLayerWithSafeSectionMemoryManager(ES);
    1182              : #else
    1183              :     LLVMOrcObjectLayerRef objlayer =
    1184          190 :         LLVMOrcCreateRTDyldObjectLinkingLayerWithSectionMemoryManager(ES);
    1185              : #endif
    1186              : 
    1187          190 :     if (jit_debugging_support)
    1188              :     {
    1189            0 :         LLVMJITEventListenerRef l = LLVMCreateGDBRegistrationListener();
    1190              : 
    1191            0 :         LLVMOrcRTDyldObjectLinkingLayerRegisterJITEventListener(objlayer, l);
    1192              :     }
    1193              : 
    1194          190 :     if (jit_profiling_support)
    1195              :     {
    1196            0 :         LLVMJITEventListenerRef l = LLVMCreatePerfJITEventListener();
    1197              : 
    1198            0 :         if (l)
    1199            0 :             LLVMOrcRTDyldObjectLinkingLayerRegisterJITEventListener(objlayer, l);
    1200              :     }
    1201              : 
    1202          190 :     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          190 : 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          190 :     lljit_builder = LLVMOrcCreateLLJITBuilder();
    1220          190 :     tm_builder = LLVMOrcJITTargetMachineBuilderCreateFromTargetMachine(tm);
    1221          190 :     LLVMOrcLLJITBuilderSetJITTargetMachineBuilder(lljit_builder, tm_builder);
    1222              : 
    1223          190 :     LLVMOrcLLJITBuilderSetObjectLinkingLayerCreator(lljit_builder,
    1224              :                                                     llvm_create_object_layer,
    1225              :                                                     NULL);
    1226              : 
    1227          190 :     error = LLVMOrcCreateLLJIT(&lljit, lljit_builder);
    1228          190 :     if (error)
    1229            0 :         elog(ERROR, "failed to create lljit instance: %s",
    1230              :              llvm_error_message(error));
    1231              : 
    1232          190 :     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          190 :     error = LLVMOrcCreateDynamicLibrarySearchGeneratorForProcess(&main_gen,
    1240          190 :                                                                  LLVMOrcLLJITGetGlobalPrefix(lljit),
    1241              :                                                                  0, NULL);
    1242          190 :     if (error)
    1243            0 :         elog(ERROR, "failed to create generator: %s",
    1244              :              llvm_error_message(error));
    1245          190 :     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          190 :     ref_gen = LLVMOrcCreateCustomCAPIDefinitionGenerator(llvm_resolve_symbols, NULL, NULL);
    1253              : #else
    1254              :     ref_gen = LLVMOrcCreateCustomCAPIDefinitionGenerator(llvm_resolve_symbols, NULL);
    1255              : #endif
    1256          190 :     LLVMOrcJITDylibAddGenerator(LLVMOrcLLJITGetMainJITDylib(lljit), ref_gen);
    1257              : 
    1258          190 :     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            8 : ResOwnerReleaseJitContext(Datum res)
    1277              : {
    1278            8 :     LLVMJitContext *context = (LLVMJitContext *) DatumGetPointer(res);
    1279              : 
    1280            8 :     context->resowner = NULL;
    1281            8 :     jit_release_context(&context->base);
    1282            8 : }
        

Generated by: LCOV version 2.0-1