LCOV - code coverage report
Current view: top level - src/backend/jit/llvm - llvmjit.c (source / functions) Hit Total Coverage
Test: PostgreSQL 19devel Lines: 300 377 79.6 %
Date: 2026-02-02 23:17:55 Functions: 27 31 87.1 %
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         924 : ResourceOwnerRememberJIT(ResourceOwner owner, LLVMJitContext *handle)
     133             : {
     134         924 :     ResourceOwnerRemember(owner, PointerGetDatum(handle), &jit_resowner_desc);
     135         924 : }
     136             : static inline void
     137         908 : ResourceOwnerForgetJIT(ResourceOwner owner, LLVMJitContext *handle)
     138             : {
     139         908 :     ResourceOwnerForget(owner, PointerGetDatum(handle), &jit_resowner_desc);
     140         908 : }
     141             : 
     142        1614 : PG_MODULE_MAGIC_EXT(
     143             :                     .name = "llvmjit",
     144             :                     .version = PG_VERSION
     145             : );
     146             : 
     147             : 
     148             : /*
     149             :  * Initialize LLVM JIT provider.
     150             :  */
     151             : void
     152         186 : _PG_jit_provider_init(JitProviderCallbacks *cb)
     153             : {
     154         186 :     cb->reset_after_error = llvm_reset_after_error;
     155         186 :     cb->release_context = llvm_release_context;
     156         186 :     cb->compile_expr = llvm_compile_expr;
     157         186 : }
     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         924 : llvm_recreate_llvm_context(void)
     175             : {
     176         924 :     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         924 :     if (llvm_jit_context_in_use_count > 0)
     184             :     {
     185           0 :         llvm_llvm_context_reuse_count++;
     186           0 :         return;
     187             :     }
     188             : 
     189         924 :     if (llvm_llvm_context_reuse_count <= LLVMJIT_LLVM_CONTEXT_REUSE_MAX)
     190             :     {
     191         924 :         llvm_llvm_context_reuse_count++;
     192         924 :         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         924 : llvm_create_context(int jitFlags)
     225             : {
     226             :     LLVMJitContext *context;
     227             : 
     228         924 :     llvm_assert_in_fatal_section();
     229             : 
     230         924 :     llvm_session_initialize();
     231             : 
     232         924 :     llvm_recreate_llvm_context();
     233             : 
     234         924 :     ResourceOwnerEnlarge(CurrentResourceOwner);
     235             : 
     236         924 :     context = MemoryContextAllocZero(TopMemoryContext,
     237             :                                      sizeof(LLVMJitContext));
     238         924 :     context->base.flags = jitFlags;
     239             : 
     240             :     /* ensure cleanup */
     241         924 :     context->resowner = CurrentResourceOwner;
     242         924 :     ResourceOwnerRememberJIT(CurrentResourceOwner, context);
     243             : 
     244         924 :     llvm_jit_context_in_use_count++;
     245             : 
     246         924 :     return context;
     247             : }
     248             : 
     249             : /*
     250             :  * Release resources required by one llvm context.
     251             :  */
     252             : static void
     253         924 : llvm_release_context(JitContext *context)
     254             : {
     255         924 :     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         924 :     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         924 :     if (proc_exit_inprogress)
     270           0 :         return;
     271             : 
     272         924 :     llvm_enter_fatal_on_oom();
     273             : 
     274         924 :     if (llvm_jit_context->module)
     275             :     {
     276         364 :         LLVMDisposeModule(llvm_jit_context->module);
     277         364 :         llvm_jit_context->module = NULL;
     278             :     }
     279             : 
     280        1568 :     foreach(lc, llvm_jit_context->handles)
     281             :     {
     282         644 :         LLVMJitHandle *jit_handle = (LLVMJitHandle *) lfirst(lc);
     283             : 
     284             :         {
     285             :             LLVMOrcExecutionSessionRef ee;
     286             :             LLVMOrcSymbolStringPoolRef sp;
     287             : 
     288         644 :             LLVMOrcResourceTrackerRemove(jit_handle->resource_tracker);
     289         644 :             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         644 :             ee = LLVMOrcLLJITGetExecutionSession(jit_handle->lljit);
     298         644 :             sp = LLVMOrcExecutionSessionGetSymbolStringPool(ee);
     299         644 :             LLVMOrcSymbolStringPoolClearDeadEntries(sp);
     300             :         }
     301             : 
     302         644 :         pfree(jit_handle);
     303             :     }
     304         924 :     list_free(llvm_jit_context->handles);
     305         924 :     llvm_jit_context->handles = NIL;
     306             : 
     307         924 :     llvm_leave_fatal_on_oom();
     308             : 
     309         924 :     if (llvm_jit_context->resowner)
     310         908 :         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       11198 : llvm_mutable_module(LLVMJitContext *context)
     318             : {
     319       11198 :     llvm_assert_in_fatal_section();
     320             : 
     321             :     /*
     322             :      * If there's no in-progress module, create a new one.
     323             :      */
     324       11198 :     if (!context->module)
     325             :     {
     326        1008 :         context->compiled = false;
     327        1008 :         context->module_generation = llvm_generation++;
     328        1008 :         context->module = LLVMModuleCreateWithNameInContext("pg", llvm_context);
     329        1008 :         LLVMSetTarget(context->module, llvm_triple);
     330        1008 :         LLVMSetDataLayout(context->module, llvm_layout);
     331             :     }
     332             : 
     333       11198 :     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       11198 : llvm_expand_funcname(struct LLVMJitContext *context, const char *basename)
     343             : {
     344             :     Assert(context->module != NULL);
     345             : 
     346       11198 :     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       22396 :     return psprintf("%s_%zu_%d",
     353             :                     basename,
     354             :                     context->module_generation,
     355       11198 :                     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        3694 : llvm_get_function(LLVMJitContext *context, const char *funcname)
     364             : {
     365             :     ListCell   *lc;
     366             : 
     367        3694 :     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        3694 :     if (!context->compiled)
     374             :     {
     375         644 :         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        3694 :     foreach(lc, context->handles)
     384             :     {
     385        3694 :         LLVMJitHandle *handle = (LLVMJitHandle *) lfirst(lc);
     386             :         instr_time  starttime;
     387             :         instr_time  endtime;
     388             :         LLVMErrorRef error;
     389             :         LLVMOrcJITTargetAddress addr;
     390             : 
     391        3694 :         INSTR_TIME_SET_CURRENT(starttime);
     392             : 
     393        3694 :         addr = 0;
     394        3694 :         error = LLVMOrcLLJITLookup(handle->lljit, &addr, funcname);
     395        3694 :         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        3694 :         INSTR_TIME_SET_CURRENT(endtime);
     406        3694 :         INSTR_TIME_ACCUM_DIFF(context->base.instr.emission_counter,
     407             :                               endtime, starttime);
     408             : 
     409        3694 :         if (addr)
     410        3694 :             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        3966 : 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        3966 :     v_srcvar = LLVMGetNamedGlobal(llvm_types_module, varname);
     430        3966 :     if (!v_srcvar)
     431           0 :         elog(ERROR, "variable %s not in llvmjit_types.c", varname);
     432             : 
     433        3966 :     typ = LLVMGlobalGetValueType(v_srcvar);
     434             : 
     435        3966 :     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       10270 : llvm_pg_var_func_type(const char *varname)
     444             : {
     445             :     LLVMValueRef v_srcvar;
     446             :     LLVMTypeRef typ;
     447             : 
     448       10270 :     v_srcvar = LLVMGetNamedFunction(llvm_types_module, varname);
     449       10270 :     if (!v_srcvar)
     450           0 :         elog(ERROR, "function %s not in llvmjit_types.c", varname);
     451             : 
     452       10270 :     typ = LLVMGetFunctionType(v_srcvar);
     453             : 
     454       10270 :     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       11040 : 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       11040 :     v_fn = LLVMGetNamedFunction(mod, funcname);
     472       11040 :     if (v_fn)
     473        8180 :         return v_fn;
     474             : 
     475        2860 :     v_srcfn = LLVMGetNamedFunction(llvm_types_module, funcname);
     476             : 
     477        2860 :     if (!v_srcfn)
     478           0 :         elog(ERROR, "function %s not in llvmjit_types.c", funcname);
     479             : 
     480        2860 :     v_fn = LLVMAddFunction(mod,
     481             :                            funcname,
     482             :                            LLVMGetFunctionType(v_srcfn));
     483        2860 :     llvm_copy_attributes(v_srcfn, v_fn);
     484             : 
     485        2860 :     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       40098 : llvm_copy_attributes_at_index(LLVMValueRef v_from, LLVMValueRef v_to, uint32 index)
     494             : {
     495             :     int         num_attributes;
     496             :     LLVMAttributeRef *attrs;
     497             : 
     498       40098 :     num_attributes = LLVMGetAttributeCountAtIndex(v_from, index);
     499             : 
     500       40098 :     if (num_attributes == 0)
     501         564 :         return;
     502             : 
     503       39534 :     attrs = palloc_array(LLVMAttributeRef, num_attributes);
     504       39534 :     LLVMGetAttributesAtIndex(v_from, index, attrs);
     505             : 
     506      258550 :     for (int attno = 0; attno < num_attributes; attno++)
     507      219016 :         LLVMAddAttributeAtIndex(v_to, index, attrs[attno]);
     508             : 
     509       39534 :     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       14058 : llvm_copy_attributes(LLVMValueRef v_from, LLVMValueRef v_to)
     518             : {
     519             :     uint32      param_count;
     520             : 
     521             :     /* copy function attributes */
     522       14058 :     llvm_copy_attributes_at_index(v_from, v_to, LLVMAttributeFunctionIndex);
     523             : 
     524       14058 :     if (LLVMGetTypeKind(LLVMGetFunctionReturnType(v_to)) != LLVMVoidTypeKind)
     525             :     {
     526             :         /* and the return value attributes */
     527        7584 :         llvm_copy_attributes_at_index(v_from, v_to, LLVMAttributeReturnIndex);
     528             :     }
     529             : 
     530             :     /* and each function parameter's attribute */
     531       14058 :     param_count = LLVMCountParams(v_from);
     532             : 
     533       32514 :     for (int paramidx = 1; paramidx <= param_count; paramidx++)
     534       18456 :         llvm_copy_attributes_at_index(v_from, v_to, paramidx);
     535       14058 : }
     536             : 
     537             : /*
     538             :  * Return a callable LLVMValueRef for fcinfo.
     539             :  */
     540             : LLVMValueRef
     541        5158 : 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        5158 :     fmgr_symbol(fcinfo->flinfo->fn_oid, &modname, &basename);
     553             : 
     554        5158 :     if (modname != NULL && basename != NULL)
     555             :     {
     556             :         /* external function in loadable library */
     557           0 :         funcname = psprintf("pgextern.%s.%s", modname, basename);
     558             :     }
     559        5158 :     else if (basename != NULL)
     560             :     {
     561             :         /* internal function */
     562        5146 :         funcname = pstrdup(basename);
     563             :     }
     564             :     else
     565             :     {
     566             :         /*
     567             :          * Function we don't know to handle, return pointer. We do so by
     568             :          * creating a global constant containing a pointer to the function.
     569             :          * Makes IR more readable.
     570             :          */
     571             :         LLVMValueRef v_fn_addr;
     572             : 
     573          12 :         funcname = psprintf("pgoidextern.%u",
     574          12 :                             fcinfo->flinfo->fn_oid);
     575          12 :         v_fn = LLVMGetNamedGlobal(mod, funcname);
     576          12 :         if (v_fn != 0)
     577           0 :             return l_load(builder, TypePGFunction, v_fn, "");
     578             : 
     579          12 :         v_fn_addr = l_ptr_const(fcinfo->flinfo->fn_addr, TypePGFunction);
     580             : 
     581          12 :         v_fn = LLVMAddGlobal(mod, TypePGFunction, funcname);
     582          12 :         LLVMSetInitializer(v_fn, v_fn_addr);
     583          12 :         LLVMSetGlobalConstant(v_fn, true);
     584          12 :         LLVMSetLinkage(v_fn, LLVMPrivateLinkage);
     585          12 :         LLVMSetUnnamedAddr(v_fn, true);
     586             : 
     587          12 :         return l_load(builder, TypePGFunction, v_fn, "");
     588             :     }
     589             : 
     590             :     /* check if function already has been added */
     591        5146 :     v_fn = LLVMGetNamedFunction(mod, funcname);
     592        5146 :     if (v_fn != 0)
     593        2966 :         return v_fn;
     594             : 
     595        2180 :     v_fn = LLVMAddFunction(mod, funcname, LLVMGetFunctionType(AttributeTemplate));
     596             : 
     597        2180 :     return v_fn;
     598             : }
     599             : 
     600             : /*
     601             :  * Optimize code in module using the flags set in context.
     602             :  */
     603             : static void
     604         644 : 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         644 :     if (context->base.flags & PGJIT_OPT3)
     676         216 :         passes = "default<O3>";
     677         428 :     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         428 :         passes = "default<O0>,mem2reg";
     683             : 
     684         644 :     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         644 :     LLVMPassBuilderOptionsSetInlinerThreshold(options, 512);
     696             : 
     697         644 :     err = LLVMRunPasses(module, passes, NULL, options);
     698             : 
     699         644 :     if (err)
     700           0 :         elog(ERROR, "failed to JIT module: %s", llvm_error_message(err));
     701             : 
     702         644 :     LLVMDisposePassBuilderOptions(options);
     703             : #endif
     704         644 : }
     705             : 
     706             : /*
     707             :  * Emit code for the currently pending module.
     708             :  */
     709             : static void
     710         644 : 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         644 :     if (context->base.flags & PGJIT_OPT3)
     719         216 :         compile_orc = llvm_opt3_orc;
     720             :     else
     721         428 :         compile_orc = llvm_opt0_orc;
     722             : 
     723             :     /* perform inlining */
     724         644 :     if (context->base.flags & PGJIT_INLINE)
     725             :     {
     726         216 :         INSTR_TIME_SET_CURRENT(starttime);
     727         216 :         llvm_inline(context->module);
     728         216 :         INSTR_TIME_SET_CURRENT(endtime);
     729         216 :         INSTR_TIME_ACCUM_DIFF(context->base.instr.inlining_counter,
     730             :                               endtime, starttime);
     731             :     }
     732             : 
     733         644 :     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         644 :     INSTR_TIME_SET_CURRENT(starttime);
     747         644 :     llvm_optimize_module(context, context->module);
     748         644 :     INSTR_TIME_SET_CURRENT(endtime);
     749         644 :     INSTR_TIME_ACCUM_DIFF(context->base.instr.optimization_counter,
     750             :                           endtime, starttime);
     751             : 
     752         644 :     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         644 :         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         644 :     INSTR_TIME_SET_CURRENT(starttime);
     773             :     {
     774             :         LLVMOrcThreadSafeModuleRef ts_module;
     775             :         LLVMErrorRef error;
     776         644 :         LLVMOrcJITDylibRef jd = LLVMOrcLLJITGetMainJITDylib(compile_orc);
     777             : 
     778         644 :         ts_module = LLVMOrcCreateNewThreadSafeModule(context->module, llvm_ts_context);
     779             : 
     780         644 :         handle->lljit = compile_orc;
     781         644 :         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         644 :         context->module = NULL; /* will be owned by LLJIT */
     790         644 :         error = LLVMOrcLLJITAddLLVMIRModuleWithRT(compile_orc,
     791             :                                                   handle->resource_tracker,
     792             :                                                   ts_module);
     793             : 
     794         644 :         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         644 :     INSTR_TIME_SET_CURRENT(endtime);
     802         644 :     INSTR_TIME_ACCUM_DIFF(context->base.instr.emission_counter,
     803             :                           endtime, starttime);
     804             : 
     805         644 :     context->module = NULL;
     806         644 :     context->compiled = true;
     807             : 
     808             :     /* remember emitted code for cleanup and lookups */
     809         644 :     oldcontext = MemoryContextSwitchTo(TopMemoryContext);
     810         644 :     context->handles = lappend(context->handles, handle);
     811         644 :     MemoryContextSwitchTo(oldcontext);
     812             : 
     813         644 :     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         644 : }
     821             : 
     822             : /*
     823             :  * Per session initialization.
     824             :  */
     825             : static void
     826         924 : llvm_session_initialize(void)
     827             : {
     828             :     MemoryContext oldcontext;
     829         924 :     char       *error = NULL;
     830         924 :     char       *cpu = NULL;
     831         924 :     char       *features = NULL;
     832             :     LLVMTargetMachineRef opt0_tm;
     833             :     LLVMTargetMachineRef opt3_tm;
     834             : 
     835         924 :     if (llvm_session_initialized)
     836         738 :         return;
     837             : 
     838         186 :     oldcontext = MemoryContextSwitchTo(TopMemoryContext);
     839             : 
     840         186 :     LLVMInitializeNativeTarget();
     841         186 :     LLVMInitializeNativeAsmPrinter();
     842         186 :     LLVMInitializeNativeAsmParser();
     843             : 
     844         186 :     if (llvm_context == NULL)
     845             :     {
     846         186 :         llvm_context = LLVMContextCreate();
     847             : 
     848         186 :         llvm_jit_context_in_use_count = 0;
     849         186 :         llvm_llvm_context_reuse_count = 0;
     850             :     }
     851             : 
     852             :     /*
     853             :      * Synchronize types early, as that also includes inferring the target
     854             :      * triple.
     855             :      */
     856         186 :     llvm_create_types();
     857             : 
     858             :     /*
     859             :      * Extract target information from loaded module.
     860             :      */
     861         186 :     llvm_set_target();
     862             : 
     863         186 :     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         186 :     cpu = LLVMGetHostCPUName();
     875         186 :     features = LLVMGetHostCPUFeatures();
     876         186 :     elog(DEBUG2, "LLVMJIT detected CPU \"%s\", with features \"%s\"",
     877             :          cpu, features);
     878             : 
     879             :     opt0_tm =
     880         186 :         LLVMCreateTargetMachine(llvm_targetref, llvm_triple, cpu, features,
     881             :                                 LLVMCodeGenLevelNone,
     882             :                                 LLVMRelocDefault,
     883             :                                 LLVMCodeModelJITDefault);
     884             :     opt3_tm =
     885         186 :         LLVMCreateTargetMachine(llvm_targetref, llvm_triple, cpu, features,
     886             :                                 LLVMCodeGenLevelAggressive,
     887             :                                 LLVMRelocDefault,
     888             :                                 LLVMCodeModelJITDefault);
     889             : 
     890         186 :     LLVMDisposeMessage(cpu);
     891         186 :     cpu = NULL;
     892         186 :     LLVMDisposeMessage(features);
     893         186 :     features = NULL;
     894             : 
     895             :     /* force symbols in main binary to be loaded */
     896         186 :     LLVMLoadLibraryPermanently(NULL);
     897             : 
     898             :     {
     899         186 :         llvm_ts_context = LLVMOrcCreateNewThreadSafeContext();
     900             : 
     901         186 :         llvm_opt0_orc = llvm_create_jit_instance(opt0_tm);
     902         186 :         opt0_tm = 0;
     903             : 
     904         186 :         llvm_opt3_orc = llvm_create_jit_instance(opt3_tm);
     905         186 :         opt3_tm = 0;
     906             :     }
     907             : 
     908         186 :     on_proc_exit(llvm_shutdown, 0);
     909             : 
     910         186 :     llvm_session_initialized = true;
     911             : 
     912         186 :     MemoryContextSwitchTo(oldcontext);
     913             : }
     914             : 
     915             : static void
     916         186 : 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         186 :     if (llvm_in_fatal_on_oom())
     927             :     {
     928             :         Assert(proc_exit_inprogress);
     929           0 :         return;
     930             :     }
     931             : 
     932         186 :     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         186 :         if (llvm_opt3_orc)
     938             :         {
     939         186 :             LLVMOrcDisposeLLJIT(llvm_opt3_orc);
     940         186 :             llvm_opt3_orc = NULL;
     941             :         }
     942         186 :         if (llvm_opt0_orc)
     943             :         {
     944         186 :             LLVMOrcDisposeLLJIT(llvm_opt0_orc);
     945         186 :             llvm_opt0_orc = NULL;
     946             :         }
     947         186 :         if (llvm_ts_context)
     948             :         {
     949         186 :             LLVMOrcDisposeThreadSafeContext(llvm_ts_context);
     950         186 :             llvm_ts_context = NULL;
     951             :         }
     952             :     }
     953             : }
     954             : 
     955             : /* helper for llvm_create_types, returning a function's return type */
     956             : static LLVMTypeRef
     957         186 : 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         186 :     value = LLVMGetNamedFunction(mod, name);
     964         186 :     if (!value)
     965           0 :         elog(ERROR, "function %s is unknown", name);
     966             : 
     967         186 :     typ = LLVMGetFunctionReturnType(value); /* in llvmjit_wrap.cpp */
     968             : 
     969         186 :     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         186 : llvm_set_target(void)
     978             : {
     979         186 :     if (!llvm_types_module)
     980           0 :         elog(ERROR, "failed to extract target information, llvmjit_types.c not loaded");
     981             : 
     982         186 :     if (llvm_triple == NULL)
     983         186 :         llvm_triple = pstrdup(LLVMGetTarget(llvm_types_module));
     984             : 
     985         186 :     if (llvm_layout == NULL)
     986         186 :         llvm_layout = pstrdup(LLVMGetDataLayoutStr(llvm_types_module));
     987         186 : }
     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         186 : llvm_create_types(void)
     997             : {
     998             :     char        path[MAXPGPATH];
     999             :     LLVMMemoryBufferRef buf;
    1000             :     char       *msg;
    1001             : 
    1002         186 :     snprintf(path, MAXPGPATH, "%s/%s", pkglib_path, "llvmjit_types.bc");
    1003             : 
    1004             :     /* open file */
    1005         186 :     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         186 :     if (LLVMParseBitcodeInContext2(llvm_context, buf, &llvm_types_module))
    1013             :     {
    1014           0 :         elog(ERROR, "LLVMParseBitcodeInContext2 of %s failed", path);
    1015             :     }
    1016         186 :     LLVMDisposeMemoryBuffer(buf);
    1017             : 
    1018         186 :     TypeSizeT = llvm_pg_var_type("TypeSizeT");
    1019         186 :     TypeDatum = llvm_pg_var_type("TypeDatum");
    1020         186 :     TypeParamBool = load_return_type(llvm_types_module, "FunctionReturningBool");
    1021         186 :     TypeStorageBool = llvm_pg_var_type("TypeStorageBool");
    1022         186 :     TypePGFunction = llvm_pg_var_type("TypePGFunction");
    1023         186 :     StructNullableDatum = llvm_pg_var_type("StructNullableDatum");
    1024         186 :     StructExprContext = llvm_pg_var_type("StructExprContext");
    1025         186 :     StructExprEvalStep = llvm_pg_var_type("StructExprEvalStep");
    1026         186 :     StructExprState = llvm_pg_var_type("StructExprState");
    1027         186 :     StructFunctionCallInfoData = llvm_pg_var_type("StructFunctionCallInfoData");
    1028         186 :     StructMemoryContextData = llvm_pg_var_type("StructMemoryContextData");
    1029         186 :     StructTupleTableSlot = llvm_pg_var_type("StructTupleTableSlot");
    1030         186 :     StructHeapTupleTableSlot = llvm_pg_var_type("StructHeapTupleTableSlot");
    1031         186 :     StructMinimalTupleTableSlot = llvm_pg_var_type("StructMinimalTupleTableSlot");
    1032         186 :     StructHeapTupleData = llvm_pg_var_type("StructHeapTupleData");
    1033         186 :     StructHeapTupleHeaderData = llvm_pg_var_type("StructHeapTupleHeaderData");
    1034         186 :     StructTupleDescData = llvm_pg_var_type("StructTupleDescData");
    1035         186 :     StructAggState = llvm_pg_var_type("StructAggState");
    1036         186 :     StructAggStatePerGroupData = llvm_pg_var_type("StructAggStatePerGroupData");
    1037         186 :     StructAggStatePerTransData = llvm_pg_var_type("StructAggStatePerTransData");
    1038         186 :     StructPlanState = llvm_pg_var_type("StructPlanState");
    1039         186 :     StructMinimalTupleData = llvm_pg_var_type("StructMinimalTupleData");
    1040             : 
    1041         186 :     AttributeTemplate = LLVMGetNamedFunction(llvm_types_module, "AttributeTemplate");
    1042         186 :     ExecEvalSubroutineTemplate = LLVMGetNamedFunction(llvm_types_module, "ExecEvalSubroutineTemplate");
    1043         186 :     ExecEvalBoolSubroutineTemplate = LLVMGetNamedFunction(llvm_types_module, "ExecEvalBoolSubroutineTemplate");
    1044         186 : }
    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       13050 : llvm_split_symbol_name(const char *name, char **modname, char **funcname)
    1052             : {
    1053       13050 :     *modname = NULL;
    1054       13050 :     *funcname = NULL;
    1055             : 
    1056             :     /*
    1057             :      * Module function names are pgextern.$module.$funcname
    1058             :      */
    1059       13050 :     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       13050 :         *modname = NULL;
    1077       13050 :         *funcname = pstrdup(name);
    1078             :     }
    1079       13050 : }
    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         372 : 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         372 :         LLVMOrcCreateRTDyldObjectLinkingLayerWithSectionMemoryManager(ES);
    1185             : #endif
    1186             : 
    1187         372 :     if (jit_debugging_support)
    1188             :     {
    1189           0 :         LLVMJITEventListenerRef l = LLVMCreateGDBRegistrationListener();
    1190             : 
    1191           0 :         LLVMOrcRTDyldObjectLinkingLayerRegisterJITEventListener(objlayer, l);
    1192             :     }
    1193             : 
    1194         372 :     if (jit_profiling_support)
    1195             :     {
    1196           0 :         LLVMJITEventListenerRef l = LLVMCreatePerfJITEventListener();
    1197             : 
    1198           0 :         if (l)
    1199           0 :             LLVMOrcRTDyldObjectLinkingLayerRegisterJITEventListener(objlayer, l);
    1200             :     }
    1201             : 
    1202         372 :     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         372 : 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         372 :     lljit_builder = LLVMOrcCreateLLJITBuilder();
    1220         372 :     tm_builder = LLVMOrcJITTargetMachineBuilderCreateFromTargetMachine(tm);
    1221         372 :     LLVMOrcLLJITBuilderSetJITTargetMachineBuilder(lljit_builder, tm_builder);
    1222             : 
    1223         372 :     LLVMOrcLLJITBuilderSetObjectLinkingLayerCreator(lljit_builder,
    1224             :                                                     llvm_create_object_layer,
    1225             :                                                     NULL);
    1226             : 
    1227         372 :     error = LLVMOrcCreateLLJIT(&lljit, lljit_builder);
    1228         372 :     if (error)
    1229           0 :         elog(ERROR, "failed to create lljit instance: %s",
    1230             :              llvm_error_message(error));
    1231             : 
    1232         372 :     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         372 :     error = LLVMOrcCreateDynamicLibrarySearchGeneratorForProcess(&main_gen,
    1240         372 :                                                                  LLVMOrcLLJITGetGlobalPrefix(lljit),
    1241             :                                                                  0, NULL);
    1242         372 :     if (error)
    1243           0 :         elog(ERROR, "failed to create generator: %s",
    1244             :              llvm_error_message(error));
    1245         372 :     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         372 :     ref_gen = LLVMOrcCreateCustomCAPIDefinitionGenerator(llvm_resolve_symbols, NULL, NULL);
    1253             : #else
    1254             :     ref_gen = LLVMOrcCreateCustomCAPIDefinitionGenerator(llvm_resolve_symbols, NULL);
    1255             : #endif
    1256         372 :     LLVMOrcJITDylibAddGenerator(LLVMOrcLLJITGetMainJITDylib(lljit), ref_gen);
    1257             : 
    1258         372 :     return lljit;
    1259             : }
    1260             : 
    1261             : static char *
    1262           0 : llvm_error_message(LLVMErrorRef error)
    1263             : {
    1264           0 :     char       *orig = LLVMGetErrorMessage(error);
    1265           0 :     char       *msg = pstrdup(orig);
    1266             : 
    1267           0 :     LLVMDisposeErrorMessage(orig);
    1268             : 
    1269           0 :     return msg;
    1270             : }
    1271             : 
    1272             : /*
    1273             :  * ResourceOwner callbacks
    1274             :  */
    1275             : static void
    1276          16 : ResOwnerReleaseJitContext(Datum res)
    1277             : {
    1278          16 :     LLVMJitContext *context = (LLVMJitContext *) DatumGetPointer(res);
    1279             : 
    1280          16 :     context->resowner = NULL;
    1281          16 :     jit_release_context(&context->base);
    1282          16 : }

Generated by: LCOV version 1.16