mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-11-27 07:21:09 +08:00
jit: Add support for LLVM 12.
LLVM 12, to be released in a few months, made some breaking changes to the Orc JIT interface. OrcV2 eventually will make it easier to support features like concurrent JIT compilation, but this commit only allows to compile against LLVM 12. This commit is a bit bigger than desirable. That partially is because the V2 interface is more granular than V1 interface, but also because I chose to make some minor changes to < LLVM 12 code to keep the code somewhat readable. The LLVM 12 support will need to be backpatched. I plan to do so after the patch stewed on the buildfarm for a few days. Author: Andres Freund Discussion: https://postgr.es/m/20201016011244.pmyvr3ee2gbzplq4@alap3.anarazel.de
This commit is contained in:
parent
24b83a5082
commit
6c57f2ed16
@ -18,7 +18,13 @@
|
||||
#include <llvm-c/BitWriter.h>
|
||||
#include <llvm-c/Core.h>
|
||||
#include <llvm-c/ExecutionEngine.h>
|
||||
#if LLVM_VERSION_MAJOR > 11
|
||||
#include <llvm-c/Orc.h>
|
||||
#include <llvm-c/OrcEE.h>
|
||||
#include <llvm-c/LLJIT.h>
|
||||
#else
|
||||
#include <llvm-c/OrcBindings.h>
|
||||
#endif
|
||||
#include <llvm-c/Support.h>
|
||||
#include <llvm-c/Target.h>
|
||||
#include <llvm-c/Transforms/IPO.h>
|
||||
@ -39,8 +45,13 @@
|
||||
/* Handle of a module emitted via ORC JIT */
|
||||
typedef struct LLVMJitHandle
|
||||
{
|
||||
#if LLVM_VERSION_MAJOR > 11
|
||||
LLVMOrcLLJITRef lljit;
|
||||
LLVMOrcResourceTrackerRef resource_tracker;
|
||||
#else
|
||||
LLVMOrcJITStackRef stack;
|
||||
LLVMOrcModuleHandle orc_handle;
|
||||
#endif
|
||||
} LLVMJitHandle;
|
||||
|
||||
|
||||
@ -85,12 +96,15 @@ static const char *llvm_triple = NULL;
|
||||
static const char *llvm_layout = NULL;
|
||||
|
||||
|
||||
static LLVMTargetMachineRef llvm_opt0_targetmachine;
|
||||
static LLVMTargetMachineRef llvm_opt3_targetmachine;
|
||||
|
||||
static LLVMTargetRef llvm_targetref;
|
||||
#if LLVM_VERSION_MAJOR > 11
|
||||
static LLVMOrcThreadSafeContextRef llvm_ts_context;
|
||||
static LLVMOrcLLJITRef llvm_opt0_orc;
|
||||
static LLVMOrcLLJITRef llvm_opt3_orc;
|
||||
#else /* LLVM_VERSION_MAJOR > 11 */
|
||||
static LLVMOrcJITStackRef llvm_opt0_orc;
|
||||
static LLVMOrcJITStackRef llvm_opt3_orc;
|
||||
#endif /* LLVM_VERSION_MAJOR > 11 */
|
||||
|
||||
|
||||
static void llvm_release_context(JitContext *context);
|
||||
@ -102,6 +116,10 @@ static void llvm_optimize_module(LLVMJitContext *context, LLVMModuleRef module);
|
||||
static void llvm_create_types(void);
|
||||
static uint64_t llvm_resolve_symbol(const char *name, void *ctx);
|
||||
|
||||
#if LLVM_VERSION_MAJOR > 11
|
||||
static LLVMOrcLLJITRef llvm_create_jit_instance(LLVMTargetMachineRef tm);
|
||||
static char *llvm_error_message(LLVMErrorRef error);
|
||||
#endif /* LLVM_VERSION_MAJOR > 11 */
|
||||
|
||||
PG_MODULE_MAGIC;
|
||||
|
||||
@ -161,24 +179,47 @@ llvm_release_context(JitContext *context)
|
||||
* have occurred from within LLVM, we do not want to risk reentering. All
|
||||
* resource cleanup is going to happen through process exit.
|
||||
*/
|
||||
if (!proc_exit_inprogress)
|
||||
if (proc_exit_inprogress)
|
||||
return;
|
||||
|
||||
if (llvm_context->module)
|
||||
{
|
||||
if (llvm_context->module)
|
||||
LLVMDisposeModule(llvm_context->module);
|
||||
llvm_context->module = NULL;
|
||||
}
|
||||
|
||||
while (llvm_context->handles != NIL)
|
||||
{
|
||||
LLVMJitHandle *jit_handle;
|
||||
|
||||
jit_handle = (LLVMJitHandle *) linitial(llvm_context->handles);
|
||||
llvm_context->handles = list_delete_first(llvm_context->handles);
|
||||
|
||||
#if LLVM_VERSION_MAJOR > 11
|
||||
{
|
||||
LLVMDisposeModule(llvm_context->module);
|
||||
llvm_context->module = NULL;
|
||||
LLVMOrcExecutionSessionRef ee;
|
||||
LLVMOrcSymbolStringPoolRef sp;
|
||||
|
||||
LLVMOrcResourceTrackerRemove(jit_handle->resource_tracker);
|
||||
LLVMOrcReleaseResourceTracker(jit_handle->resource_tracker);
|
||||
|
||||
/*
|
||||
* Without triggering cleanup of the string pool, we'd leak
|
||||
* memory. It'd be sufficient to do this far less often, but in
|
||||
* experiments the required time was small enough to just always
|
||||
* do it.
|
||||
*/
|
||||
ee = LLVMOrcLLJITGetExecutionSession(jit_handle->lljit);
|
||||
sp = LLVMOrcExecutionSessionGetSymbolStringPool(ee);
|
||||
LLVMOrcSymbolStringPoolClearDeadEntries(sp);
|
||||
}
|
||||
|
||||
while (llvm_context->handles != NIL)
|
||||
#else /* LLVM_VERSION_MAJOR > 11 */
|
||||
{
|
||||
LLVMJitHandle *jit_handle;
|
||||
|
||||
jit_handle = (LLVMJitHandle *) linitial(llvm_context->handles);
|
||||
llvm_context->handles = list_delete_first(llvm_context->handles);
|
||||
|
||||
LLVMOrcRemoveModule(jit_handle->stack, jit_handle->orc_handle);
|
||||
pfree(jit_handle);
|
||||
}
|
||||
#endif /* LLVM_VERSION_MAJOR > 11 */
|
||||
|
||||
pfree(jit_handle);
|
||||
}
|
||||
}
|
||||
|
||||
@ -234,8 +275,8 @@ llvm_expand_funcname(struct LLVMJitContext *context, const char *basename)
|
||||
void *
|
||||
llvm_get_function(LLVMJitContext *context, const char *funcname)
|
||||
{
|
||||
LLVMOrcTargetAddress addr = 0;
|
||||
#if defined(HAVE_DECL_LLVMORCGETSYMBOLADDRESSIN) && HAVE_DECL_LLVMORCGETSYMBOLADDRESSIN
|
||||
#if LLVM_VERSION_MAJOR > 11 || \
|
||||
defined(HAVE_DECL_LLVMORCGETSYMBOLADDRESSIN) && HAVE_DECL_LLVMORCGETSYMBOLADDRESSIN
|
||||
ListCell *lc;
|
||||
#endif
|
||||
|
||||
@ -255,10 +296,41 @@ llvm_get_function(LLVMJitContext *context, const char *funcname)
|
||||
* to mangle here.
|
||||
*/
|
||||
|
||||
#if defined(HAVE_DECL_LLVMORCGETSYMBOLADDRESSIN) && HAVE_DECL_LLVMORCGETSYMBOLADDRESSIN
|
||||
#if LLVM_VERSION_MAJOR > 11
|
||||
foreach(lc, context->handles)
|
||||
{
|
||||
LLVMJitHandle *handle = (LLVMJitHandle *) lfirst(lc);
|
||||
instr_time starttime;
|
||||
instr_time endtime;
|
||||
LLVMErrorRef error;
|
||||
LLVMOrcJITTargetAddress addr;
|
||||
|
||||
INSTR_TIME_SET_CURRENT(starttime);
|
||||
|
||||
addr = 0;
|
||||
error = LLVMOrcLLJITLookup(handle->lljit, &addr, funcname);
|
||||
if (error)
|
||||
elog(ERROR, "failed to look up symbol \"%s\": %s",
|
||||
funcname, llvm_error_message(error));
|
||||
|
||||
/*
|
||||
* LLJIT only actually emits code the first time a symbol is
|
||||
* referenced. Thus add lookup time to emission time. That's counting
|
||||
* a bit more than with older LLVM versions, but unlikely to ever
|
||||
* matter.
|
||||
*/
|
||||
INSTR_TIME_SET_CURRENT(endtime);
|
||||
INSTR_TIME_ACCUM_DIFF(context->base.instr.emission_counter,
|
||||
endtime, starttime);
|
||||
|
||||
if (addr)
|
||||
return (void *) (uintptr_t) addr;
|
||||
}
|
||||
#elif defined(HAVE_DECL_LLVMORCGETSYMBOLADDRESSIN) && HAVE_DECL_LLVMORCGETSYMBOLADDRESSIN
|
||||
foreach(lc, context->handles)
|
||||
{
|
||||
LLVMOrcTargetAddress addr;
|
||||
LLVMJitHandle *handle = (LLVMJitHandle *) lfirst(lc);
|
||||
|
||||
addr = 0;
|
||||
if (LLVMOrcGetSymbolAddressIn(handle->stack, &addr, handle->orc_handle, funcname))
|
||||
@ -266,26 +338,29 @@ llvm_get_function(LLVMJitContext *context, const char *funcname)
|
||||
if (addr)
|
||||
return (void *) (uintptr_t) addr;
|
||||
}
|
||||
#elif LLVM_VERSION_MAJOR < 5
|
||||
{
|
||||
LLVMOrcTargetAddress addr;
|
||||
|
||||
if ((addr = LLVMOrcGetSymbolAddress(llvm_opt0_orc, funcname)))
|
||||
return (void *) (uintptr_t) addr;
|
||||
if ((addr = LLVMOrcGetSymbolAddress(llvm_opt3_orc, funcname)))
|
||||
return (void *) (uintptr_t) addr;
|
||||
}
|
||||
#else
|
||||
{
|
||||
LLVMOrcTargetAddress addr;
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
if ((addr = LLVMOrcGetSymbolAddress(llvm_opt0_orc, funcname)))
|
||||
return (void *) (uintptr_t) addr;
|
||||
if ((addr = LLVMOrcGetSymbolAddress(llvm_opt3_orc, funcname)))
|
||||
return (void *) (uintptr_t) addr;
|
||||
#else
|
||||
if (LLVMOrcGetSymbolAddress(llvm_opt0_orc, &addr, funcname))
|
||||
elog(ERROR, "failed to look up symbol \"%s\"", funcname);
|
||||
if (addr)
|
||||
return (void *) (uintptr_t) addr;
|
||||
if (LLVMOrcGetSymbolAddress(llvm_opt3_orc, &addr, funcname))
|
||||
elog(ERROR, "failed to look up symbol \"%s\"", funcname);
|
||||
if (addr)
|
||||
return (void *) (uintptr_t) addr;
|
||||
#endif /* LLVM_VERSION_MAJOR */
|
||||
|
||||
#endif /* HAVE_DECL_LLVMORCGETSYMBOLADDRESSIN */
|
||||
if (LLVMOrcGetSymbolAddress(llvm_opt0_orc, &addr, funcname))
|
||||
elog(ERROR, "failed to look up symbol \"%s\"", funcname);
|
||||
if (addr)
|
||||
return (void *) (uintptr_t) addr;
|
||||
if (LLVMOrcGetSymbolAddress(llvm_opt3_orc, &addr, funcname))
|
||||
elog(ERROR, "failed to look up symbol \"%s\"", funcname);
|
||||
if (addr)
|
||||
return (void *) (uintptr_t) addr;
|
||||
}
|
||||
#endif
|
||||
|
||||
elog(ERROR, "failed to JIT: %s", funcname);
|
||||
|
||||
@ -420,6 +495,8 @@ llvm_function_reference(LLVMJitContext *context,
|
||||
v_fn = LLVMAddGlobal(mod, TypePGFunction, funcname);
|
||||
LLVMSetInitializer(v_fn, v_fn_addr);
|
||||
LLVMSetGlobalConstant(v_fn, true);
|
||||
LLVMSetLinkage(v_fn, LLVMPrivateLinkage);
|
||||
LLVMSetUnnamedAddr(v_fn, true);
|
||||
|
||||
return LLVMBuildLoad(builder, v_fn, "");
|
||||
}
|
||||
@ -511,11 +588,15 @@ llvm_optimize_module(LLVMJitContext *context, LLVMModuleRef module)
|
||||
static void
|
||||
llvm_compile_module(LLVMJitContext *context)
|
||||
{
|
||||
LLVMOrcModuleHandle orc_handle;
|
||||
LLVMJitHandle *handle;
|
||||
MemoryContext oldcontext;
|
||||
static LLVMOrcJITStackRef compile_orc;
|
||||
instr_time starttime;
|
||||
instr_time endtime;
|
||||
#if LLVM_VERSION_MAJOR > 11
|
||||
LLVMOrcLLJITRef compile_orc;
|
||||
#else
|
||||
LLVMOrcJITStackRef compile_orc;
|
||||
#endif
|
||||
|
||||
if (context->base.flags & PGJIT_OPT3)
|
||||
compile_orc = llvm_opt3_orc;
|
||||
@ -562,6 +643,9 @@ llvm_compile_module(LLVMJitContext *context)
|
||||
pfree(filename);
|
||||
}
|
||||
|
||||
handle = (LLVMJitHandle *)
|
||||
MemoryContextAlloc(TopMemoryContext, sizeof(LLVMJitHandle));
|
||||
|
||||
/*
|
||||
* Emit the code. Note that this can, depending on the optimization
|
||||
* settings, take noticeable resources as code emission executes low-level
|
||||
@ -569,13 +653,42 @@ llvm_compile_module(LLVMJitContext *context)
|
||||
* faster instruction selection mechanism is used.
|
||||
*/
|
||||
INSTR_TIME_SET_CURRENT(starttime);
|
||||
#if LLVM_VERSION_MAJOR > 6
|
||||
#if LLVM_VERSION_MAJOR > 11
|
||||
{
|
||||
if (LLVMOrcAddEagerlyCompiledIR(compile_orc, &orc_handle, context->module,
|
||||
LLVMOrcThreadSafeModuleRef ts_module;
|
||||
LLVMErrorRef error;
|
||||
LLVMOrcJITDylibRef jd = LLVMOrcLLJITGetMainJITDylib(compile_orc);
|
||||
|
||||
ts_module = LLVMOrcCreateNewThreadSafeModule(context->module, llvm_ts_context);
|
||||
|
||||
handle->lljit = compile_orc;
|
||||
handle->resource_tracker = LLVMOrcJITDylibCreateResourceTracker(jd);
|
||||
|
||||
/*
|
||||
* NB: This doesn't actually emit code. That happens lazily the first
|
||||
* time a symbol defined in the module is requested. Due to that
|
||||
* llvm_get_function() also accounts for emission time.
|
||||
*/
|
||||
|
||||
context->module = NULL; /* will be owned by LLJIT */
|
||||
error = LLVMOrcLLJITAddLLVMIRModuleWithRT(compile_orc,
|
||||
handle->resource_tracker,
|
||||
ts_module);
|
||||
|
||||
if (error)
|
||||
elog(ERROR, "failed to JIT module: %s",
|
||||
llvm_error_message(error));
|
||||
|
||||
handle->lljit = compile_orc;
|
||||
|
||||
/* LLVMOrcLLJITAddLLVMIRModuleWithRT takes ownership of the module */
|
||||
}
|
||||
#elif LLVM_VERSION_MAJOR > 6
|
||||
{
|
||||
handle->stack = compile_orc;
|
||||
if (LLVMOrcAddEagerlyCompiledIR(compile_orc, &handle->orc_handle, context->module,
|
||||
llvm_resolve_symbol, NULL))
|
||||
{
|
||||
elog(ERROR, "failed to JIT module");
|
||||
}
|
||||
|
||||
/* LLVMOrcAddEagerlyCompiledIR takes ownership of the module */
|
||||
}
|
||||
@ -584,20 +697,23 @@ llvm_compile_module(LLVMJitContext *context)
|
||||
LLVMSharedModuleRef smod;
|
||||
|
||||
smod = LLVMOrcMakeSharedModule(context->module);
|
||||
if (LLVMOrcAddEagerlyCompiledIR(compile_orc, &orc_handle, smod,
|
||||
handle->stack = compile_orc;
|
||||
if (LLVMOrcAddEagerlyCompiledIR(compile_orc, &handle->orc_handle, smod,
|
||||
llvm_resolve_symbol, NULL))
|
||||
{
|
||||
elog(ERROR, "failed to JIT module");
|
||||
}
|
||||
|
||||
LLVMOrcDisposeSharedModuleRef(smod);
|
||||
}
|
||||
#else /* LLVM 4.0 and 3.9 */
|
||||
{
|
||||
orc_handle = LLVMOrcAddEagerlyCompiledIR(compile_orc, context->module,
|
||||
llvm_resolve_symbol, NULL);
|
||||
handle->stack = compile_orc;
|
||||
handle->orc_handle = LLVMOrcAddEagerlyCompiledIR(compile_orc, context->module,
|
||||
llvm_resolve_symbol, NULL);
|
||||
|
||||
LLVMDisposeModule(context->module);
|
||||
}
|
||||
#endif
|
||||
|
||||
INSTR_TIME_SET_CURRENT(endtime);
|
||||
INSTR_TIME_ACCUM_DIFF(context->base.instr.emission_counter,
|
||||
endtime, starttime);
|
||||
@ -607,15 +723,7 @@ llvm_compile_module(LLVMJitContext *context)
|
||||
|
||||
/* remember emitted code for cleanup and lookups */
|
||||
oldcontext = MemoryContextSwitchTo(TopMemoryContext);
|
||||
{
|
||||
LLVMJitHandle *handle;
|
||||
|
||||
handle = (LLVMJitHandle *) palloc(sizeof(LLVMJitHandle));
|
||||
handle->stack = compile_orc;
|
||||
handle->orc_handle = orc_handle;
|
||||
|
||||
context->handles = lappend(context->handles, handle);
|
||||
}
|
||||
context->handles = lappend(context->handles, handle);
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
|
||||
ereport(DEBUG1,
|
||||
@ -637,6 +745,8 @@ llvm_session_initialize(void)
|
||||
char *error = NULL;
|
||||
char *cpu = NULL;
|
||||
char *features = NULL;
|
||||
LLVMTargetMachineRef opt0_tm;
|
||||
LLVMTargetMachineRef opt3_tm;
|
||||
|
||||
if (llvm_session_initialized)
|
||||
return;
|
||||
@ -669,12 +779,12 @@ llvm_session_initialize(void)
|
||||
elog(DEBUG2, "LLVMJIT detected CPU \"%s\", with features \"%s\"",
|
||||
cpu, features);
|
||||
|
||||
llvm_opt0_targetmachine =
|
||||
opt0_tm =
|
||||
LLVMCreateTargetMachine(llvm_targetref, llvm_triple, cpu, features,
|
||||
LLVMCodeGenLevelNone,
|
||||
LLVMRelocDefault,
|
||||
LLVMCodeModelJITDefault);
|
||||
llvm_opt3_targetmachine =
|
||||
opt3_tm =
|
||||
LLVMCreateTargetMachine(llvm_targetref, llvm_triple, cpu, features,
|
||||
LLVMCodeGenLevelAggressive,
|
||||
LLVMRelocDefault,
|
||||
@ -688,27 +798,41 @@ llvm_session_initialize(void)
|
||||
/* force symbols in main binary to be loaded */
|
||||
LLVMLoadLibraryPermanently(NULL);
|
||||
|
||||
llvm_opt0_orc = LLVMOrcCreateInstance(llvm_opt0_targetmachine);
|
||||
llvm_opt3_orc = LLVMOrcCreateInstance(llvm_opt3_targetmachine);
|
||||
#if LLVM_VERSION_MAJOR > 11
|
||||
{
|
||||
llvm_ts_context = LLVMOrcCreateNewThreadSafeContext();
|
||||
|
||||
llvm_opt0_orc = llvm_create_jit_instance(opt0_tm);
|
||||
opt0_tm = 0;
|
||||
|
||||
llvm_opt3_orc = llvm_create_jit_instance(opt3_tm);
|
||||
opt3_tm = 0;
|
||||
}
|
||||
#else /* LLVM_VERSION_MAJOR > 11 */
|
||||
{
|
||||
llvm_opt0_orc = LLVMOrcCreateInstance(opt0_tm);
|
||||
llvm_opt3_orc = LLVMOrcCreateInstance(opt3_tm);
|
||||
|
||||
#if defined(HAVE_DECL_LLVMCREATEGDBREGISTRATIONLISTENER) && HAVE_DECL_LLVMCREATEGDBREGISTRATIONLISTENER
|
||||
if (jit_debugging_support)
|
||||
{
|
||||
LLVMJITEventListenerRef l = LLVMCreateGDBRegistrationListener();
|
||||
if (jit_debugging_support)
|
||||
{
|
||||
LLVMJITEventListenerRef l = LLVMCreateGDBRegistrationListener();
|
||||
|
||||
LLVMOrcRegisterJITEventListener(llvm_opt0_orc, l);
|
||||
LLVMOrcRegisterJITEventListener(llvm_opt3_orc, l);
|
||||
}
|
||||
LLVMOrcRegisterJITEventListener(llvm_opt0_orc, l);
|
||||
LLVMOrcRegisterJITEventListener(llvm_opt3_orc, l);
|
||||
}
|
||||
#endif
|
||||
#if defined(HAVE_DECL_LLVMCREATEPERFJITEVENTLISTENER) && HAVE_DECL_LLVMCREATEPERFJITEVENTLISTENER
|
||||
if (jit_profiling_support)
|
||||
{
|
||||
LLVMJITEventListenerRef l = LLVMCreatePerfJITEventListener();
|
||||
if (jit_profiling_support)
|
||||
{
|
||||
LLVMJITEventListenerRef l = LLVMCreatePerfJITEventListener();
|
||||
|
||||
LLVMOrcRegisterJITEventListener(llvm_opt0_orc, l);
|
||||
LLVMOrcRegisterJITEventListener(llvm_opt3_orc, l);
|
||||
}
|
||||
LLVMOrcRegisterJITEventListener(llvm_opt0_orc, l);
|
||||
LLVMOrcRegisterJITEventListener(llvm_opt3_orc, l);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif /* LLVM_VERSION_MAJOR > 11 */
|
||||
|
||||
on_proc_exit(llvm_shutdown, 0);
|
||||
|
||||
@ -720,27 +844,49 @@ llvm_session_initialize(void)
|
||||
static void
|
||||
llvm_shutdown(int code, Datum arg)
|
||||
{
|
||||
/* unregister profiling support, needs to be flushed to be useful */
|
||||
|
||||
if (llvm_opt3_orc)
|
||||
#if LLVM_VERSION_MAJOR > 11
|
||||
{
|
||||
#if defined(HAVE_DECL_LLVMORCREGISTERPERF) && HAVE_DECL_LLVMORCREGISTERPERF
|
||||
if (jit_profiling_support)
|
||||
LLVMOrcUnregisterPerf(llvm_opt3_orc);
|
||||
#endif
|
||||
LLVMOrcDisposeInstance(llvm_opt3_orc);
|
||||
llvm_opt3_orc = NULL;
|
||||
if (llvm_opt3_orc)
|
||||
{
|
||||
LLVMOrcDisposeLLJIT(llvm_opt3_orc);
|
||||
llvm_opt3_orc = NULL;
|
||||
}
|
||||
if (llvm_opt0_orc)
|
||||
{
|
||||
LLVMOrcDisposeLLJIT(llvm_opt0_orc);
|
||||
llvm_opt0_orc = NULL;
|
||||
}
|
||||
if (llvm_ts_context)
|
||||
{
|
||||
LLVMOrcDisposeThreadSafeContext(llvm_ts_context);
|
||||
llvm_ts_context = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (llvm_opt0_orc)
|
||||
#else /* LLVM_VERSION_MAJOR > 11 */
|
||||
{
|
||||
/* unregister profiling support, needs to be flushed to be useful */
|
||||
|
||||
if (llvm_opt3_orc)
|
||||
{
|
||||
#if defined(HAVE_DECL_LLVMORCREGISTERPERF) && HAVE_DECL_LLVMORCREGISTERPERF
|
||||
if (jit_profiling_support)
|
||||
LLVMOrcUnregisterPerf(llvm_opt0_orc);
|
||||
if (jit_profiling_support)
|
||||
LLVMOrcUnregisterPerf(llvm_opt3_orc);
|
||||
#endif
|
||||
LLVMOrcDisposeInstance(llvm_opt0_orc);
|
||||
llvm_opt0_orc = NULL;
|
||||
LLVMOrcDisposeInstance(llvm_opt3_orc);
|
||||
llvm_opt3_orc = NULL;
|
||||
}
|
||||
|
||||
if (llvm_opt0_orc)
|
||||
{
|
||||
#if defined(HAVE_DECL_LLVMORCREGISTERPERF) && HAVE_DECL_LLVMORCREGISTERPERF
|
||||
if (jit_profiling_support)
|
||||
LLVMOrcUnregisterPerf(llvm_opt0_orc);
|
||||
#endif
|
||||
LLVMOrcDisposeInstance(llvm_opt0_orc);
|
||||
llvm_opt0_orc = NULL;
|
||||
}
|
||||
}
|
||||
#endif /* LLVM_VERSION_MAJOR > 11 */
|
||||
}
|
||||
|
||||
/* helper for llvm_create_types, returning a global var's type */
|
||||
@ -922,3 +1068,145 @@ llvm_resolve_symbol(const char *symname, void *ctx)
|
||||
|
||||
return (uint64_t) addr;
|
||||
}
|
||||
|
||||
#if LLVM_VERSION_MAJOR > 11
|
||||
|
||||
static LLVMErrorRef
|
||||
llvm_resolve_symbols(LLVMOrcDefinitionGeneratorRef GeneratorObj, void *Ctx,
|
||||
LLVMOrcLookupStateRef *LookupState, LLVMOrcLookupKind Kind,
|
||||
LLVMOrcJITDylibRef JD, LLVMOrcJITDylibLookupFlags JDLookupFlags,
|
||||
LLVMOrcCLookupSet LookupSet, size_t LookupSetSize)
|
||||
{
|
||||
LLVMOrcCSymbolMapPairs symbols = palloc0(sizeof(LLVMJITCSymbolMapPair) * LookupSetSize);
|
||||
LLVMErrorRef error;
|
||||
LLVMOrcMaterializationUnitRef mu;
|
||||
|
||||
for (int i = 0; i < LookupSetSize; i++)
|
||||
{
|
||||
const char *name = LLVMOrcSymbolStringPoolEntryStr(LookupSet[i].Name);
|
||||
|
||||
symbols[i].Name = LookupSet[i].Name;
|
||||
symbols[i].Sym.Address = llvm_resolve_symbol(name, NULL);
|
||||
symbols[i].Sym.Flags.GenericFlags = LLVMJITSymbolGenericFlagsExported;
|
||||
}
|
||||
|
||||
mu = LLVMOrcAbsoluteSymbols(symbols, LookupSetSize);
|
||||
error = LLVMOrcJITDylibDefine(JD, mu);
|
||||
if (error != LLVMErrorSuccess)
|
||||
LLVMOrcDisposeMaterializationUnit(mu);
|
||||
|
||||
pfree(symbols);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* We cannot throw errors through LLVM (without causing a FATAL at least), so
|
||||
* just use WARNING here. That's OK anyway, as the error is also reported at
|
||||
* the top level action (with less detail) and there might be multiple
|
||||
* invocations of errors with details.
|
||||
*
|
||||
* This doesn't really happen during normal operation, but in cases like
|
||||
* symbol resolution breakage. So just using elog(WARNING) is fine.
|
||||
*/
|
||||
static void
|
||||
llvm_log_jit_error(void *ctx, LLVMErrorRef error)
|
||||
{
|
||||
elog(WARNING, "error during JITing: %s",
|
||||
llvm_error_message(error));
|
||||
}
|
||||
|
||||
/*
|
||||
* Create our own object layer, so we can add event listeners.
|
||||
*/
|
||||
static LLVMOrcObjectLayerRef
|
||||
llvm_create_object_layer(void *Ctx, LLVMOrcExecutionSessionRef ES, const char *Triple)
|
||||
{
|
||||
LLVMOrcObjectLayerRef objlayer =
|
||||
LLVMOrcCreateRTDyldObjectLinkingLayerWithSectionMemoryManager(ES);
|
||||
|
||||
#if defined(HAVE_DECL_LLVMCREATEGDBREGISTRATIONLISTENER) && HAVE_DECL_LLVMCREATEGDBREGISTRATIONLISTENER
|
||||
if (jit_debugging_support)
|
||||
{
|
||||
LLVMJITEventListenerRef l = LLVMCreateGDBRegistrationListener();
|
||||
|
||||
LLVMOrcRTDyldObjectLinkingLayerRegisterJITEventListener(objlayer, l);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_DECL_LLVMCREATEPERFJITEVENTLISTENER) && HAVE_DECL_LLVMCREATEPERFJITEVENTLISTENER
|
||||
if (jit_profiling_support)
|
||||
{
|
||||
LLVMJITEventListenerRef l = LLVMCreatePerfJITEventListener();
|
||||
|
||||
LLVMOrcRTDyldObjectLinkingLayerRegisterJITEventListener(objlayer, l);
|
||||
}
|
||||
#endif
|
||||
|
||||
return objlayer;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create LLJIT instance, using the passed in target machine. Note that the
|
||||
* target machine afterwards is owned by the LLJIT instance.
|
||||
*/
|
||||
static LLVMOrcLLJITRef
|
||||
llvm_create_jit_instance(LLVMTargetMachineRef tm)
|
||||
{
|
||||
LLVMOrcLLJITRef lljit;
|
||||
LLVMOrcJITTargetMachineBuilderRef tm_builder;
|
||||
LLVMOrcLLJITBuilderRef lljit_builder;
|
||||
LLVMErrorRef error;
|
||||
LLVMOrcDefinitionGeneratorRef main_gen;
|
||||
LLVMOrcDefinitionGeneratorRef ref_gen;
|
||||
|
||||
lljit_builder = LLVMOrcCreateLLJITBuilder();
|
||||
tm_builder = LLVMOrcJITTargetMachineBuilderCreateFromTargetMachine(tm);
|
||||
LLVMOrcLLJITBuilderSetJITTargetMachineBuilder(lljit_builder, tm_builder);
|
||||
|
||||
LLVMOrcLLJITBuilderSetObjectLinkingLayerCreator(lljit_builder,
|
||||
llvm_create_object_layer,
|
||||
NULL);
|
||||
|
||||
error = LLVMOrcCreateLLJIT(&lljit, lljit_builder);
|
||||
if (error)
|
||||
elog(ERROR, "failed to create lljit instance: %s",
|
||||
llvm_error_message(error));
|
||||
|
||||
LLVMOrcExecutionSessionSetErrorReporter(LLVMOrcLLJITGetExecutionSession(lljit),
|
||||
llvm_log_jit_error, NULL);
|
||||
|
||||
/*
|
||||
* Symbol resolution support for symbols in the postgres binary /
|
||||
* libraries already loaded.
|
||||
*/
|
||||
error = LLVMOrcCreateDynamicLibrarySearchGeneratorForProcess(&main_gen,
|
||||
LLVMOrcLLJITGetGlobalPrefix(lljit),
|
||||
0, NULL);
|
||||
if (error)
|
||||
elog(ERROR, "failed to create generator: %s",
|
||||
llvm_error_message(error));
|
||||
LLVMOrcJITDylibAddGenerator(LLVMOrcLLJITGetMainJITDylib(lljit), main_gen);
|
||||
|
||||
/*
|
||||
* Symbol resolution support for "special" functions, e.g. a call into an
|
||||
* SQL callable function.
|
||||
*/
|
||||
ref_gen = LLVMOrcCreateCustomCAPIDefinitionGenerator(llvm_resolve_symbols, NULL);
|
||||
LLVMOrcJITDylibAddGenerator(LLVMOrcLLJITGetMainJITDylib(lljit), ref_gen);
|
||||
|
||||
return lljit;
|
||||
}
|
||||
|
||||
static char *
|
||||
llvm_error_message(LLVMErrorRef error)
|
||||
{
|
||||
char *orig = LLVMGetErrorMessage(error);
|
||||
char *msg = pstrdup(orig);
|
||||
|
||||
LLVMDisposeErrorMessage(orig);
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
#endif /* LLVM_VERSION_MAJOR > 11 */
|
||||
|
@ -1218,6 +1218,7 @@ LLVMJitHandle
|
||||
LLVMMemoryBufferRef
|
||||
LLVMModuleRef
|
||||
LLVMOrcJITStackRef
|
||||
LLVMOrcLookupStateRef
|
||||
LLVMOrcModuleHandle
|
||||
LLVMOrcTargetAddress
|
||||
LLVMPassManagerBuilderRef
|
||||
|
Loading…
Reference in New Issue
Block a user