LCOV - code coverage report
Current view: top level - src/backend/jit/llvm - llvmjit.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 0.0 % 377 0
Test Date: 2026-04-07 14:16:30 Functions: 0.0 % 31 0
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            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            0 :     *modname = NULL;
    1054            0 :     *funcname = NULL;
    1055              : 
    1056              :     /*
    1057              :      * Module function names are pgextern.$module.$funcname
    1058              :      */
    1059            0 :     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            0 :         *modname = NULL;
    1077            0 :         *funcname = pstrdup(name);
    1078              :     }
    1079            0 : }
    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            0 : llvm_create_object_layer(void *Ctx, LLVMOrcExecutionSessionRef ES, const char *Triple)
    1178              : {
    1179              : #if LLVM_VERSION_MAJOR >= 22
    1180              :     LLVMOrcObjectLayerRef objlayer =
    1181              :         LLVMOrcCreateRTDyldObjectLinkingLayerWithSectionMemoryManagerReserveAlloc(ES, true);
    1182              : #elif defined(USE_LLVM_BACKPORT_SECTION_MEMORY_MANAGER)
    1183              :     LLVMOrcObjectLayerRef objlayer =
    1184              :         LLVMOrcCreateRTDyldObjectLinkingLayerWithSafeSectionMemoryManager(ES);
    1185              : #else
    1186              :     LLVMOrcObjectLayerRef objlayer =
    1187            0 :         LLVMOrcCreateRTDyldObjectLinkingLayerWithSectionMemoryManager(ES);
    1188              : #endif
    1189              : 
    1190            0 :     if (jit_debugging_support)
    1191              :     {
    1192            0 :         LLVMJITEventListenerRef l = LLVMCreateGDBRegistrationListener();
    1193              : 
    1194            0 :         LLVMOrcRTDyldObjectLinkingLayerRegisterJITEventListener(objlayer, l);
    1195              :     }
    1196              : 
    1197            0 :     if (jit_profiling_support)
    1198              :     {
    1199            0 :         LLVMJITEventListenerRef l = LLVMCreatePerfJITEventListener();
    1200              : 
    1201            0 :         if (l)
    1202            0 :             LLVMOrcRTDyldObjectLinkingLayerRegisterJITEventListener(objlayer, l);
    1203              :     }
    1204              : 
    1205            0 :     return objlayer;
    1206              : }
    1207              : 
    1208              : /*
    1209              :  * Create LLJIT instance, using the passed in target machine. Note that the
    1210              :  * target machine afterwards is owned by the LLJIT instance.
    1211              :  */
    1212              : static LLVMOrcLLJITRef
    1213            0 : llvm_create_jit_instance(LLVMTargetMachineRef tm)
    1214              : {
    1215              :     LLVMOrcLLJITRef lljit;
    1216              :     LLVMOrcJITTargetMachineBuilderRef tm_builder;
    1217              :     LLVMOrcLLJITBuilderRef lljit_builder;
    1218              :     LLVMErrorRef error;
    1219              :     LLVMOrcDefinitionGeneratorRef main_gen;
    1220              :     LLVMOrcDefinitionGeneratorRef ref_gen;
    1221              : 
    1222            0 :     lljit_builder = LLVMOrcCreateLLJITBuilder();
    1223            0 :     tm_builder = LLVMOrcJITTargetMachineBuilderCreateFromTargetMachine(tm);
    1224            0 :     LLVMOrcLLJITBuilderSetJITTargetMachineBuilder(lljit_builder, tm_builder);
    1225              : 
    1226            0 :     LLVMOrcLLJITBuilderSetObjectLinkingLayerCreator(lljit_builder,
    1227              :                                                     llvm_create_object_layer,
    1228              :                                                     NULL);
    1229              : 
    1230            0 :     error = LLVMOrcCreateLLJIT(&lljit, lljit_builder);
    1231            0 :     if (error)
    1232            0 :         elog(ERROR, "failed to create lljit instance: %s",
    1233              :              llvm_error_message(error));
    1234              : 
    1235            0 :     LLVMOrcExecutionSessionSetErrorReporter(LLVMOrcLLJITGetExecutionSession(lljit),
    1236              :                                             llvm_log_jit_error, NULL);
    1237              : 
    1238              :     /*
    1239              :      * Symbol resolution support for symbols in the postgres binary /
    1240              :      * libraries already loaded.
    1241              :      */
    1242            0 :     error = LLVMOrcCreateDynamicLibrarySearchGeneratorForProcess(&main_gen,
    1243            0 :                                                                  LLVMOrcLLJITGetGlobalPrefix(lljit),
    1244              :                                                                  0, NULL);
    1245            0 :     if (error)
    1246            0 :         elog(ERROR, "failed to create generator: %s",
    1247              :              llvm_error_message(error));
    1248            0 :     LLVMOrcJITDylibAddGenerator(LLVMOrcLLJITGetMainJITDylib(lljit), main_gen);
    1249              : 
    1250              :     /*
    1251              :      * Symbol resolution support for "special" functions, e.g. a call into an
    1252              :      * SQL callable function.
    1253              :      */
    1254              : #if LLVM_VERSION_MAJOR > 14
    1255            0 :     ref_gen = LLVMOrcCreateCustomCAPIDefinitionGenerator(llvm_resolve_symbols, NULL, NULL);
    1256              : #else
    1257              :     ref_gen = LLVMOrcCreateCustomCAPIDefinitionGenerator(llvm_resolve_symbols, NULL);
    1258              : #endif
    1259            0 :     LLVMOrcJITDylibAddGenerator(LLVMOrcLLJITGetMainJITDylib(lljit), ref_gen);
    1260              : 
    1261            0 :     return lljit;
    1262              : }
    1263              : 
    1264              : static char *
    1265            0 : llvm_error_message(LLVMErrorRef error)
    1266              : {
    1267            0 :     char       *orig = LLVMGetErrorMessage(error);
    1268            0 :     char       *msg = pstrdup(orig);
    1269              : 
    1270            0 :     LLVMDisposeErrorMessage(orig);
    1271              : 
    1272            0 :     return msg;
    1273              : }
    1274              : 
    1275              : /*
    1276              :  * ResourceOwner callbacks
    1277              :  */
    1278              : static void
    1279            0 : ResOwnerReleaseJitContext(Datum res)
    1280              : {
    1281            0 :     LLVMJitContext *context = (LLVMJitContext *) DatumGetPointer(res);
    1282              : 
    1283            0 :     context->resowner = NULL;
    1284            0 :     jit_release_context(&context->base);
    1285            0 : }
        

Generated by: LCOV version 2.0-1