1 /*-------------------------------------------------------------------------
4 * Core part of the LLVM JIT provider.
6 * Copyright (c) 2016-2018, PostgreSQL Global Development Group
9 * src/backend/jit/llvm/llvmjit.c
11 *-------------------------------------------------------------------------
16 #include "jit/llvmjit.h"
17 #include "jit/llvmjit_emit.h"
19 #include "miscadmin.h"
21 #include "utils/memutils.h"
22 #include "utils/resowner_private.h"
23 #include "portability/instr_time.h"
24 #include "storage/ipc.h"
27 #include <llvm-c/Analysis.h>
28 #include <llvm-c/BitReader.h>
29 #include <llvm-c/BitWriter.h>
30 #include <llvm-c/Core.h>
31 #include <llvm-c/OrcBindings.h>
32 #include <llvm-c/Support.h>
33 #include <llvm-c/Target.h>
34 #include <llvm-c/Transforms/IPO.h>
35 #include <llvm-c/Transforms/PassManagerBuilder.h>
36 #include <llvm-c/Transforms/Scalar.h>
39 /* Handle of a module emitted via ORC JIT */
40 typedef struct LLVMJitHandle
42 LLVMOrcJITStackRef stack;
43 LLVMOrcModuleHandle orc_handle;
47 /* types & functions commonly needed for JITing */
48 LLVMTypeRef TypeSizeT;
49 LLVMTypeRef TypeParamBool;
50 LLVMTypeRef TypeStorageBool;
51 LLVMTypeRef TypePGFunction;
52 LLVMTypeRef StructHeapTupleFieldsField3;
53 LLVMTypeRef StructHeapTupleFields;
54 LLVMTypeRef StructHeapTupleHeaderData;
55 LLVMTypeRef StructHeapTupleDataChoice;
56 LLVMTypeRef StructHeapTupleData;
57 LLVMTypeRef StructMinimalTupleData;
58 LLVMTypeRef StructItemPointerData;
59 LLVMTypeRef StructBlockId;
60 LLVMTypeRef StructFormPgAttribute;
61 LLVMTypeRef StructTupleConstr;
62 LLVMTypeRef StructtupleDesc;
63 LLVMTypeRef StructTupleTableSlot;
64 LLVMTypeRef StructMemoryContextData;
65 LLVMTypeRef StructPGFinfoRecord;
66 LLVMTypeRef StructFmgrInfo;
67 LLVMTypeRef StructFunctionCallInfoData;
68 LLVMTypeRef StructExprContext;
69 LLVMTypeRef StructExprEvalStep;
70 LLVMTypeRef StructExprState;
71 LLVMTypeRef StructAggState;
72 LLVMTypeRef StructAggStatePerGroupData;
73 LLVMTypeRef StructAggStatePerTransData;
75 LLVMValueRef AttributeTemplate;
76 LLVMValueRef FuncStrlen;
77 LLVMValueRef FuncVarsizeAny;
78 LLVMValueRef FuncSlotGetsomeattrs;
79 LLVMValueRef FuncHeapGetsysattr;
80 LLVMValueRef FuncMakeExpandedObjectReadOnlyInternal;
81 LLVMValueRef FuncExecEvalArrayRefSubscript;
82 LLVMValueRef FuncExecAggTransReparent;
83 LLVMValueRef FuncExecAggInitGroup;
86 static bool llvm_session_initialized = false;
87 static size_t llvm_generation = 0;
88 static const char *llvm_triple = NULL;
89 static const char *llvm_layout = NULL;
92 static LLVMTargetMachineRef llvm_opt0_targetmachine;
93 static LLVMTargetMachineRef llvm_opt3_targetmachine;
95 static LLVMTargetRef llvm_targetref;
96 static LLVMOrcJITStackRef llvm_opt0_orc;
97 static LLVMOrcJITStackRef llvm_opt3_orc;
100 static void llvm_release_context(JitContext *context);
101 static void llvm_session_initialize(void);
102 static void llvm_shutdown(int code, Datum arg);
103 static void llvm_compile_module(LLVMJitContext *context);
104 static void llvm_optimize_module(LLVMJitContext *context, LLVMModuleRef module);
106 static void llvm_create_types(void);
107 static uint64_t llvm_resolve_symbol(const char *name, void *ctx);
114 * Initialize LLVM JIT provider.
117 _PG_jit_provider_init(JitProviderCallbacks *cb)
119 cb->reset_after_error = llvm_reset_after_error;
120 cb->release_context = llvm_release_context;
121 cb->compile_expr = llvm_compile_expr;
125 * Create a context for JITing work.
127 * The context, including subsidiary resources, will be cleaned up either when
128 * the context is explicitly released, or when the lifetime of
129 * CurrentResourceOwner ends (usually the end of the current [sub]xact).
132 llvm_create_context(int jitFlags)
134 LLVMJitContext *context;
136 llvm_assert_in_fatal_section();
138 llvm_session_initialize();
140 ResourceOwnerEnlargeJIT(CurrentResourceOwner);
142 context = MemoryContextAllocZero(TopMemoryContext,
143 sizeof(LLVMJitContext));
144 context->base.flags = jitFlags;
147 context->base.resowner = CurrentResourceOwner;
148 ResourceOwnerRememberJIT(CurrentResourceOwner, PointerGetDatum(context));
154 * Release resources required by one llvm context.
157 llvm_release_context(JitContext *context)
159 LLVMJitContext *llvm_context = (LLVMJitContext *) context;
161 llvm_enter_fatal_on_oom();
164 * When this backend is exiting, don't clean up LLVM. As an error might
165 * have occurred from within LLVM, we do not want to risk reentering. All
166 * resource cleanup is going to happen through process exit.
168 if (!proc_exit_inprogress)
170 if (llvm_context->module)
172 LLVMDisposeModule(llvm_context->module);
173 llvm_context->module = NULL;
176 while (llvm_context->handles != NIL)
178 LLVMJitHandle *jit_handle;
180 jit_handle = (LLVMJitHandle *) linitial(llvm_context->handles);
181 llvm_context->handles = list_delete_first(llvm_context->handles);
183 LLVMOrcRemoveModule(jit_handle->stack, jit_handle->orc_handle);
190 * Return module which may be modified, e.g. by creating new functions.
193 llvm_mutable_module(LLVMJitContext *context)
195 llvm_assert_in_fatal_section();
198 * If there's no in-progress module, create a new one.
200 if (!context->module)
202 context->compiled = false;
203 context->module_generation = llvm_generation++;
204 context->module = LLVMModuleCreateWithName("pg");
205 LLVMSetTarget(context->module, llvm_triple);
206 LLVMSetDataLayout(context->module, llvm_layout);
209 return context->module;
213 * Expand function name to be non-conflicting. This should be used by code
214 * generating code, when adding new externally visible function definitions to
218 llvm_expand_funcname(struct LLVMJitContext *context, const char *basename)
220 Assert(context->module != NULL);
222 context->base.created_functions++;
225 * Previously we used dots to separate, but turns out some tools, e.g.
226 * GDB, don't like that and truncate name.
228 return psprintf("%s_%zu_%d",
230 context->module_generation,
235 * Return pointer to function funcname, which has to exist. If there's pending
236 * code to be optimized and emitted, do so first.
239 llvm_get_function(LLVMJitContext *context, const char *funcname)
241 LLVMOrcTargetAddress addr = 0;
242 #if defined(HAVE_DECL_LLVMORCGETSYMBOLADDRESSIN) && HAVE_DECL_LLVMORCGETSYMBOLADDRESSIN
246 llvm_assert_in_fatal_section();
249 * If there is a pending / not emitted module, compile and emit now.
250 * Otherwise we might not find the [correct] function.
252 if (!context->compiled)
254 llvm_compile_module(context);
258 * ORC's symbol table is of *unmangled* symbols. Therefore we don't need
262 #if defined(HAVE_DECL_LLVMORCGETSYMBOLADDRESSIN) && HAVE_DECL_LLVMORCGETSYMBOLADDRESSIN
263 foreach(lc, context->handles)
265 LLVMJitHandle *handle = (LLVMJitHandle *) lfirst(lc);
268 if (LLVMOrcGetSymbolAddressIn(handle->stack, &addr, handle->orc_handle, funcname))
269 elog(ERROR, "failed to look up symbol \"%s\"", funcname);
271 return (void *) (uintptr_t) addr;
276 #if LLVM_VERSION_MAJOR < 5
277 if ((addr = LLVMOrcGetSymbolAddress(llvm_opt0_orc, funcname)))
278 return (void *) (uintptr_t) addr;
279 if ((addr = LLVMOrcGetSymbolAddress(llvm_opt3_orc, funcname)))
280 return (void *) (uintptr_t) addr;
282 if (LLVMOrcGetSymbolAddress(llvm_opt0_orc, &addr, funcname))
283 elog(ERROR, "failed to look up symbol \"%s\"", funcname);
285 return (void *) (uintptr_t) addr;
286 if (LLVMOrcGetSymbolAddress(llvm_opt3_orc, &addr, funcname))
287 elog(ERROR, "failed to look up symbol \"%s\"", funcname);
289 return (void *) (uintptr_t) addr;
290 #endif /* LLVM_VERSION_MAJOR */
292 #endif /* HAVE_DECL_LLVMORCGETSYMBOLADDRESSIN */
294 elog(ERROR, "failed to JIT: %s", funcname);
300 * Return declaration for passed function, adding it to the module if
303 * This is used to make functions imported by llvm_create_types() known to the
304 * module that's currently being worked on.
307 llvm_get_decl(LLVMModuleRef mod, LLVMValueRef v_src)
311 /* don't repeatedly add function */
312 v_fn = LLVMGetNamedFunction(mod, LLVMGetValueName(v_src));
316 v_fn = LLVMAddFunction(mod,
317 LLVMGetValueName(v_src),
318 LLVMGetElementType(LLVMTypeOf(v_src)));
319 llvm_copy_attributes(v_src, v_fn);
325 * Copy attributes from one function to another.
328 llvm_copy_attributes(LLVMValueRef v_from, LLVMValueRef v_to)
332 LLVMAttributeRef *attrs;
335 LLVMGetAttributeCountAtIndex(v_from, LLVMAttributeFunctionIndex);
337 attrs = palloc(sizeof(LLVMAttributeRef) * num_attributes);
338 LLVMGetAttributesAtIndex(v_from, LLVMAttributeFunctionIndex, attrs);
340 for (attno = 0; attno < num_attributes; attno++)
342 LLVMAddAttributeAtIndex(v_to, LLVMAttributeFunctionIndex,
348 * Return a callable LLVMValueRef for fcinfo.
351 llvm_function_reference(LLVMJitContext *context,
352 LLVMBuilderRef builder,
354 FunctionCallInfo fcinfo)
362 fmgr_symbol(fcinfo->flinfo->fn_oid, &modname, &basename);
364 if (modname != NULL && basename != NULL)
366 /* external function in loadable library */
367 funcname = psprintf("pgextern.%s.%s", modname, basename);
369 else if (basename != NULL)
371 /* internal function */
372 funcname = psprintf("%s", basename);
377 * Function we don't know to handle, return pointer. We do so by
378 * creating a global constant containing a pointer to the function.
379 * Makes IR more readable.
381 LLVMValueRef v_fn_addr;
383 funcname = psprintf("pgoidextern.%u",
384 fcinfo->flinfo->fn_oid);
385 v_fn = LLVMGetNamedGlobal(mod, funcname);
387 return LLVMBuildLoad(builder, v_fn, "");
389 v_fn_addr = l_ptr_const(fcinfo->flinfo->fn_addr, TypePGFunction);
391 v_fn = LLVMAddGlobal(mod, TypePGFunction, funcname);
392 LLVMSetInitializer(v_fn, v_fn_addr);
393 LLVMSetGlobalConstant(v_fn, true);
395 return LLVMBuildLoad(builder, v_fn, "");
399 /* check if function already has been added */
400 v_fn = LLVMGetNamedFunction(mod, funcname);
404 v_fn = LLVMAddFunction(mod, funcname, LLVMGetElementType(TypePGFunction));
410 * Optimize code in module using the flags set in context.
413 llvm_optimize_module(LLVMJitContext *context, LLVMModuleRef module)
415 LLVMPassManagerBuilderRef llvm_pmb;
416 LLVMPassManagerRef llvm_mpm;
417 LLVMPassManagerRef llvm_fpm;
419 int compile_optlevel;
421 if (context->base.flags & PGJIT_OPT3)
422 compile_optlevel = 3;
424 compile_optlevel = 0;
427 * Have to create a new pass manager builder every pass through, as the
428 * inliner has some per-builder state. Otherwise one ends up only inlining
429 * a function the first time though.
431 llvm_pmb = LLVMPassManagerBuilderCreate();
432 LLVMPassManagerBuilderSetOptLevel(llvm_pmb, compile_optlevel);
433 llvm_fpm = LLVMCreateFunctionPassManagerForModule(module);
435 if (context->base.flags & PGJIT_OPT3)
437 /* TODO: Unscientifically determined threshhold */
438 LLVMPassManagerBuilderUseInlinerWithThreshold(llvm_pmb, 512);
442 /* we rely on mem2reg heavily, so emit even in the O0 case */
443 LLVMAddPromoteMemoryToRegisterPass(llvm_fpm);
446 LLVMPassManagerBuilderPopulateFunctionPassManager(llvm_pmb, llvm_fpm);
449 * Do function level optimization. This could be moved to the point where
450 * functions are emitted, to reduce memory usage a bit.
452 LLVMInitializeFunctionPassManager(llvm_fpm);
453 for (func = LLVMGetFirstFunction(context->module);
455 func = LLVMGetNextFunction(func))
456 LLVMRunFunctionPassManager(llvm_fpm, func);
457 LLVMFinalizeFunctionPassManager(llvm_fpm);
458 LLVMDisposePassManager(llvm_fpm);
461 * Perform module level optimization. We do so even in the non-optimized
462 * case, so always-inline functions etc get inlined. It's cheap enough.
464 llvm_mpm = LLVMCreatePassManager();
465 LLVMPassManagerBuilderPopulateModulePassManager(llvm_pmb,
467 /* always use always-inliner pass */
468 if (!(context->base.flags & PGJIT_OPT3))
469 LLVMAddAlwaysInlinerPass(llvm_mpm);
470 LLVMRunPassManager(llvm_mpm, context->module);
471 LLVMDisposePassManager(llvm_mpm);
473 LLVMPassManagerBuilderDispose(llvm_pmb);
477 * Emit code for the currently pending module.
480 llvm_compile_module(LLVMJitContext *context)
482 LLVMOrcModuleHandle orc_handle;
483 MemoryContext oldcontext;
484 static LLVMOrcJITStackRef compile_orc;
485 instr_time starttime;
488 if (context->base.flags & PGJIT_OPT3)
489 compile_orc = llvm_opt3_orc;
491 compile_orc = llvm_opt0_orc;
493 if (jit_dump_bitcode)
497 filename = psprintf("%u.%zu.bc",
499 context->module_generation);
500 LLVMWriteBitcodeToFile(context->module, filename);
505 /* optimize according to the chosen optimization settings */
506 INSTR_TIME_SET_CURRENT(starttime);
507 llvm_optimize_module(context, context->module);
508 INSTR_TIME_SET_CURRENT(endtime);
509 INSTR_TIME_ACCUM_DIFF(context->base.optimization_counter,
512 if (jit_dump_bitcode)
516 filename = psprintf("%u.%zu.optimized.bc",
518 context->module_generation);
519 LLVMWriteBitcodeToFile(context->module, filename);
524 * Emit the code. Note that this can, depending on the optimization
525 * settings, take noticeable resources as code emission executes low-level
526 * instruction combining/selection passes etc. Without optimization a
527 * faster instruction selection mechanism is used.
529 INSTR_TIME_SET_CURRENT(starttime);
530 #if LLVM_VERSION_MAJOR < 5
532 orc_handle = LLVMOrcAddEagerlyCompiledIR(compile_orc, context->module,
533 llvm_resolve_symbol, NULL);
534 LLVMDisposeModule(context->module);
538 LLVMSharedModuleRef smod;
540 smod = LLVMOrcMakeSharedModule(context->module);
541 if (LLVMOrcAddEagerlyCompiledIR(compile_orc, &orc_handle, smod,
542 llvm_resolve_symbol, NULL))
544 elog(ERROR, "failed to JIT module");
546 LLVMOrcDisposeSharedModuleRef(smod);
549 INSTR_TIME_SET_CURRENT(endtime);
550 INSTR_TIME_ACCUM_DIFF(context->base.emission_counter,
553 context->module = NULL;
554 context->compiled = true;
556 /* remember emitted code for cleanup and lookups */
557 oldcontext = MemoryContextSwitchTo(TopMemoryContext);
559 LLVMJitHandle *handle;
561 handle = (LLVMJitHandle *) palloc(sizeof(LLVMJitHandle));
562 handle->stack = compile_orc;
563 handle->orc_handle = orc_handle;
565 context->handles = lappend(context->handles, handle);
567 MemoryContextSwitchTo(oldcontext);
570 (errmsg("time to opt: %.3fs, emit: %.3fs",
571 INSTR_TIME_GET_DOUBLE(context->base.optimization_counter),
572 INSTR_TIME_GET_DOUBLE(context->base.emission_counter)),
574 errhidecontext(true)));
578 * Per session initialization.
581 llvm_session_initialize(void)
583 MemoryContext oldcontext;
586 char *features = NULL;
588 if (llvm_session_initialized)
591 oldcontext = MemoryContextSwitchTo(TopMemoryContext);
593 LLVMInitializeNativeTarget();
594 LLVMInitializeNativeAsmPrinter();
595 LLVMInitializeNativeAsmParser();
598 * Synchronize types early, as that also includes inferring the target
603 if (LLVMGetTargetFromTriple(llvm_triple, &llvm_targetref, &error) != 0)
605 elog(FATAL, "failed to query triple %s\n", error);
609 * We want the generated code to use all available features. Therefore
610 * grab the host CPU string and detect features of the current CPU. The
611 * latter is needed because some CPU architectures default to enabling
612 * features not all CPUs have (weird, huh).
614 cpu = LLVMGetHostCPUName();
615 features = LLVMGetHostCPUFeatures();
616 elog(DEBUG2, "LLVMJIT detected CPU \"%s\", with features \"%s\"",
619 llvm_opt0_targetmachine =
620 LLVMCreateTargetMachine(llvm_targetref, llvm_triple, cpu, features,
621 LLVMCodeGenLevelNone,
623 LLVMCodeModelJITDefault);
624 llvm_opt3_targetmachine =
625 LLVMCreateTargetMachine(llvm_targetref, llvm_triple, cpu, features,
626 LLVMCodeGenLevelAggressive,
628 LLVMCodeModelJITDefault);
630 LLVMDisposeMessage(cpu);
632 LLVMDisposeMessage(features);
635 /* force symbols in main binary to be loaded */
636 LLVMLoadLibraryPermanently(NULL);
638 llvm_opt0_orc = LLVMOrcCreateInstance(llvm_opt0_targetmachine);
639 llvm_opt3_orc = LLVMOrcCreateInstance(llvm_opt3_targetmachine);
641 #if defined(HAVE_DECL_LLVMORCREGISTERGDB) && HAVE_DECL_LLVMORCREGISTERGDB
642 if (jit_debugging_support)
644 LLVMOrcRegisterGDB(llvm_opt0_orc);
645 LLVMOrcRegisterGDB(llvm_opt3_orc);
648 #if defined(HAVE_DECL_LLVMORCREGISTERPERF) && HAVE_DECL_LLVMORCREGISTERPERF
649 if (jit_profiling_support)
651 LLVMOrcRegisterPerf(llvm_opt0_orc);
652 LLVMOrcRegisterPerf(llvm_opt3_orc);
656 before_shmem_exit(llvm_shutdown, 0);
658 llvm_session_initialized = true;
660 MemoryContextSwitchTo(oldcontext);
664 llvm_shutdown(int code, Datum arg)
666 /* unregister profiling support, needs to be flushed to be useful */
670 #if defined(HAVE_DECL_LLVMORCREGISTERPERF) && HAVE_DECL_LLVMORCREGISTERPERF
671 if (jit_profiling_support)
672 LLVMOrcUnregisterPerf(llvm_opt3_orc);
674 LLVMOrcDisposeInstance(llvm_opt3_orc);
675 llvm_opt3_orc = NULL;
680 #if defined(HAVE_DECL_LLVMORCREGISTERPERF) && HAVE_DECL_LLVMORCREGISTERPERF
681 if (jit_profiling_support)
682 LLVMOrcUnregisterPerf(llvm_opt0_orc);
684 LLVMOrcDisposeInstance(llvm_opt0_orc);
685 llvm_opt0_orc = NULL;
689 /* helper for llvm_create_types, returning a global var's type */
691 load_type(LLVMModuleRef mod, const char *name)
696 /* this'll return a *pointer* to the global */
697 value = LLVMGetNamedGlobal(mod, name);
699 elog(ERROR, "type %s is unknown", name);
701 /* therefore look at the contained type and return that */
702 typ = LLVMTypeOf(value);
704 typ = LLVMGetElementType(typ);
709 /* helper for llvm_create_types, returning a function's return type */
711 load_return_type(LLVMModuleRef mod, const char *name)
716 /* this'll return a *pointer* to the function */
717 value = LLVMGetNamedFunction(mod, name);
719 elog(ERROR, "function %s is unknown", name);
721 /* get type of function pointer */
722 typ = LLVMTypeOf(value);
724 /* dereference pointer */
725 typ = LLVMGetElementType(typ);
727 /* and look at return type */
728 typ = LLVMGetReturnType(typ);
735 * Load required information, types, function signatures from llvmjit_types.c
736 * and make them available in global variables.
738 * Those global variables are then used while emitting code.
741 llvm_create_types(void)
743 char path[MAXPGPATH];
744 LLVMMemoryBufferRef buf;
746 LLVMModuleRef mod = NULL;
748 snprintf(path, MAXPGPATH, "%s/%s", pkglib_path, "llvmjit_types.bc");
751 if (LLVMCreateMemoryBufferWithContentsOfFile(path, &buf, &msg))
753 elog(ERROR, "LLVMCreateMemoryBufferWithContentsOfFile(%s) failed: %s",
757 /* eagerly load contents, going to need it all */
758 if (LLVMParseBitcode2(buf, &mod))
760 elog(ERROR, "LLVMParseBitcode2 of %s failed", path);
762 LLVMDisposeMemoryBuffer(buf);
765 * Load triple & layout from clang emitted file so we're guaranteed to be
768 llvm_triple = pstrdup(LLVMGetTarget(mod));
769 llvm_layout = pstrdup(LLVMGetDataLayoutStr(mod));
771 TypeSizeT = load_type(mod, "TypeSizeT");
772 TypeParamBool = load_return_type(mod, "FunctionReturningBool");
773 TypeStorageBool = load_type(mod, "TypeStorageBool");
774 TypePGFunction = load_type(mod, "TypePGFunction");
775 StructExprContext = load_type(mod, "StructExprContext");
776 StructExprEvalStep = load_type(mod, "StructExprEvalStep");
777 StructExprState = load_type(mod, "StructExprState");
778 StructFunctionCallInfoData = load_type(mod, "StructFunctionCallInfoData");
779 StructMemoryContextData = load_type(mod, "StructMemoryContextData");
780 StructTupleTableSlot = load_type(mod, "StructTupleTableSlot");
781 StructHeapTupleData = load_type(mod, "StructHeapTupleData");
782 StructtupleDesc = load_type(mod, "StructtupleDesc");
783 StructAggState = load_type(mod, "StructAggState");
784 StructAggStatePerGroupData = load_type(mod, "StructAggStatePerGroupData");
785 StructAggStatePerTransData = load_type(mod, "StructAggStatePerTransData");
787 AttributeTemplate = LLVMGetNamedFunction(mod, "AttributeTemplate");
788 FuncStrlen = LLVMGetNamedFunction(mod, "strlen");
789 FuncVarsizeAny = LLVMGetNamedFunction(mod, "varsize_any");
790 FuncSlotGetsomeattrs = LLVMGetNamedFunction(mod, "slot_getsomeattrs");
791 FuncHeapGetsysattr = LLVMGetNamedFunction(mod, "heap_getsysattr");
792 FuncMakeExpandedObjectReadOnlyInternal = LLVMGetNamedFunction(mod, "MakeExpandedObjectReadOnlyInternal");
793 FuncExecEvalArrayRefSubscript = LLVMGetNamedFunction(mod, "ExecEvalArrayRefSubscript");
794 FuncExecAggTransReparent = LLVMGetNamedFunction(mod, "ExecAggTransReparent");
795 FuncExecAggInitGroup = LLVMGetNamedFunction(mod, "ExecAggInitGroup");
798 * Leave the module alive, otherwise references to function would be
806 * Split a symbol into module / function parts. If the function is in the
807 * main binary (or an external library) *modname will be NULL.
810 llvm_split_symbol_name(const char *name, char **modname, char **funcname)
816 * Module function names are pgextern.$module.$funcname
818 if (strncmp(name, "pgextern.", strlen("pgextern.")) == 0)
821 * Symbol names cannot contain a ., therefore we can split based on
822 * first and last occurance of one.
824 *funcname = rindex(name, '.');
825 (*funcname)++; /* jump over . */
827 *modname = pnstrdup(name + strlen("pgextern."),
828 *funcname - name - strlen("pgextern.") - 1);
831 *funcname = pstrdup(*funcname);
836 *funcname = pstrdup(name);
841 * Attempt to resolve symbol, so LLVM can emit a reference to it.
844 llvm_resolve_symbol(const char *symname, void *ctx)
851 * macOS prefixes all object level symbols with an underscore. But neither
852 * dlsym() nor PG's inliner expect that. So undo.
854 #if defined(__darwin__)
855 if (symname[0] != '_')
856 elog(ERROR, "expected prefixed symbol name, but got \"%s\"", symname);
860 llvm_split_symbol_name(symname, &modname, &funcname);
862 /* functions that aren't resolved to names shouldn't ever get here */
866 addr = (uintptr_t) load_external_function(modname, funcname,
869 addr = (uintptr_t) LLVMSearchForAddressOfSymbol(symname);
875 /* let LLVM will error out - should never happen */
877 elog(WARNING, "failed to resolve name %s", symname);
879 return (uint64_t) addr;