From 6c451ae14646f28733d9ff52a660c19de9a817d7 Mon Sep 17 00:00:00 2001
From: Dmitrii Dolgov <9erthalion6@gmail.com>
Date: Sat, 5 Oct 2024 18:31:36 +0200
Subject: [PATCH v6 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                   | 24 ++++++++++++++++++++++++
 src/backend/jit/llvm/llvmjit.c          | 17 +++++++++++++++++
 src/backend/tcop/postgres.c             |  7 +++++++
 src/backend/utils/misc/system_version.c |  7 +++++++
 src/include/jit/jit.h                   |  9 +++++++++
 src/include/jit/llvmjit.h               |  2 ++
 6 files changed, 66 insertions(+)

diff --git a/src/backend/jit/jit.c b/src/backend/jit/jit.c
index d2ccef9de85..9ffefde2a8d 100644
--- a/src/backend/jit/jit.c
+++ b/src/backend/jit/jit.c
@@ -188,3 +188,27 @@ InstrJitAgg(JitInstrumentation *dst, JitInstrumentation *add)
 	INSTR_TIME_ADD(dst->optimization_counter, add->optimization_counter);
 	INSTR_TIME_ADD(dst->emission_counter, add->emission_counter);
 }
+
+/*
+ * Callback for add_system_version, returns JIT provider's version string and
+ * reports if it's not available.
+ */
+const char *
+jit_get_version(bool *available)
+{
+	const char *version;
+
+	if (provider_init())
+	{
+		version = provider.get_version();
+
+		if (version)
+		{
+			*available = true;
+			return version;
+		}
+	}
+
+	*available = false;
+	return "";
+}
diff --git a/src/backend/jit/llvm/llvmjit.c b/src/backend/jit/llvm/llvmjit.c
index e978b996bae..b2f445963ab 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,19 @@ ResOwnerReleaseJitContext(Datum res)
 	context->resowner = NULL;
 	jit_release_context(&context->base);
 }
+
+const char *
+llvm_version()
+{
+#if LLVM_VERSION_MAJOR > 15
+	unsigned int major,
+				minor,
+				patch;
+
+	LLVMGetVersion(&major, &minor, &patch);
+
+	return (const char *) psprintf("%d.%d.%d", major, minor, patch);
+#else
+	return NULL;
+#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/backend/utils/misc/system_version.c b/src/backend/utils/misc/system_version.c
index a6061a7c6b6..7721af45362 100644
--- a/src/backend/utils/misc/system_version.c
+++ b/src/backend/utils/misc/system_version.c
@@ -34,6 +34,7 @@
 #endif
 
 #include "funcapi.h"
+#include "jit/jit.h"
 #include "utils/builtins.h"
 #include "utils/system_version.h"
 
@@ -116,6 +117,12 @@ glibc_get_version(bool *available)
 }
 #endif
 
+void
+jit_register_version(void)
+{
+	add_system_version("LLVM", jit_get_version, RunTime);
+}
+
 /*
  * Register versions that describe core components and do not correspond to any
  * individual component.
diff --git a/src/include/jit/jit.h b/src/include/jit/jit.h
index 33cb36c5d2e..5342a282fb4 100644
--- a/src/include/jit/jit.h
+++ b/src/include/jit/jit.h
@@ -70,12 +70,14 @@ typedef void (*JitProviderResetAfterErrorCB) (void);
 typedef void (*JitProviderReleaseContextCB) (JitContext *context);
 struct ExprState;
 typedef bool (*JitProviderCompileExprCB) (struct ExprState *state);
+typedef const char *(*JitProviderVersion) (void);
 
 struct JitProviderCallbacks
 {
 	JitProviderResetAfterErrorCB reset_after_error;
 	JitProviderReleaseContextCB release_context;
 	JitProviderCompileExprCB compile_expr;
+	JitProviderVersion get_version;
 };
 
 
@@ -102,5 +104,12 @@ extern void jit_release_context(JitContext *context);
 extern bool jit_compile_expr(struct ExprState *state);
 extern void InstrJitAgg(JitInstrumentation *dst, JitInstrumentation *add);
 
+/*
+ * Callback for add_system_version, get the provider's version string. The flag
+ * indicating availability is passed as an argument.
+ */
+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..1c903a4dc52 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(void);
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
-- 
2.49.0

