On Sun, Jan 4, 2026 at 6:02 PM Thomas Munro <[email protected]> wrote:
> On Sat, Jan 3, 2026 at 3:02 PM Thomas Munro <[email protected]> wrote:
> > 1.  We won't need our local llvm::backport::SectionMemoryManager for
> > LLVM 22, so it will be nice to draw a line under that messy business.
> > See commit message for details.
>
> While that's true, there is a problem with the patch I posted:
> "ReserveAlloc" is not enabled when called from C.  I can't actually
> reproduce the issue locally due to lack of RAM connected to an ARM
> CPU, or I'd have noticed that...  I'll attempt to do something about
> that upstream[1], let's see...  if not, we can still use the new
> in-tree SectionMemoryManager, but we'll still need some C++ glue code.

That was successful, so here is an update.

A new unrelated assertion started firing in LLVM main/22 a few days ago:

    v_nullbytemask = l_int8_const(lc, 1 << ((attnum) & 0x07));
    Assertion failed: (llvm::isUIntN(BitWidth, val) && "Value is not
an N-bit unsigned value")

Here is a fix for that.
From 8f799057689934dd6099ba911a1450499a61f7b6 Mon Sep 17 00:00:00 2001
From: Thomas Munro <[email protected]>
Date: Wed, 31 Dec 2025 17:35:04 +1300
Subject: [PATCH v2 1/3] jit: Skip local SectionMemoryManager for LLVM 22.

LLVM 22 has the fix that we copied into our tree in commit 9044fc1d and
a new function to reach it[1][2], so we only need to use our local copy
for LLVM < 22.

The only change that we don't have from the version that was committed
is the addition of the LLVM_ABI macro to control shared library exports,
but that isn't defined before LLVM 20 (our copy has to work with earlier
versions), and isn't appropriate here as our copy is private and in our
own library.

[1] https://github.com/llvm/llvm-project/pull/71968
[2] https://github.com/llvm/llvm-project/pull/174307

Backpatch-through: 14
Discussion: https://postgr.es/m/CA%2BhUKGJTumad75o8Zao-LFseEbt%3DenbUFCM7LZVV%3Dc8yg2i7dg%40mail.gmail.com
---
 src/backend/jit/llvm/SectionMemoryManager.cpp | 22 ++++++-------------
 src/backend/jit/llvm/llvmjit.c                |  5 ++++-
 src/include/jit/SectionMemoryManager.h        |  2 +-
 src/include/jit/llvmjit_backport.h            |  4 ++--
 4 files changed, 14 insertions(+), 19 deletions(-)

diff --git a/src/backend/jit/llvm/SectionMemoryManager.cpp b/src/backend/jit/llvm/SectionMemoryManager.cpp
index 2171db5f382..e113ce81a3d 100644
--- a/src/backend/jit/llvm/SectionMemoryManager.cpp
+++ b/src/backend/jit/llvm/SectionMemoryManager.cpp
@@ -1,25 +1,17 @@
 /*
- * This file is from https://github.com/llvm/llvm-project/pull/71968
- * with minor modifications to avoid name clash and work with older
- * LLVM versions.  The llvm::backport::SectionMemoryManager class is a
- * drop-in replacement for llvm::SectionMemoryManager, for use with
- * llvm::RuntimeDyld.  It fixes a memory layout bug on large memory
- * ARM systems (see pull request for details).  If the LLVM project
- * eventually commits the change, we may need to resynchronize our
- * copy with any further modifications, but they would be unlikely to
- * backport it into the LLVM versions that we target so we would still
- * need this copy.
+ * This file is from LLVM 22 (originally pull request #71968), with minor
+ * modifications to avoid name clash and work with older LLVM versions.  It
+ * replaces llvm::SectionMemoryManager, and is injected into llvm::RuntimeDyld
+ * to fix a memory layout bug on large memory ARM systems on LLVM < 22.
  *
- * In the future we will switch to using JITLink instead of
- * RuntimeDyld where possible, and later remove this code (.cpp, .h,
- * .LICENSE) after all LLVM versions that we target allow it.
+ * We can remove this code (.cpp, .h, .LICENSE) once LLVM 22 is our minimum
+ * supported version or we've switched to JITLink for at least Aarch64.
  *
  * This file is a modified copy of a part of the LLVM source code that
  * we would normally access from the LLVM library.  It is therefore
  * covered by the license at https://llvm.org/LICENSE.txt, reproduced
  * verbatim in SectionMemoryManager.LICENSE in fulfillment of clause
- * 4a.  The bugfix changes from the pull request are also covered, per
- * clause 5.
+ * 4a.
  */
 
 //===- SectionMemoryManager.cpp - Memory manager for MCJIT/RtDyld *- C++ -*-==//
