From 24d375900604935867b0e538a48299dedaace92a Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Thu, 10 Oct 2024 13:31:56 +1300
Subject: [PATCH v1] jit: Add optional LLVM JITLink support.

LLVM's JITLink API is replacing RuntimeDyld, and the latter will
eventually be deprecated and disappear.  Support currently varies by
architecture/platform and LLVM version.  In the case of RISC-V, only
JITLink works, while in some other cases especially in older LLVM
versions, only RuntimeDyld seems to be mature enough.

XXX WIP -- see comments
---
 src/backend/jit/llvm/llvmjit.c        | 25 ++++++++++++++++-----
 src/backend/jit/llvm/llvmjit_wrap.cpp | 31 +++++++++++++++++++++++++--
 src/include/jit/llvmjit.h             |  5 ++++-
 src/include/jit/llvmjit_backport.h    | 10 +++++++++
 4 files changed, 63 insertions(+), 8 deletions(-)

diff --git a/src/backend/jit/llvm/llvmjit.c b/src/backend/jit/llvm/llvmjit.c
index e978b996bae..d87e16f9a0c 100644
--- a/src/backend/jit/llvm/llvmjit.c
+++ b/src/backend/jit/llvm/llvmjit.c
@@ -1172,15 +1172,29 @@ llvm_log_jit_error(void *ctx, LLVMErrorRef error)
 static LLVMOrcObjectLayerRef
 llvm_create_object_layer(void *Ctx, LLVMOrcExecutionSessionRef ES, const char *Triple)
 {
-#ifdef USE_LLVM_BACKPORT_SECTION_MEMORY_MANAGER
-	LLVMOrcObjectLayerRef objlayer =
-		LLVMOrcCreateRTDyldObjectLinkingLayerWithSafeSectionMemoryManager(ES);
+	LLVMOrcObjectLayerRef objlayer;
+
+#if defined(USE_LLVM_JITLINK)
+	objlayer = LLVMOrcCreateJITLinkObjectLinkingLayer(ES);
+#elif defined(USE_LLVM_BACKPORT_SECTION_MEMORY_MANAGER)
+	objlayer = LLVMOrcCreateRTDyldObjectLinkingLayerWithSafeSectionMemoryManager(ES);
 #else
-	LLVMOrcObjectLayerRef objlayer =
-		LLVMOrcCreateRTDyldObjectLinkingLayerWithSectionMemoryManager(ES);
+	objlayer = LLVMOrcCreateRTDyldObjectLinkingLayerWithSectionMemoryManager(ES);
 #endif
 
+	/*
+	 * XXX The JITLink equivalents of the following seem to be:
+	 *
+	 * llvm::orc::PerfSupportPlugin
+	 * llvm::orc::DebuggerSupportPlugin
+	 *
+	 * At least the first arrived in LLVM 18?  Need to decide how to access
+	 * those, either from C like below, or just shove it inot the C++ wrapper
+	 * function, and check if they are feature-equivalent and
+	 * portability-equivalent.
+	 */
 
+#if !defined(USE_LLVM_JITLINK)
 #if defined(HAVE_DECL_LLVMCREATEGDBREGISTRATIONLISTENER) && HAVE_DECL_LLVMCREATEGDBREGISTRATIONLISTENER
 	if (jit_debugging_support)
 	{
@@ -1197,6 +1211,7 @@ llvm_create_object_layer(void *Ctx, LLVMOrcExecutionSessionRef ES, const char *T
 
 		LLVMOrcRTDyldObjectLinkingLayerRegisterJITEventListener(objlayer, l);
 	}
+#endif
 #endif
 
 	return objlayer;
diff --git a/src/backend/jit/llvm/llvmjit_wrap.cpp b/src/backend/jit/llvm/llvmjit_wrap.cpp
index da850d67ab6..ecb97a14944 100644
--- a/src/backend/jit/llvm/llvmjit_wrap.cpp
+++ b/src/backend/jit/llvm/llvmjit_wrap.cpp
@@ -22,6 +22,10 @@ extern "C"
 #include "jit/llvmjit.h"
 #include "jit/llvmjit_backport.h"
 
+#ifdef USE_LLVM_JITLINK
+#include <llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h>
+#endif
+
 #ifdef USE_LLVM_BACKPORT_SECTION_MEMORY_MANAGER
 #include <llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h>
 #include <llvm/ExecutionEngine/SectionMemoryManager.h>
@@ -46,14 +50,37 @@ LLVMGetFunctionType(LLVMValueRef r)
 	return llvm::wrap(llvm::unwrap<llvm::Function>(r)->getFunctionType());
 }
 
-#ifdef USE_LLVM_BACKPORT_SECTION_MEMORY_MANAGER
+#if defined(USE_LLVM_JITLINK) || defined(USE_LLVM_BACKPORT_SECTION_MEMORY_MANAGER)
 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(llvm::orc::ExecutionSession, LLVMOrcExecutionSessionRef)
-DEFINE_SIMPLE_CONVERSION_FUNCTIONS(llvm::orc::ObjectLayer, LLVMOrcObjectLayerRef);
+DEFINE_SIMPLE_CONVERSION_FUNCTIONS(llvm::orc::ObjectLayer, LLVMOrcObjectLayerRef)
+#endif
+
+#if defined(USE_LLVM_JITLINK)
 
+LLVMOrcObjectLayerRef
+LLVMOrcCreateJITLinkObjectLinkingLayer(LLVMOrcExecutionSessionRef ES)
+{
+	auto expected_mm = llvm::jitlink::InProcessMemoryManager::Create();
+
+	/* XXX how should this error be reported? */
+	if (!expected_mm)
+		elog(ERROR,
+			 "could not create JITLink memory manager: %s",
+			 llvm::toString(expected_mm.takeError()).c_str());
+
+	return wrap(new llvm::orc::ObjectLinkingLayer(*unwrap(ES), std::move(*expected_mm)));
+}
+
+#elif defined(USE_LLVM_BACKPORT_SECTION_MEMORY_MANAGER)
+
+/*
+ * Using the older RuntimeDyld API, but with our backported memory manager.
+ */
 LLVMOrcObjectLayerRef
 LLVMOrcCreateRTDyldObjectLinkingLayerWithSafeSectionMemoryManager(LLVMOrcExecutionSessionRef ES)
 {
 	return wrap(new llvm::orc::RTDyldObjectLinkingLayer(
 		*unwrap(ES), [] { return std::make_unique<llvm::backport::SectionMemoryManager>(nullptr, true); }));
 }
+
 #endif
diff --git a/src/include/jit/llvmjit.h b/src/include/jit/llvmjit.h
index b3c75022f55..95004cf12f0 100644
--- a/src/include/jit/llvmjit.h
+++ b/src/include/jit/llvmjit.h
@@ -20,7 +20,7 @@
 #include "jit/llvmjit_backport.h"
 
 #include <llvm-c/Types.h>
-#ifdef USE_LLVM_BACKPORT_SECTION_MEMORY_MANAGER
+#if defined(USE_LLVM_JITLINK) || defined(USE_LLVM_BACKPORT_SECTION_MEMORY_MANAGER)
 #include <llvm-c/OrcEE.h>
 #endif
 
@@ -141,6 +141,9 @@ extern LLVMValueRef slot_compile_deform(struct LLVMJitContext *context, TupleDes
  */
 extern LLVMTypeRef LLVMGetFunctionReturnType(LLVMValueRef r);
 extern LLVMTypeRef LLVMGetFunctionType(LLVMValueRef r);
+#ifdef USE_LLVM_JITLINK
+extern LLVMOrcObjectLayerRef LLVMOrcCreateJITLinkObjectLinkingLayer(LLVMOrcExecutionSessionRef ES);
+#endif
 #ifdef USE_LLVM_BACKPORT_SECTION_MEMORY_MANAGER
 extern LLVMOrcObjectLayerRef LLVMOrcCreateRTDyldObjectLinkingLayerWithSafeSectionMemoryManager(LLVMOrcExecutionSessionRef ES);
 #endif
diff --git a/src/include/jit/llvmjit_backport.h b/src/include/jit/llvmjit_backport.h
index cba8eafc4f3..ed2245d7011 100644
--- a/src/include/jit/llvmjit_backport.h
+++ b/src/include/jit/llvmjit_backport.h
@@ -7,6 +7,15 @@
 
 #include <llvm/Config/llvm-config.h>
 
+/*
+ * On newer LLVM versions, prefer JITLink over RuntimeDyld for linking.
+ * Earlier versions may also work on some platforms.
+ *
+ * XXX What should the conditions be for this?
+ */
+#if LLVM_VERSION_MAJOR >= 19
+#define USE_LLVM_JITLINK
+#else
 /*
  * LLVM's RuntimeDyld can produce code that crashes on larger memory ARM
  * systems, because llvm::SectionMemoryManager allocates multiple pieces of
@@ -18,5 +27,6 @@
 #if defined(__aarch64__)
 #define USE_LLVM_BACKPORT_SECTION_MEMORY_MANAGER
 #endif
+#endif
 
 #endif
-- 
2.39.5 (Apple Git-154)

