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

Generated by: LCOV version 1.14