diff --git a/src/backend/jit/llvm/llvmjit.c b/src/backend/jit/llvm/llvmjit.c
index 8d009dd5cf7..8fb282f6cce 100644
--- a/src/backend/jit/llvm/llvmjit.c
+++ b/src/backend/jit/llvm/llvmjit.c
@@ -1172,7 +1172,10 @@ 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
+#if LLVM_VERSION_MAJOR >= 22
+	LLVMOrcObjectLayerRef objlayer =
+		LLVMOrcCreateRTDyldObjectLinkingLayerWithSectionMemoryManagerReserveAlloc(ES, true);
+#elif defined(USE_LLVM_BACKPORT_SECTION_MEMORY_MANAGER)
 	LLVMOrcObjectLayerRef objlayer =
 		LLVMOrcCreateRTDyldObjectLinkingLayerWithSafeSectionMemoryManager(ES);
 #else
diff --git a/src/include/jit/SectionMemoryManager.h b/src/include/jit/SectionMemoryManager.h
index 924a99b0d33..4c9bd1c7f01 100644
--- a/src/include/jit/SectionMemoryManager.h
+++ b/src/include/jit/SectionMemoryManager.h
@@ -1,5 +1,5 @@
 /*
- * This is a copy LLVM source code modified by the PostgreSQL project.
+ * This is a copy of LLVM source code modified by the PostgreSQL project.
  * See SectionMemoryManager.cpp for notes on provenance and license.
  */
 
diff --git a/src/include/jit/llvmjit_backport.h b/src/include/jit/llvmjit_backport.h
index cba8eafc4f3..71cfdfc832f 100644
--- a/src/include/jit/llvmjit_backport.h
+++ b/src/include/jit/llvmjit_backport.h
@@ -8,14 +8,14 @@
 #include <llvm/Config/llvm-config.h>
 
 /*
- * LLVM's RuntimeDyld can produce code that crashes on larger memory ARM
+ * Pre-LLVM 22 RuntimeDyld can produce code that crashes on large memory ARM
  * systems, because llvm::SectionMemoryManager allocates multiple pieces of
  * memory that can be placed too far apart for the generated code.  See
  * src/backend/jit/llvm/SectionMemoryManager.cpp for the patched replacement
  * class llvm::backport::SectionMemoryManager that we use as a workaround.
  * This header controls whether we use it.
  */
-#if defined(__aarch64__)
+#if defined(__aarch64__) && LLVM_VERSION_MAJOR < 22
 #define USE_LLVM_BACKPORT_SECTION_MEMORY_MANAGER
 #endif
 
-- 
2.52.0

From 9db2fb14b57863fb1b5ab8e211e38c4ed1628c77 Mon Sep 17 00:00:00 2001
From: Thomas Munro <[email protected]>
Date: Wed, 19 Nov 2025 00:00:13 +1300
Subject: [PATCH v2 2/3] jit: Stop using lifetime.end intrinsic for LLVM 22.

The lifetime.end intrinsic can now only be used for stack memory
allocated with alloca.  We were using it to tell the optimizer that we
are no longer interested in the arguments and null flag in a
FunctionCallInfo struct, so it could avoid actually storing them if it
managed to inline the function and keep everything in registers.  It
can't figure that out by itself because it's part of the ExecEvalStep
struct and we scribble on it directly rather than building a new one on
the stack.

