LCOV - code coverage report
Current view: top level - src/backend/jit/llvm - llvmjit.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 0.0 % 377 0
Test Date: 2026-07-03 19:57:34 Functions: 0.0 % 31 0
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 0.0 % 166 0

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

Generated by: LCOV version 2.0-1