From cb5cb74461ac9407c16903bfa9d2855f4e76918e Mon Sep 17 00:00:00 2001
From: Pierre Ducroquet <pinaraf@pinaraf.info>
Date: Wed, 7 Jan 2026 15:43:19 +0100
Subject: [PATCH] llvmjit: always use the simplifycfg pass

The simplifycfg pass will remove empty or unreachable LLVM basic blocks,
and merge blocks together when possible.
This is important because the tuple  deforming code will generate a lot of
basic blocks, and previously with O0 we did not run this pass, thus creating
this kind of (amd64) machine code:
   0x723382b781c1:      jmp    0x723382b781c3
   0x723382b781c3:      jmp    0x723382b781eb
   0x723382b781c5:      mov    -0x20(%rsp),%rax
   0x723382b781..:      ...    .....
   0x723382b781e7:      mov    %cx,(%rax)
   0x723382b781ea:      ret
   0x723382b781eb:      jmp    0x723382b781ed
   0x723382b781ed:      jmp    0x723382b781ef
   0x723382b781ef:      jmp    0x723382b781f1
   0x723382b781f1:      jmp    0x723382b781f3
   0x723382b781f3:      mov    -0x30(%rsp),%rax
   0x723382b781..:      ...    ......
   0x723382b78208:      mov    %rcx,(%rax)
   0x723382b7820b:      jmp    0x723382b781c5

This is not efficient at all, and triggering the simplifycfg pass ends up
tacking a few hundreds micro seconds while possibly saving much more time
during execution. On a basic benchmark, I saved 7ms on query runtime while
using 0.2ms on extra JIT compilation overhead
---
 src/backend/jit/llvm/llvmjit.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/src/backend/jit/llvm/llvmjit.c b/src/backend/jit/llvm/llvmjit.c
index 2e8aa4749db..c22f83e97cf 100644
--- a/src/backend/jit/llvm/llvmjit.c
+++ b/src/backend/jit/llvm/llvmjit.c
@@ -633,6 +633,11 @@ llvm_optimize_module(LLVMJitContext *context, LLVMModuleRef module)
 	{
 		/* we rely on mem2reg heavily, so emit even in the O0 case */
 		LLVMAddPromoteMemoryToRegisterPass(llvm_fpm);
+		/*
+		 * the tuple deforming generates a lot of basic blocks,
+		 * simplify them even with O0
+		 */
+		LLVMAddCFGSimplificationPass(llvm_fpm);
 	}
 
 	LLVMPassManagerBuilderPopulateFunctionPassManager(llvm_pmb, llvm_fpm);
@@ -676,10 +681,10 @@ llvm_optimize_module(LLVMJitContext *context, LLVMModuleRef module)
 		passes = "default<O3>";
 	else if (context->base.flags & PGJIT_INLINE)
 		/* if doing inlining, but no expensive optimization, add inline pass */
-		passes = "default<O0>,mem2reg,inline";
+		passes = "default<O0>,mem2reg,simplifycfg,inline";
 	else
 		/* default<O0> includes always-inline pass */
-		passes = "default<O0>,mem2reg";
+		passes = "default<O0>,mem2reg,simplifycfg";
 
 	options = LLVMCreatePassBuilderOptions();
 
-- 
2.43.0

