From d4d14a092bf15f7b389a5803d745b085f122e5c4 Mon Sep 17 00:00:00 2001
From: soumyadeep2007 <sochakraborty@pivotal.io>
Date: Tue, 17 Sep 2019 09:21:48 -0700
Subject: [PATCH v2 1/2] Don't codegen if tuple is virtual in expr eval of scan
 fetch

Delete the resulting empty opblock and replace all of its uses with that
of its successor opblock.
---
 src/backend/jit/llvm/llvmjit_expr.c | 53 +++++++++++++++++++++++------
 1 file changed, 43 insertions(+), 10 deletions(-)

diff --git a/src/backend/jit/llvm/llvmjit_expr.c b/src/backend/jit/llvm/llvmjit_expr.c
index 30133634c7..52f20fe787 100644
--- a/src/backend/jit/llvm/llvmjit_expr.c
+++ b/src/backend/jit/llvm/llvmjit_expr.c
@@ -65,6 +65,8 @@ static void build_EvalXFunc(LLVMBuilderRef b, LLVMModuleRef mod,
 							ExprEvalStep *op);
 static LLVMValueRef create_LifetimeEnd(LLVMModuleRef mod);
 
+static void eliminate_empty_opblock(LLVMBasicBlockRef opblock,
+									LLVMBasicBlockRef successor);
 
 /*
  * JIT compile expression.
@@ -278,14 +280,23 @@ llvm_compile_expr(ExprState *state)
 					LLVMValueRef l_jit_deform = NULL;
 					const TupleTableSlotOps *tts_ops = NULL;
 
-					b_fetch = l_bb_before_v(opblocks[i + 1],
-											"op.%d.fetch", i);
-
 					if (op->d.fetch.known_desc)
 						desc = op->d.fetch.known_desc;
 
 					if (op->d.fetch.fixed)
+					{
 						tts_ops = op->d.fetch.kind;
+						/*
+						 * Deforming is not required if the tuple is virtual.
+						 * In such a case, the current opblock is redundant and
+						 * should be unlinked from it's predecessors and removed.
+						 */
+						if (tts_ops && tts_ops == &TTSOpsVirtual)
+						{
+							eliminate_empty_opblock(opblocks[i], opblocks[i + 1]);
+							break;
+						}
+					}
 
 					if (opcode == EEOP_INNER_FETCHSOME)
 						v_slot = v_innerslot;
@@ -294,13 +305,8 @@ llvm_compile_expr(ExprState *state)
 					else
 						v_slot = v_scanslot;
 
-					/*
-					 * Check if all required attributes are available, or
-					 * whether deforming is required.
-					 *
-					 * TODO: skip nvalid check if slot is fixed and known to
-					 * be a virtual slot.
-					 */
+					b_fetch = l_bb_before_v(opblocks[i + 1],
+											"op.%d.fetch", i);
 					v_nvalid =
 						l_load_struct_gep(b, v_slot,
 										  FIELDNO_TUPLETABLESLOT_NVALID,
@@ -2603,3 +2609,30 @@ create_LifetimeEnd(LLVMModuleRef mod)
 
 	return fn;
 }
+
+/*
+ * Unlink given opblock from CFG and remove it.
+ */
+static void
+eliminate_empty_opblock(LLVMBasicBlockRef opblock,
+						LLVMBasicBlockRef successor)
+{
+	LLVMUseRef   useRef = NULL;
+	LLVMValueRef instr   = NULL;
+	/*
+	 * Assert that all uses are terminator instructions of the opblock's
+	 * predecessors. We want to rewire all such references of the opblock to
+	 * point to its successor.
+	 */
+	useRef = LLVMGetFirstUse((LLVMValueRef) opblock);
+	for (; useRef != NULL; useRef = LLVMGetNextUse(useRef))
+	{
+		instr = LLVMGetUser(useRef);
+		Assert (LLVMIsATerminatorInst(instr));
+	}
+	/*
+	 * Perform the rewiring and delete the opblock.
+	 */
+	LLVMReplaceAllUsesWith((LLVMValueRef) opblock, (LLVMValueRef) successor);
+	LLVMDeleteBasicBlock(opblock);
+}
-- 
2.23.0