Instead, store the special poison value (undef would work too).  This
generates no actual code, but tells the optimizer that we are not
interested in the values.

Deform functions use LLVMBuildAlloca() for a stack variable, but that
memory is reclaimed implicitly by the ret instruction.  This code should
probably do the same, but the change is non-trivial and not studied yet.

https://github.com/llvm/llvm-project/pull/149310
https://llvm.org/docs/LangRef.html#llvm-lifetime-end-intrinsic
https://llvm.org/docs/LangRef.html#i-alloca

Backpatch-through: 14
Reviewed-by: Matheus Alcantara <[email protected]>
Discussion: https://postgr.es/m/CA%2BhUKGJTumad75o8Zao-LFseEbt%3DenbUFCM7LZVV%3Dc8yg2i7dg%40mail.gmail.com
---
 src/backend/jit/llvm/llvmjit_expr.c | 18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/src/backend/jit/llvm/llvmjit_expr.c b/src/backend/jit/llvm/llvmjit_expr.c
index 650f1d42a93..b742cce38cf 100644
--- a/src/backend/jit/llvm/llvmjit_expr.c
+++ b/src/backend/jit/llvm/llvmjit_expr.c
@@ -62,7 +62,9 @@ static LLVMValueRef build_EvalXFuncInt(LLVMBuilderRef b, LLVMModuleRef mod,
 									   LLVMValueRef v_state,
 									   ExprEvalStep *op,
 									   int natts, LLVMValueRef *v_args);
+#if LLVM_VERSION_MAJOR < 22
 static LLVMValueRef create_LifetimeEnd(LLVMModuleRef mod);
+#endif
 
 /* macro making it easier to call ExecEval* functions */
 #define build_EvalXFunc(b, mod, funcname, v_state, op, ...) \
