From 7b71bc3ba1dada57dab8cab31a2911256ccf49a0 Mon Sep 17 00:00:00 2001
From: Dmitrii Dolgov <9erthalion6@gmail.com>
Date: Sat, 5 Oct 2024 18:31:36 +0200
Subject: [PATCH v4 3/3] Add JIT provider version to pg_system_versions

Populate pg_system_versions with the JIT provider version. To actually
fetch the version, extend the JIT provider callbacks with the
get_version method. For LLVM provider llvm_version will be used, which
utilizes C-API LLVMGetVersion, available since LLVM 16.

The JIT provider will be initialized, when a first expression will be
compiled. For reporting purposes it's too late, thus register the
version at the backend startup, right after the core versions.
---
 src/backend/jit/jit.c          | 19 +++++++++++++++++++
 src/backend/jit/llvm/llvmjit.c | 19 +++++++++++++++++++
 src/backend/tcop/postgres.c    |  7 +++++++
 src/include/jit/jit.h          | 11 +++++++++++
 src/include/jit/llvmjit.h      |  2 ++
 5 files changed, 58 insertions(+)

diff --git a/src/backend/jit/jit.c b/src/backend/jit/jit.c
index d2ccef9de85..cd6505f0db0 100644
--- a/src/backend/jit/jit.c
+++ b/src/backend/jit/jit.c
@@ -188,3 +188,22 @@ InstrJitAgg(JitInstrumentation *dst, JitInstrumentation *add)
 	INSTR_TIME_ADD(dst->optimization_counter, add->optimization_counter);
 	INSTR_TIME_ADD(dst->emission_counter, add->emission_counter);
 }
+
+/*
+ * Return JIT provider's version string for troubleshooting purposes.
+ */
+const char *
+jit_get_version(bool *available)
+{
+	if (provider_init())
+		return provider.get_version(available);
+
+	*available = false;
+	return "";
+}
+
+void
+jit_register_version(void)
+{
+	add_system_version("LLVM", jit_get_version, RunTime);
+}
diff --git a/src/backend/jit/llvm/llvmjit.c b/src/backend/jit/llvm/llvmjit.c
index e978b996bae..9b40af60464 100644
--- a/src/backend/jit/llvm/llvmjit.c
+++ b/src/backend/jit/llvm/llvmjit.c
@@ -154,6 +154,7 @@ _PG_jit_provider_init(JitProviderCallbacks *cb)
 	cb->reset_after_error = llvm_reset_after_error;
 	cb->release_context = llvm_release_context;
 	cb->compile_expr = llvm_compile_expr;
+	cb->get_version = llvm_version;
 }
 
 
@@ -1280,3 +1281,21 @@ ResOwnerReleaseJitContext(Datum res)
 	context->resowner = NULL;
 	jit_release_context(&context->base);
 }
+
+const char *
+llvm_version(bool *available)
+{
+#if LLVM_VERSION_MAJOR > 15
+	unsigned int major,
+				minor,
+				patch;
+
+	LLVMGetVersion(&major, &minor, &patch);
+
+	*available = true;
+	return (const char *) psprintf("%d.%d.%d", major, minor, patch);
+#else
+	*available = false;
+	return "";
+#endif
+}
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 3a8ff419425..a23a858f2c9 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -5248,4 +5248,11 @@ register_system_versions()
 {
 	/* Set up reporting of core versions. */
 	register_core_versions();
+
+	/*
+	 * Set up reporting for JIT provider version. JIT provider initialization
+	 * happens when the first expression is getting compiled, which is too
+	 * late. Thus register the callback here instead.
+	 */
+	jit_register_version();
 }
diff --git a/src/include/jit/jit.h b/src/include/jit/jit.h
index 33cb36c5d2e..8088ab37256 100644
--- a/src/include/jit/jit.h
+++ b/src/include/jit/jit.h
@@ -13,6 +13,7 @@
 
 #include "executor/instrument.h"
 #include "utils/resowner.h"
+#include "utils/system_version.h"
 
 
 /* Flags determining what kind of JIT operations to perform */
@@ -70,12 +71,14 @@ typedef void (*JitProviderResetAfterErrorCB) (void);
 typedef void (*JitProviderReleaseContextCB) (JitContext *context);
 struct ExprState;
 typedef bool (*JitProviderCompileExprCB) (struct ExprState *state);
+typedef const char *(*JitProviderVersion) (bool *available);
 
 struct JitProviderCallbacks
 {
 	JitProviderResetAfterErrorCB reset_after_error;
 	JitProviderReleaseContextCB release_context;
 	JitProviderCompileExprCB compile_expr;
+	JitProviderVersion get_version;
 };
 
 
@@ -102,5 +105,13 @@ extern void jit_release_context(JitContext *context);
 extern bool jit_compile_expr(struct ExprState *state);
 extern void InstrJitAgg(JitInstrumentation *dst, JitInstrumentation *add);
 
+/*
+ * Get the provider's version string. The flag indicating availability is
+ * passed as an argument, and will be set accordingly if it's not possible to
+ * get the version.
+ */
+extern const char *jit_get_version(bool *available);
+
+extern void jit_register_version(void);
 
 #endif							/* JIT_H */
diff --git a/src/include/jit/llvmjit.h b/src/include/jit/llvmjit.h
index b3c75022f55..1125451fbf5 100644
--- a/src/include/jit/llvmjit.h
+++ b/src/include/jit/llvmjit.h
@@ -145,6 +145,8 @@ extern LLVMTypeRef LLVMGetFunctionType(LLVMValueRef r);
 extern LLVMOrcObjectLayerRef LLVMOrcCreateRTDyldObjectLinkingLayerWithSafeSectionMemoryManager(LLVMOrcExecutionSessionRef ES);
 #endif
 
+extern const char* llvm_version(bool *available);
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
-- 
2.49.0

