diff options
author | Thomas Munro <tmunro@postgresql.org> | 2023-10-18 22:09:05 +1300 |
---|---|---|
committer | Thomas Munro <tmunro@postgresql.org> | 2023-10-18 23:18:16 +1300 |
commit | 15ddc9725eb73d97a16652c7c90d993302773544 (patch) | |
tree | 62edba6b6ed3af6c3ae417f9e508c9e2dd357505 /src/backend/jit/llvm/llvmjit.c | |
parent | 0e32652a79164965e8ef409bb84804a6e608e9ea (diff) | |
download | postgresql-15ddc9725eb73d97a16652c7c90d993302773544.tar.gz postgresql-15ddc9725eb73d97a16652c7c90d993302773544.zip |
jit: Support opaque pointers in LLVM 16.
Remove use of LLVMGetElementType() and provide the type of all pointers
to LLVMBuildXXX() functions when emitting IR, as required by modern LLVM
versions[1].
* For LLVM <= 14, we'll still use the old LLVMBuildXXX() functions.
* For LLVM == 15, we'll continue to do the same, explicitly opting
out of opaque pointer mode.
* For LLVM >= 16, we'll use the new LLVMBuildXXX2() functions that take
the extra type argument.
The difference is hidden behind some new IR emitting wrapper functions
l_load(), l_gep(), l_call() etc. The change is mostly mechanical,
except that at each site the correct type had to be provided.
In some places we needed to do some extra work to get functions types,
including some new wrappers for C++ APIs that are not yet exposed by in
LLVM's C API, and some new "example" functions in llvmjit_types.c
because it's no longer possible to start from the function pointer type
and ask for the function type.
Back-patch to 12, because it's a little tricker in 11 and we agreed not
to put the latest LLVM support into the upcoming final release of 11.
[1] https://llvm.org/docs/OpaquePointers.html
Reviewed-by: Dmitry Dolgov <9erthalion6@gmail.com>
Reviewed-by: Ronan Dunklau <ronan.dunklau@aiven.io>
Reviewed-by: Andres Freund <andres@anarazel.de>
Discussion: https://postgr.es/m/CA%2BhUKGKNX_%3Df%2B1C4r06WETKTq0G4Z_7q4L4Fxn5WWpMycDj9Fw%40mail.gmail.com
Diffstat (limited to 'src/backend/jit/llvm/llvmjit.c')
-rw-r--r-- | src/backend/jit/llvm/llvmjit.c | 193 |
1 files changed, 97 insertions, 96 deletions
diff --git a/src/backend/jit/llvm/llvmjit.c b/src/backend/jit/llvm/llvmjit.c index 67ebf6248e9..3867ec589d2 100644 --- a/src/backend/jit/llvm/llvmjit.c +++ b/src/backend/jit/llvm/llvmjit.c @@ -89,18 +89,12 @@ LLVMTypeRef StructExprState; LLVMTypeRef StructAggState; LLVMTypeRef StructAggStatePerGroupData; LLVMTypeRef StructAggStatePerTransData; +LLVMTypeRef StructPlanState; LLVMValueRef AttributeTemplate; -LLVMValueRef FuncStrlen; -LLVMValueRef FuncVarsizeAny; -LLVMValueRef FuncSlotGetsomeattrsInt; -LLVMValueRef FuncSlotGetmissingattrs; -LLVMValueRef FuncMakeExpandedObjectReadOnlyInternal; -LLVMValueRef FuncExecEvalSubscriptingRef; -LLVMValueRef FuncExecEvalSysVar; -LLVMValueRef FuncExecAggTransReparent; -LLVMValueRef FuncExecAggInitGroup; +LLVMValueRef ExecEvalSubroutineTemplate; +LLVMModuleRef llvm_types_module = NULL; static bool llvm_session_initialized = false; static size_t llvm_generation = 0; @@ -382,26 +376,71 @@ llvm_get_function(LLVMJitContext *context, const char *funcname) } /* - * Return declaration for passed function, adding it to the module if - * necessary. + * Return type of a variable in llvmjit_types.c. This is useful to keep types + * in sync between plain C and JIT related code. + */ +LLVMTypeRef +llvm_pg_var_type(const char *varname) +{ + LLVMValueRef v_srcvar; + LLVMTypeRef typ; + + /* this'll return a *pointer* to the global */ + v_srcvar = LLVMGetNamedGlobal(llvm_types_module, varname); + if (!v_srcvar) + elog(ERROR, "variable %s not in llvmjit_types.c", varname); + + typ = LLVMGlobalGetValueType(v_srcvar); + + return typ; +} + +/* + * Return function type of a variable in llvmjit_types.c. This is useful to + * keep function types in sync between C and JITed code. + */ +LLVMTypeRef +llvm_pg_var_func_type(const char *varname) +{ + LLVMValueRef v_srcvar; + LLVMTypeRef typ; + + v_srcvar = LLVMGetNamedFunction(llvm_types_module, varname); + if (!v_srcvar) + elog(ERROR, "function %s not in llvmjit_types.c", varname); + + typ = LLVMGetFunctionType(v_srcvar); + + return typ; +} + +/* + * Return declaration for a function referenced in llvmjit_types.c, adding it + * to the module if necessary. * - * This is used to make functions imported by llvm_create_types() known to the - * module that's currently being worked on. + * This is used to make functions discovered via llvm_create_types() known to + * the module that's currently being worked on. */ LLVMValueRef -llvm_get_decl(LLVMModuleRef mod, LLVMValueRef v_src) +llvm_pg_func(LLVMModuleRef mod, const char *funcname) { + LLVMValueRef v_srcfn; LLVMValueRef v_fn; /* don't repeatedly add function */ - v_fn = LLVMGetNamedFunction(mod, LLVMGetValueName(v_src)); + v_fn = LLVMGetNamedFunction(mod, funcname); if (v_fn) return v_fn; + v_srcfn = LLVMGetNamedFunction(llvm_types_module, funcname); + + if (!v_srcfn) + elog(ERROR, "function %s not in llvmjit_types.c", funcname); + v_fn = LLVMAddFunction(mod, - LLVMGetValueName(v_src), - LLVMGetElementType(LLVMTypeOf(v_src))); - llvm_copy_attributes(v_src, v_fn); + funcname, + LLVMGetFunctionType(v_srcfn)); + llvm_copy_attributes(v_srcfn, v_fn); return v_fn; } @@ -496,7 +535,7 @@ llvm_function_reference(LLVMJitContext *context, fcinfo->flinfo->fn_oid); v_fn = LLVMGetNamedGlobal(mod, funcname); if (v_fn != 0) - return LLVMBuildLoad(builder, v_fn, ""); + return l_load(builder, TypePGFunction, v_fn, ""); v_fn_addr = l_ptr_const(fcinfo->flinfo->fn_addr, TypePGFunction); @@ -506,7 +545,7 @@ llvm_function_reference(LLVMJitContext *context, LLVMSetLinkage(v_fn, LLVMPrivateLinkage); LLVMSetUnnamedAddr(v_fn, true); - return LLVMBuildLoad(builder, v_fn, ""); + return l_load(builder, TypePGFunction, v_fn, ""); } /* check if function already has been added */ @@ -514,7 +553,7 @@ llvm_function_reference(LLVMJitContext *context, if (v_fn != 0) return v_fn; - v_fn = LLVMAddFunction(mod, funcname, LLVMGetElementType(TypePGFunction)); + v_fn = LLVMAddFunction(mod, funcname, LLVMGetFunctionType(AttributeTemplate)); return v_fn; } @@ -766,12 +805,15 @@ llvm_session_initialize(void) LLVMInitializeNativeAsmParser(); /* - * When targeting an LLVM version with opaque pointers enabled by - * default, turn them off for the context we build our code in. We don't - * need to do so for other contexts (e.g. llvm_ts_context). Once the IR is - * generated, it carries the necessary information. + * When targeting LLVM 15, turn off opaque pointers for the context we + * build our code in. We don't need to do so for other contexts (e.g. + * llvm_ts_context). Once the IR is generated, it carries the necessary + * information. + * + * For 16 and above, opaque pointers must be used, and we have special + * code for that. */ -#if LLVM_VERSION_MAJOR > 14 +#if LLVM_VERSION_MAJOR == 15 LLVMContextSetOpaquePointers(LLVMGetGlobalContext(), false); #endif @@ -921,26 +963,6 @@ llvm_shutdown(int code, Datum arg) #endif /* LLVM_VERSION_MAJOR > 11 */ } -/* helper for llvm_create_types, returning a global var's type */ -static LLVMTypeRef -load_type(LLVMModuleRef mod, const char *name) -{ - LLVMValueRef value; - LLVMTypeRef typ; - - /* this'll return a *pointer* to the global */ - value = LLVMGetNamedGlobal(mod, name); - if (!value) - elog(ERROR, "type %s is unknown", name); - - /* therefore look at the contained type and return that */ - typ = LLVMTypeOf(value); - Assert(typ != NULL); - typ = LLVMGetElementType(typ); - Assert(typ != NULL); - return typ; -} - /* helper for llvm_create_types, returning a function's return type */ static LLVMTypeRef load_return_type(LLVMModuleRef mod, const char *name) @@ -953,15 +975,7 @@ load_return_type(LLVMModuleRef mod, const char *name) if (!value) elog(ERROR, "function %s is unknown", name); - /* get type of function pointer */ - typ = LLVMTypeOf(value); - Assert(typ != NULL); - /* dereference pointer */ - typ = LLVMGetElementType(typ); - Assert(typ != NULL); - /* and look at return type */ - typ = LLVMGetReturnType(typ); - Assert(typ != NULL); + typ = LLVMGetFunctionReturnType(value); /* in llvmjit_wrap.cpp */ return typ; } @@ -978,7 +992,6 @@ llvm_create_types(void) char path[MAXPGPATH]; LLVMMemoryBufferRef buf; char *msg; - LLVMModuleRef mod = NULL; snprintf(path, MAXPGPATH, "%s/%s", pkglib_path, "llvmjit_types.bc"); @@ -990,7 +1003,7 @@ llvm_create_types(void) } /* eagerly load contents, going to need it all */ - if (LLVMParseBitcode2(buf, &mod)) + if (LLVMParseBitcode2(buf, &llvm_types_module)) { elog(ERROR, "LLVMParseBitcode2 of %s failed", path); } @@ -1000,45 +1013,33 @@ llvm_create_types(void) * Load triple & layout from clang emitted file so we're guaranteed to be * compatible. */ - llvm_triple = pstrdup(LLVMGetTarget(mod)); - llvm_layout = pstrdup(LLVMGetDataLayoutStr(mod)); - - TypeSizeT = load_type(mod, "TypeSizeT"); - TypeParamBool = load_return_type(mod, "FunctionReturningBool"); - TypeStorageBool = load_type(mod, "TypeStorageBool"); - TypePGFunction = load_type(mod, "TypePGFunction"); - StructNullableDatum = load_type(mod, "StructNullableDatum"); - StructExprContext = load_type(mod, "StructExprContext"); - StructExprEvalStep = load_type(mod, "StructExprEvalStep"); - StructExprState = load_type(mod, "StructExprState"); - StructFunctionCallInfoData = load_type(mod, "StructFunctionCallInfoData"); - StructMemoryContextData = load_type(mod, "StructMemoryContextData"); - StructTupleTableSlot = load_type(mod, "StructTupleTableSlot"); - StructHeapTupleTableSlot = load_type(mod, "StructHeapTupleTableSlot"); - StructMinimalTupleTableSlot = load_type(mod, "StructMinimalTupleTableSlot"); - StructHeapTupleData = load_type(mod, "StructHeapTupleData"); - StructTupleDescData = load_type(mod, "StructTupleDescData"); - StructAggState = load_type(mod, "StructAggState"); - StructAggStatePerGroupData = load_type(mod, "StructAggStatePerGroupData"); - StructAggStatePerTransData = load_type(mod, "StructAggStatePerTransData"); - - AttributeTemplate = LLVMGetNamedFunction(mod, "AttributeTemplate"); - FuncStrlen = LLVMGetNamedFunction(mod, "strlen"); - FuncVarsizeAny = LLVMGetNamedFunction(mod, "varsize_any"); - FuncSlotGetsomeattrsInt = LLVMGetNamedFunction(mod, "slot_getsomeattrs_int"); - FuncSlotGetmissingattrs = LLVMGetNamedFunction(mod, "slot_getmissingattrs"); - FuncMakeExpandedObjectReadOnlyInternal = LLVMGetNamedFunction(mod, "MakeExpandedObjectReadOnlyInternal"); - FuncExecEvalSubscriptingRef = LLVMGetNamedFunction(mod, "ExecEvalSubscriptingRef"); - FuncExecEvalSysVar = LLVMGetNamedFunction(mod, "ExecEvalSysVar"); - FuncExecAggTransReparent = LLVMGetNamedFunction(mod, "ExecAggTransReparent"); - FuncExecAggInitGroup = LLVMGetNamedFunction(mod, "ExecAggInitGroup"); - - /* - * Leave the module alive, otherwise references to function would be - * dangling. - */ - - return; + llvm_triple = pstrdup(LLVMGetTarget(llvm_types_module)); + llvm_layout = pstrdup(LLVMGetDataLayoutStr(llvm_types_module)); + + TypeSizeT = llvm_pg_var_type("TypeSizeT"); + TypeParamBool = load_return_type(llvm_types_module, "FunctionReturningBool"); + TypeStorageBool = llvm_pg_var_type("TypeStorageBool"); + TypePGFunction = llvm_pg_var_type("TypePGFunction"); + StructNullableDatum = llvm_pg_var_type("StructNullableDatum"); + StructExprContext = llvm_pg_var_type("StructExprContext"); + StructExprEvalStep = llvm_pg_var_type("StructExprEvalStep"); + StructExprState = llvm_pg_var_type("StructExprState"); + StructFunctionCallInfoData = llvm_pg_var_type("StructFunctionCallInfoData"); + StructMemoryContextData = llvm_pg_var_type("StructMemoryContextData"); + StructTupleTableSlot = llvm_pg_var_type("StructTupleTableSlot"); + StructHeapTupleTableSlot = llvm_pg_var_type("StructHeapTupleTableSlot"); + StructMinimalTupleTableSlot = llvm_pg_var_type("StructMinimalTupleTableSlot"); + StructHeapTupleData = llvm_pg_var_type("StructHeapTupleData"); + StructHeapTupleHeaderData = llvm_pg_var_type("StructHeapTupleHeaderData"); + StructTupleDescData = llvm_pg_var_type("StructTupleDescData"); + StructAggState = llvm_pg_var_type("StructAggState"); + StructAggStatePerGroupData = llvm_pg_var_type("StructAggStatePerGroupData"); + StructAggStatePerTransData = llvm_pg_var_type("StructAggStatePerTransData"); + StructPlanState = llvm_pg_var_type("StructPlanState"); + StructMinimalTupleData = llvm_pg_var_type("StructMinimalTupleData"); + + AttributeTemplate = LLVMGetNamedFunction(llvm_types_module, "AttributeTemplate"); + ExecEvalSubroutineTemplate = LLVMGetNamedFunction(llvm_types_module, "ExecEvalSubroutineTemplate"); } /* |