@@ -3007,14 +3009,11 @@ BuildV1Call(LLVMJitContext *context, LLVMBuilderRef b,
 			LLVMModuleRef mod, FunctionCallInfo fcinfo,
 			LLVMValueRef *v_fcinfo_isnull)
 {
-	LLVMContextRef lc;
 	LLVMValueRef v_fn;
 	LLVMValueRef v_fcinfo_isnullp;
 	LLVMValueRef v_retval;
 	LLVMValueRef v_fcinfo;
 
-	lc = LLVMGetModuleContext(mod);
-
 	v_fn = llvm_function_reference(context, b, mod, fcinfo);
 
 	v_fcinfo = l_ptr_const(fcinfo, l_ptr(StructFunctionCallInfoData));
@@ -3031,10 +3030,16 @@ BuildV1Call(LLVMJitContext *context, LLVMBuilderRef b,
 		*v_fcinfo_isnull = l_load(b, TypeStorageBool, v_fcinfo_isnullp, "");
 
 	/*
-	 * Add lifetime-end annotation, signaling that writes to memory don't have
-	 * to be retained (important for inlining potential).
+	 * Signal that writes to FunctionCallInfoData don't have to be retained
+	 * (important for inlining potential).
 	 */
+#if LLVM_VERSION_MAJOR >= 22
+	for (int i = 0; i < fcinfo->nargs; ++i)
+		LLVMBuildStore(b, LLVMGetPoison(StructNullableDatum), l_funcvaluep(b, v_fcinfo, i));
+	LLVMBuildStore(b, LLVMGetPoison(TypeStorageBool), v_fcinfo_isnullp);
+#else
 	{
+		LLVMContextRef lc = LLVMGetModuleContext(mod);
 		LLVMValueRef v_lifetime = create_LifetimeEnd(mod);
 		LLVMValueRef params[2];
 
@@ -3046,6 +3051,7 @@ BuildV1Call(LLVMJitContext *context, LLVMBuilderRef b,
 		params[1] = l_ptr_const(&fcinfo->isnull, l_ptr(LLVMInt8TypeInContext(lc)));
 		l_call(b, LLVMGetFunctionType(v_lifetime), v_lifetime, params, lengthof(params), "");
 	}
+#endif
 
 	return v_retval;
 }
@@ -3083,6 +3089,7 @@ build_EvalXFuncInt(LLVMBuilderRef b, LLVMModuleRef mod, const char *funcname,
 	return v_ret;
 }
 
+#if LLVM_VERSION_MAJOR < 22
 static LLVMValueRef
 create_LifetimeEnd(LLVMModuleRef mod)
 {
@@ -3112,3 +3119,4 @@ create_LifetimeEnd(LLVMModuleRef mod)
 
 	return fn;
 }
+#endif
-- 
2.52.0

From e2551375e0093b8e24821a316edf42c6ff2d7ac7 Mon Sep 17 00:00:00 2001
From: Thomas Munro <[email protected]>
Date: Sun, 11 Jan 2026 12:44:25 +1300
Subject: [PATCH v2 3/3] jit: Fix integer constants for LLVM 22.

LLVM 22 fails an assertion where we do:

  l_int8_const(lc, 1 << ((attnum) & 0x07))

Assertion failed: (llvm::isUIntN(BitWidth, val) && "Value is not an
N-bit unsigned value")

That's because it no longer truncates values to fit the type[1].
Unfortunately our l_intN_const() wrapper functions take signed intN_t
arguments that are internally coerced to unsigned long long, triggering
sign extension.  That was OK with automatic truncation, but now it fails
a bit-width test.

Cast to the corresponding unsigned type first to avoid that.

[1] https://github.com/llvm/llvm-project/commit/a83c89495ba6fe0134dcaa02372c320cc7ff0dbf

Backpatch-through: 14
Reviewed-by:
Discussion: https://postgr.es/m/CA%2BhUKGJTumad75o8Zao-LFseEbt%3DenbUFCM7LZVV%3Dc8yg2i7dg%40mail.gmail.com
---
 src/include/jit/llvmjit_emit.h | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/include/jit/llvmjit_emit.h b/src/include/jit/llvmjit_emit.h
index 089945391ee..83b67dffd25 100644
--- a/src/include/jit/llvmjit_emit.h
+++ b/src/include/jit/llvmjit_emit.h
@@ -47,7 +47,7 @@ l_ptr(LLVMTypeRef t)
 static inline LLVMValueRef
 l_int8_const(LLVMContextRef lc, int8 i)
 {
-	return LLVMConstInt(LLVMInt8TypeInContext(lc), i, false);
+	return LLVMConstInt(LLVMInt8TypeInContext(lc), (uint8) i, false);
 }
 
 /*
@@ -56,7 +56,7 @@ l_int8_const(LLVMContextRef lc, int8 i)
 static inline LLVMValueRef
 l_int16_const(LLVMContextRef lc, int16 i)
 {
-	return LLVMConstInt(LLVMInt16TypeInContext(lc), i, false);
+	return LLVMConstInt(LLVMInt16TypeInContext(lc), (uint16) i, false);
 }
 
 /*
@@ -65,7 +65,7 @@ l_int16_const(LLVMContextRef lc, int16 i)
 static inline LLVMValueRef
 l_int32_const(LLVMContextRef lc, int32 i)
 {
-	return LLVMConstInt(LLVMInt32TypeInContext(lc), i, false);
+	return LLVMConstInt(LLVMInt32TypeInContext(lc), (uint32) i, false);
 }
 
 /*
@@ -74,7 +74,7 @@ l_int32_const(LLVMContextRef lc, int32 i)
 static inline LLVMValueRef
 l_int64_const(LLVMContextRef lc, int64 i)
 {
-	return LLVMConstInt(LLVMInt64TypeInContext(lc), i, false);
+	return LLVMConstInt(LLVMInt64TypeInContext(lc), (uint64) i, false);
 }
 
 /*
-- 
2.52.0

Reply via email to