From 23e5dce848ed8dac7b590da5c77321344b30310d Mon Sep 17 00:00:00 2001 From: Andres Freund Date: Mon, 13 Mar 2017 20:22:10 -0700 Subject: [PATCH 04/16] WIP: Beginning of a LLVM JIT infrastructure. This needs to do a lot more, especially around error handling, and memory management. --- configure | 2 +- configure.in | 2 +- src/backend/executor/execUtils.c | 2 + src/backend/lib/Makefile | 2 +- src/backend/lib/llvmjit.c | 519 ++++++++++++++++++++++++++++++++++ src/backend/utils/misc/guc.c | 27 ++ src/backend/utils/resowner/resowner.c | 40 +++ src/include/lib/llvmjit.h | 83 ++++++ src/include/nodes/execnodes.h | 4 +- src/include/utils/resowner_private.h | 7 + 10 files changed, 684 insertions(+), 4 deletions(-) create mode 100644 src/backend/lib/llvmjit.c create mode 100644 src/include/lib/llvmjit.h diff --git a/configure b/configure index fe905e294b..b6adceb990 100755 --- a/configure +++ b/configure @@ -6546,7 +6546,7 @@ done -L*) LDFLAGS="$LDFLAGS $pgac_option";; esac done - for pgac_option in `$LLVM_CONFIG --libs --system-libs engine`; do + for pgac_option in `$LLVM_CONFIG --libs --system-libs engine debuginfodwarf orcjit passes perfjitevents`; do case $pgac_option in -l*) LLVM_LIBS="$LLVM_LIBS $pgac_option";; esac diff --git a/configure.in b/configure.in index a99da9dff3..7028a31137 100644 --- a/configure.in +++ b/configure.in @@ -872,7 +872,7 @@ if test "$with_llvm" = yes ; then -L*) LDFLAGS="$LDFLAGS $pgac_option";; esac done - for pgac_option in `$LLVM_CONFIG --libs --system-libs engine`; do + for pgac_option in `$LLVM_CONFIG --libs --system-libs engine debuginfodwarf orcjit passes perfjitevents`; do case $pgac_option in -l*) LLVM_LIBS="$LLVM_LIBS $pgac_option";; esac diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c index 5928c38f90..aee6111c14 100644 --- a/src/backend/executor/execUtils.c +++ b/src/backend/executor/execUtils.c @@ -156,6 +156,8 @@ CreateExecutorState(void) estate->es_epqScanDone = NULL; estate->es_sourceText = NULL; + estate->es_jit = NULL; + /* * Return the executor state structure */ diff --git a/src/backend/lib/Makefile b/src/backend/lib/Makefile index d1fefe43f2..dd1390f9cf 100644 --- a/src/backend/lib/Makefile +++ b/src/backend/lib/Makefile @@ -13,6 +13,6 @@ top_builddir = ../../.. include $(top_builddir)/src/Makefile.global OBJS = binaryheap.o bipartite_match.o dshash.o hyperloglog.o ilist.o \ - knapsack.o pairingheap.o rbtree.o stringinfo.o + knapsack.o llvmjit.o pairingheap.o rbtree.o stringinfo.o include $(top_srcdir)/src/backend/common.mk diff --git a/src/backend/lib/llvmjit.c b/src/backend/lib/llvmjit.c new file mode 100644 index 0000000000..460cb6b325 --- /dev/null +++ b/src/backend/lib/llvmjit.c @@ -0,0 +1,519 @@ +/* + * JIT infrastructure. + */ + +#include "postgres.h" + + +#include "lib/llvmjit.h" + +#include "utils/memutils.h" +#include "utils/resowner_private.h" + +#ifdef USE_LLVM + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* GUCs */ +bool jit_log_ir = 0; +bool jit_dump_bitcode = 0; + +static bool llvm_initialized = false; +static LLVMPassManagerBuilderRef llvm_pmb; + +/* very common public things */ +const char *llvm_triple = NULL; + +LLVMTargetMachineRef llvm_targetmachine; + +LLVMTypeRef TypeSizeT; +LLVMTypeRef TypeMemoryContext; +LLVMTypeRef TypePGFunction; + +LLVMTypeRef StructHeapTupleFieldsField3; +LLVMTypeRef StructHeapTupleFields; +LLVMTypeRef StructHeapTupleHeaderData; +LLVMTypeRef StructHeapTupleDataChoice; +LLVMTypeRef StructHeapTupleData; +LLVMTypeRef StructMinimalTupleData; +LLVMTypeRef StructItemPointerData; +LLVMTypeRef StructBlockId; +LLVMTypeRef StructFormPgAttribute; +LLVMTypeRef StructTupleConstr; +LLVMTypeRef StructtupleDesc; +LLVMTypeRef StructTupleTableSlot; +LLVMTypeRef StructMemoryContextData; +LLVMTypeRef StructPGFinfoRecord; +LLVMTypeRef StructFmgrInfo; +LLVMTypeRef StructFunctionCallInfoData; +LLVMTypeRef StructExprState; +LLVMTypeRef StructExprContext; + + +static LLVMTargetRef llvm_targetref; +static LLVMOrcJITStackRef llvm_orc; + +static void llvm_shutdown(void); +static void llvm_create_types(void); + + +static void +llvm_shutdown(void) +{ + /* unregister profiling support, needs to be flushed to be useful */ + if (llvm_orc) + { + LLVMOrcUnregisterPerf(llvm_orc); + llvm_orc = NULL; + } +} + +void +llvm_initialize(void) +{ + char *error = NULL; + MemoryContext oldcontext; + + if (llvm_initialized) + return; + + oldcontext = MemoryContextSwitchTo(TopMemoryContext); + + LLVMInitializeNativeTarget(); + LLVMInitializeNativeAsmPrinter(); + LLVMInitializeNativeAsmParser(); + + /* force symbols in main binary to be loaded */ + LLVMLoadLibraryPermanently(""); + + llvm_triple = LLVMGetDefaultTargetTriple(); + + if (LLVMGetTargetFromTriple(llvm_triple, &llvm_targetref, &error) != 0) + { + elog(FATAL, "failed to query triple %s\n", error); + } + + llvm_targetmachine = + LLVMCreateTargetMachine(llvm_targetref, llvm_triple, NULL, NULL, + LLVMCodeGenLevelAggressive, + LLVMRelocDefault, + LLVMCodeModelJITDefault); + + llvm_pmb = LLVMPassManagerBuilderCreate(); + LLVMPassManagerBuilderSetOptLevel(llvm_pmb, 3); + + llvm_orc = LLVMOrcCreateInstance(llvm_targetmachine); + + LLVMOrcRegisterGDB(llvm_orc); + LLVMOrcRegisterPerf(llvm_orc); + + atexit(llvm_shutdown); + + llvm_create_types(); + + llvm_initialized = true; + MemoryContextSwitchTo(oldcontext); +} + +static void +llvm_create_types(void) +{ + /* so we don't constantly have to decide between 32/64 bit */ +#if SIZEOF_DATUM == 8 + TypeSizeT = LLVMInt64Type(); +#else + TypeSizeT = LLVMInt32Type(); +#endif + + /* + * XXX: should rather load these from disk using bitcode? It's ugly to + * duplicate the information, but in either case we're going to have to + * use member indexes for structs :(. + */ + { + LLVMTypeRef members[2]; + members[0] = LLVMInt16Type(); /* bi_hi */ + members[1] = LLVMInt16Type(); /* bi_lo */ + StructBlockId = LLVMStructCreateNamed(LLVMGetGlobalContext(), + "struct.BlockId"); + LLVMStructSetBody(StructBlockId, members, 2, false); + } + + { + LLVMTypeRef members[2]; + members[0] = StructBlockId; /* ip_blkid */ + members[1] = LLVMInt16Type(); /* ip_posid */ + + StructItemPointerData = LLVMStructCreateNamed(LLVMGetGlobalContext(), + "struct.ItemPointerData"); + LLVMStructSetBody(StructItemPointerData, members, lengthof(members), false); + } + + + { + LLVMTypeRef members[1]; + + members[0] = LLVMInt32Type() ; /* cid | xvac */ + + StructHeapTupleFieldsField3 = LLVMStructCreateNamed(LLVMGetGlobalContext(), + "struct.StructHeapTupleFieldsField3"); + LLVMStructSetBody(StructHeapTupleFieldsField3, members, lengthof(members), false); + } + + { + LLVMTypeRef members[1]; + + members[0] = LLVMInt32Type() ; /* ? */ + + StructPGFinfoRecord = LLVMStructCreateNamed(LLVMGetGlobalContext(), + "struct.PGFinfoRecord"); + LLVMStructSetBody(StructPGFinfoRecord, members, lengthof(members), false); + } + + { + LLVMTypeRef members[3]; + members[0] = LLVMInt32Type(); /* xmin */ + members[1] = LLVMInt32Type(); /* xmax */ + members[2] = StructHeapTupleFieldsField3; /* cid | xvac */ + + StructHeapTupleFields = LLVMStructCreateNamed(LLVMGetGlobalContext(), + "struct.HeapTupleFields"); + LLVMStructSetBody(StructHeapTupleFields, members, lengthof(members), false); + } + + { + LLVMTypeRef members[1]; + + members[0] = StructHeapTupleFields; /* t_heap | t_datum */ + + StructHeapTupleDataChoice = LLVMStructCreateNamed(LLVMGetGlobalContext(), + "struct.HeapTupleHeaderDataChoice"); + LLVMStructSetBody(StructHeapTupleDataChoice, members, lengthof(members), false); + + } + + { + LLVMTypeRef members[6]; + + members[0] = StructHeapTupleDataChoice; /* t_heap | t_datum */ + members[1] = StructItemPointerData; /* t_ctid */ + members[2] = LLVMInt16Type(); /* t_infomask2 */ + members[3] = LLVMInt16Type(); /* t_infomask1 */ + members[4] = LLVMInt8Type(); /* t_hoff */ + members[5] = LLVMArrayType(LLVMInt8Type(), 0); /* t_bits */ + /* t_bits and other data follow */ + + StructHeapTupleHeaderData = LLVMStructCreateNamed(LLVMGetGlobalContext(), + "struct.HeapTupleHeaderData"); + LLVMStructSetBody(StructHeapTupleHeaderData, members, lengthof(members), false); + } + + { + LLVMTypeRef members[4]; + members[0] = LLVMInt32Type(); /* t_len */ + members[1] = StructItemPointerData; /* t_self */ + members[2] = LLVMInt32Type(); /* t_tableOid */ + members[3] = LLVMPointerType(StructHeapTupleHeaderData, 0); /* t_data */ + + StructHeapTupleData = LLVMStructCreateNamed(LLVMGetGlobalContext(), + "struct.HeapTupleData"); + LLVMStructSetBody(StructHeapTupleData, members, lengthof(members), false); + } + + { + StructMinimalTupleData = LLVMStructCreateNamed(LLVMGetGlobalContext(), + "struct.MinimalTupleData"); + } + + + { + StructFormPgAttribute = LLVMStructCreateNamed(LLVMGetGlobalContext(), + "struct.Form_pg_attribute"); + } + + { + StructTupleConstr = LLVMStructCreateNamed(LLVMGetGlobalContext(), + "struct.TupleConstr"); + } + + { + LLVMTypeRef members[7]; + + members[0] = LLVMInt32Type(); /* natts */ + members[1] = LLVMInt32Type(); /* tdtypeid */ + members[2] = LLVMInt32Type(); /* tdtypemod */ + members[3] = LLVMInt8Type(); /* tdhasoid */ + members[4] = LLVMInt32Type(); /* tsrefcount */ + members[5] = LLVMPointerType(StructTupleConstr, 0); /* constr */ + members[6] = LLVMArrayType(LLVMPointerType(StructFormPgAttribute, 0), 0); /* attrs */ + + StructtupleDesc = LLVMStructCreateNamed(LLVMGetGlobalContext(), + "struct.tupleDesc"); + LLVMStructSetBody(StructtupleDesc, members, lengthof(members), false); + } + + { + StructMemoryContextData = LLVMStructCreateNamed(LLVMGetGlobalContext(), + "struct.MemoryContext"); + } + + { + TypeMemoryContext = LLVMPointerType(StructMemoryContextData, 0); + } + + { + LLVMTypeRef members[15]; + + members[ 0] = LLVMInt32Type(); /* type */ + members[ 1] = LLVMInt8Type(); /* isempty */ + members[ 2] = LLVMInt8Type(); /* shouldFree */ + members[ 3] = LLVMInt8Type(); /* shouldFreeMin */ + members[ 4] = LLVMInt8Type(); /* slow */ + members[ 5] = LLVMPointerType(StructHeapTupleData, 0); /* tuple */ + members[ 6] = LLVMPointerType(StructtupleDesc, 0); /* tupleDescriptor */ + members[ 7] = TypeMemoryContext; /* mcxt */ + members[ 8] = LLVMInt32Type(); /* buffer */ + members[ 9] = LLVMInt32Type(); /* nvalid */ + members[10] = LLVMPointerType(TypeSizeT, 0); /* values */ + members[11] = LLVMPointerType(LLVMInt8Type(), 0); /* nulls */ + members[12] = LLVMPointerType(StructMinimalTupleData, 0); /* mintuple */ + members[13] = StructHeapTupleData; /* minhdr */ + members[14] = LLVMInt64Type(); /* off: FIXME, deterministic type, not long */ + + StructTupleTableSlot = LLVMStructCreateNamed(LLVMGetGlobalContext(), + "struct.TupleTableSlot"); + LLVMStructSetBody(StructTupleTableSlot, members, lengthof(members), false); + } + + { + StructFmgrInfo = LLVMStructCreateNamed(LLVMGetGlobalContext(), + "struct.FmgrInfo"); + } + + { + LLVMTypeRef members[8]; + + members[0] = LLVMPointerType(StructFmgrInfo, 0); /* flinfo */ + members[1] = LLVMPointerType(StructPGFinfoRecord, 0); /* context */ + members[2] = LLVMPointerType(StructPGFinfoRecord, 0); /* resultinfo */ + members[3] = LLVMInt32Type(); /* fncollation */ + members[4] = LLVMInt8Type(); /* isnull */ + members[5] = LLVMInt16Type(); /* nargs */ + members[6] = LLVMArrayType(TypeSizeT, FUNC_MAX_ARGS); + members[7] = LLVMArrayType(LLVMInt8Type(), FUNC_MAX_ARGS); + + StructFunctionCallInfoData = LLVMStructCreateNamed(LLVMGetGlobalContext(), + "struct.FunctionCallInfoData"); + LLVMStructSetBody(StructFunctionCallInfoData, members, lengthof(members), false); + } + + { + LLVMTypeRef members[14]; + + members[ 0] = LLVMInt32Type(); /* tag */ + members[ 1] = LLVMInt8Type(); /* flags */ + members[ 2] = LLVMInt8Type(); /* resnull */ + members[ 3] = TypeSizeT; /* resvalue */ + members[ 4] = LLVMPointerType(StructTupleTableSlot, 0); /* resultslot */ + members[ 5] = LLVMPointerType(TypeSizeT, 0); /* steps */ + members[ 6] = LLVMPointerType(TypeSizeT, 0); /* evalfunc */ + members[ 7] = LLVMPointerType(TypeSizeT, 0); /* expr */ + members[ 8] = TypeSizeT; /* steps_len */ + members[ 9] = TypeSizeT; /* steps_alloc */ + members[10] = LLVMPointerType(TypeSizeT, 0); /* innermost caseval */ + members[11] = LLVMPointerType(LLVMInt8Type(), 0); /* innermost casenull */ + members[12] = LLVMPointerType(TypeSizeT, 0); /* innermost domainval */ + members[13] = LLVMPointerType(LLVMInt8Type(), 0); /* innermost domainnull */ + + StructExprState = LLVMStructCreateNamed(LLVMGetGlobalContext(), + "struct.ExprState"); + LLVMStructSetBody(StructExprState, members, lengthof(members), false); + } + + { + LLVMTypeRef members[16]; + + members[ 0] = LLVMInt32Type(); /* tag */ + members[ 1] = LLVMPointerType(StructTupleTableSlot, 0); /* scantuple */ + members[ 2] = LLVMPointerType(StructTupleTableSlot, 0); /* innertuple */ + members[ 3] = LLVMPointerType(StructTupleTableSlot, 0); /* outertuple */ + + members[ 4] = LLVMPointerType(TypeSizeT, 0); /* per_query_memory */ + members[ 5] = LLVMPointerType(TypeSizeT, 0); /* per_tuple_memory */ + + members[ 6] = LLVMPointerType(TypeSizeT, 0); /* param_exec */ + members[ 7] = LLVMPointerType(TypeSizeT, 0); /* param_list_info */ + + members[ 8] = LLVMPointerType(TypeSizeT, 0); /* aggvalues */ + members[ 9] = LLVMPointerType(LLVMInt8Type(), 0); /* aggnulls */ + + members[10] = TypeSizeT; /* casvalue */ + members[11] = LLVMInt8Type(); /* casenull */ + + members[12] = TypeSizeT; /* domainvalue */ + members[13] = LLVMInt8Type(); /* domainnull */ + + members[14] = LLVMPointerType(TypeSizeT, 0); /* estate */ + members[15] = LLVMPointerType(TypeSizeT, 0); /* callbacks */ + + StructExprContext = LLVMStructCreateNamed(LLVMGetGlobalContext(), + "struct.ExprContext"); + LLVMStructSetBody(StructExprContext, members, lengthof(members), false); + } + + { + LLVMTypeRef params[1]; + params[0] = LLVMPointerType(StructFunctionCallInfoData, 0); + TypePGFunction = LLVMFunctionType(TypeSizeT, params, lengthof(params), 0); + } +} + +static uint64_t +llvm_resolve_symbol(const char *name, void *ctx) +{ + return (uint64_t) LLVMSearchForAddressOfSymbol(name); +} + +void * +llvm_get_function(LLVMJitContext *context, const char *funcname) +{ + /* + * If there is a pending, not emitted, module, compile and emit + * now. Otherwise we migh not find the [correct] function. + */ + if (!context->compiled) + { + int handle; + LLVMSharedModuleRef smod = LLVMOrcMakeSharedModule(context->module); + MemoryContext oldcontext; + + if (jit_log_ir) + { + LLVMDumpModule(context->module); + } + + if (jit_dump_bitcode) + { + /* FIXME: invent module rather than function specific name */ + char *filename = psprintf("%s.bc", funcname); + LLVMWriteBitcodeToFile(context->module, filename); + pfree(filename); + } + + + /* perform optimization */ + { + LLVMValueRef func; + LLVMPassManagerRef llvm_fpm; + LLVMPassManagerRef llvm_mpm; + + llvm_fpm = LLVMCreateFunctionPassManagerForModule(context->module); + llvm_mpm = LLVMCreatePassManager(); + + LLVMPassManagerBuilderPopulateFunctionPassManager(llvm_pmb, llvm_fpm); + LLVMPassManagerBuilderPopulateModulePassManager(llvm_pmb, llvm_mpm); + LLVMPassManagerBuilderPopulateLTOPassManager(llvm_pmb, llvm_mpm, true, true); + + LLVMAddAnalysisPasses(llvm_targetmachine, llvm_mpm); + LLVMAddAnalysisPasses(llvm_targetmachine, llvm_fpm); + + LLVMAddDeadStoreEliminationPass(llvm_fpm); + + /* do function level optimization */ + LLVMInitializeFunctionPassManager(llvm_fpm); + for (func = LLVMGetFirstFunction(context->module); + func != NULL; + func = LLVMGetNextFunction(func)) + LLVMRunFunctionPassManager(llvm_fpm, func); + LLVMFinalizeFunctionPassManager(llvm_fpm); + + /* do module level optimization */ + LLVMRunPassManager(llvm_mpm, context->module); + + LLVMDisposePassManager(llvm_fpm); + LLVMDisposePassManager(llvm_mpm); + } + + /* and emit the code */ + { + handle = + LLVMOrcAddEagerlyCompiledIR(llvm_orc, smod, + llvm_resolve_symbol, NULL); + + oldcontext = MemoryContextSwitchTo(TopMemoryContext); + context->handles = lappend_int(context->handles, handle); + MemoryContextSwitchTo(oldcontext); + + LLVMOrcDisposeSharedModuleRef(smod); + + ResourceOwnerEnlargeJIT(CurrentResourceOwner); + ResourceOwnerRememberJIT(CurrentResourceOwner, PointerGetDatum(context)); + } + + context->module = NULL; + context->compiled = true; + } + + /* search all emitted modules for function we're asked for */ + { + void *addr; + char *mangled; + ListCell *lc; + + LLVMOrcGetMangledSymbol(llvm_orc, &mangled, funcname); + foreach(lc, context->handles) + { + int handle = lfirst_int(lc); + + addr = (void *) LLVMOrcGetSymbolAddressIn(llvm_orc, handle, mangled); + if (addr) + return addr; + } + } + + elog(ERROR, "failed to JIT: %s", funcname); + + return NULL; +} + +void +llvm_release_handle(ResourceOwner resowner, Datum handle) +{ + LLVMJitContext *context = (LLVMJitContext *) DatumGetPointer(handle); + ListCell *lc; + + foreach(lc, context->handles) + { + int handle = lfirst_int(lc); + + LLVMOrcRemoveModule(llvm_orc, handle); + } + list_free(context->handles); + context->handles = NIL; + + ResourceOwnerForgetJIT(resowner, handle); +} + +#else /* USE_LLVM */ + +void +llvm_release_handle(ResourceOwner resowner, Datum handle) +{ +} + +#endif diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 246fea8693..2edc0b33c5 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -42,6 +42,7 @@ #include "commands/variable.h" #include "commands/trigger.h" #include "funcapi.h" +#include "lib/llvmjit.h" #include "libpq/auth.h" #include "libpq/be-fsstubs.h" #include "libpq/libpq.h" @@ -995,6 +996,32 @@ static struct config_bool ConfigureNamesBool[] = false, NULL, NULL, NULL }, + +#ifdef USE_LLVM + { + {"jit_log_ir", PGC_USERSET, DEVELOPER_OPTIONS, + gettext_noop("just-in-time debugging: print IR to stdout"), + NULL, + GUC_NOT_IN_SAMPLE + }, + &jit_log_ir, + false, + NULL, NULL, NULL + }, + + { + {"jit_dump_bitcode", PGC_USERSET, DEVELOPER_OPTIONS, + gettext_noop("just-in-time debuggin: write out bitcode"), + NULL, + GUC_NOT_IN_SAMPLE + }, + &jit_dump_bitcode, + false, + NULL, NULL, NULL + }, + +#endif + { {"zero_damaged_pages", PGC_SUSET, DEVELOPER_OPTIONS, gettext_noop("Continues processing past damaged page headers."), diff --git a/src/backend/utils/resowner/resowner.c b/src/backend/utils/resowner/resowner.c index 4a4a287148..3c89db5003 100644 --- a/src/backend/utils/resowner/resowner.c +++ b/src/backend/utils/resowner/resowner.c @@ -27,6 +27,7 @@ #include "utils/rel.h" #include "utils/resowner_private.h" #include "utils/snapmgr.h" +#include "lib/llvmjit.h" /* @@ -124,6 +125,7 @@ typedef struct ResourceOwnerData ResourceArray snapshotarr; /* snapshot references */ ResourceArray filearr; /* open temporary files */ ResourceArray dsmarr; /* dynamic shmem segments */ + ResourceArray jitarr; /* JIT handles */ /* We can remember up to MAX_RESOWNER_LOCKS references to local locks. */ int nlocks; /* number of owned locks */ @@ -437,6 +439,7 @@ ResourceOwnerCreate(ResourceOwner parent, const char *name) ResourceArrayInit(&(owner->snapshotarr), PointerGetDatum(NULL)); ResourceArrayInit(&(owner->filearr), FileGetDatum(-1)); ResourceArrayInit(&(owner->dsmarr), PointerGetDatum(NULL)); + ResourceArrayInit(&(owner->jitarr), Int32GetDatum(-1)); return owner; } @@ -552,6 +555,21 @@ ResourceOwnerReleaseInternal(ResourceOwner owner, PrintDSMLeakWarning(res); dsm_detach(res); } + + /* Ditto for jited functions */ + while (ResourceArrayGetAny(&(owner->jitarr), &foundres)) + { + if (isTopLevel) + llvm_release_handle(owner, foundres); + else + { + ResourceOwnerForgetJIT(owner, foundres); + ResourceOwnerEnlargeJIT(owner->parent); + ResourceOwnerRememberJIT(owner->parent, foundres); + + } + } + } else if (phase == RESOURCE_RELEASE_LOCKS) { @@ -699,6 +717,7 @@ ResourceOwnerDelete(ResourceOwner owner) Assert(owner->snapshotarr.nitems == 0); Assert(owner->filearr.nitems == 0); Assert(owner->dsmarr.nitems == 0); + Assert(owner->jitarr.nitems == 0); Assert(owner->nlocks == 0 || owner->nlocks == MAX_RESOWNER_LOCKS + 1); /* @@ -725,6 +744,7 @@ ResourceOwnerDelete(ResourceOwner owner) ResourceArrayFree(&(owner->snapshotarr)); ResourceArrayFree(&(owner->filearr)); ResourceArrayFree(&(owner->dsmarr)); + ResourceArrayFree(&(owner->jitarr)); pfree(owner); } @@ -1267,3 +1287,23 @@ PrintDSMLeakWarning(dsm_segment *seg) elog(WARNING, "dynamic shared memory leak: segment %u still referenced", dsm_segment_handle(seg)); } + +void +ResourceOwnerEnlargeJIT(ResourceOwner owner) +{ + ResourceArrayEnlarge(&(owner->jitarr)); +} + +void +ResourceOwnerRememberJIT(ResourceOwner owner, Datum handle) +{ + ResourceArrayAdd(&(owner->jitarr), handle); +} + +void +ResourceOwnerForgetJIT(ResourceOwner owner, Datum handle) +{ + if (!ResourceArrayRemove(&(owner->jitarr), handle)) + elog(ERROR, "jit %lu is not owned by resource owner %s", + handle, owner->name); +} diff --git a/src/include/lib/llvmjit.h b/src/include/lib/llvmjit.h new file mode 100644 index 0000000000..82b0b91c93 --- /dev/null +++ b/src/include/lib/llvmjit.h @@ -0,0 +1,83 @@ +#ifndef LLVMJIT_H +#define LLVMJIT_H + +#include "utils/resowner.h" + +#ifdef USE_LLVM + +/* symbol conflict :( */ +#undef PM + +#include "nodes/pg_list.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct LLVMJitContext +{ + int counter; + LLVMModuleRef module; + bool compiled; + List *handles; +} LLVMJitContext; + +extern bool jit_log_ir; +extern bool jit_dump_bitcode; + +extern LLVMTargetMachineRef llvm_targetmachine; +extern const char *llvm_triple; + +extern LLVMTypeRef TypeSizeT; +extern LLVMTypeRef TypePGFunction; +extern LLVMTypeRef TypeMemoryContext; + +extern LLVMTypeRef StructFormPgAttribute; +extern LLVMTypeRef StructTupleConstr; +extern LLVMTypeRef StructtupleDesc; +extern LLVMTypeRef StructHeapTupleFields; +extern LLVMTypeRef StructHeapTupleFieldsField3; +extern LLVMTypeRef StructHeapTupleHeaderData; +extern LLVMTypeRef StructHeapTupleDataChoice; +extern LLVMTypeRef StructHeapTupleData; +extern LLVMTypeRef StructMinimalTupleData; +extern LLVMTypeRef StructItemPointerData; +extern LLVMTypeRef StructBlockId; +extern LLVMTypeRef StructTupleTableSlot; +extern LLVMTypeRef StructMemoryContextData; +extern LLVMTypeRef StructPGFinfoRecord; +extern LLVMTypeRef StructFmgrInfo; +extern LLVMTypeRef StructFunctionCallInfoData; +extern LLVMTypeRef StructExprState; +extern LLVMTypeRef StructExprContext; + +extern void llvm_initialize(void); +extern void llvm_dispose_module(LLVMModuleRef mod, const char *funcname); + +extern void *llvm_get_function(LLVMJitContext *context, const char *funcname); + +extern void llvm_perf_support(LLVMExecutionEngineRef EE); +extern void llvm_shutdown_perf_support(LLVMExecutionEngineRef EE); + +extern void llvm_perf_orc_support(LLVMOrcJITStackRef llvm_orc); +extern void llvm_shutdown_orc_perf_support(LLVMOrcJITStackRef llvm_orc); + +#else + +typedef struct LLVMJitContext +{ +} LLVMJitContext; + +#endif /* USE_LLVM */ + +extern void llvm_release_handle(ResourceOwner resowner, Datum handle); + +#endif /* LLVMJIT_H */ diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 90a60abc4d..0dc9fa8d79 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -508,7 +508,9 @@ typedef struct EState bool *es_epqScanDone; /* true if EPQ tuple has been fetched */ /* The per-query shared memory area to use for parallel execution. */ - struct dsa_area *es_query_dsa; + struct dsa_area *es_query_dsa; + + struct LLVMJitContext *es_jit; } EState; diff --git a/src/include/utils/resowner_private.h b/src/include/utils/resowner_private.h index 2420b651b3..1921e4e666 100644 --- a/src/include/utils/resowner_private.h +++ b/src/include/utils/resowner_private.h @@ -88,4 +88,11 @@ extern void ResourceOwnerRememberDSM(ResourceOwner owner, extern void ResourceOwnerForgetDSM(ResourceOwner owner, dsm_segment *); +/* support for JITed functions */ +extern void ResourceOwnerEnlargeJIT(ResourceOwner owner); +extern void ResourceOwnerRememberJIT(ResourceOwner owner, + Datum handle); +extern void ResourceOwnerForgetJIT(ResourceOwner owner, + Datum handle); + #endif /* RESOWNER_PRIVATE_H */ -- 2.14.1.2.g4274c698f4.dirty