WIP: JITed expression evaluation.
authorAndres Freund <andres@anarazel.de>
Tue, 14 Mar 2017 03:22:10 +0000 (20:22 -0700)
committerAndres Freund <andres@anarazel.de>
Tue, 14 Mar 2017 06:34:02 +0000 (23:34 -0700)
src/backend/executor/Makefile
src/backend/executor/execCompileExpr.c [new file with mode: 0644]
src/backend/executor/execExpr.c
src/backend/utils/misc/guc.c
src/include/executor/execExpr.h
src/include/executor/executor.h

index 2c68e18a5b3680c375519330482e436a9f1232ae..f157041c18f8218712991595bfbb191f56a602bf 100644 (file)
@@ -12,9 +12,9 @@ subdir = src/backend/executor
 top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
-OBJS = execAmi.o execCurrent.o execExpr.o execInterpExpr.o execGrouping.o \
-       execIndexing.o execJunk.o execMain.o execParallel.o execProcnode.o \
-       execQual.o execReplication.o execScan.o execTuples.o \
+OBJS = execAmi.o execCurrent.o execExpr.o execCompileExpr.o execInterpExpr.o \
+       execGrouping.o execIndexing.o execJunk.o execMain.o execParallel.o \
+       execProcnode.o execQual.o execReplication.o execScan.o execTuples.o \
        execUtils.o functions.o instrument.o nodeAppend.o nodeAgg.o \
        nodeBitmapAnd.o nodeBitmapOr.o \
        nodeBitmapHeapscan.o nodeBitmapIndexscan.o \
diff --git a/src/backend/executor/execCompileExpr.c b/src/backend/executor/execCompileExpr.c
new file mode 100644 (file)
index 0000000..ba0d11d
--- /dev/null
@@ -0,0 +1,2338 @@
+/*-------------------------------------------------------------------------
+ *
+ * execCompileExpr.c
+ *   LLVM compilation based expression evaluation.
+ *
+ * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *   src/backend/executor/execCompileExpr.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#ifdef USE_LLVM
+
+#include "access/htup_details.h"
+#include "access/nbtree.h"
+#include "access/tupconvert.h"
+#include "catalog/objectaccess.h"
+#include "catalog/pg_type.h"
+#include "executor/execdebug.h"
+#include "executor/nodeSubplan.h"
+#include "executor/execExpr.h"
+#include "funcapi.h"
+#include "lib/llvmjit.h"
+#include "miscadmin.h"
+#include "nodes/makefuncs.h"
+#include "nodes/nodeFuncs.h"
+#include "optimizer/planner.h"
+#include "parser/parse_coerce.h"
+#include "parser/parsetree.h"
+#include "pgstat.h"
+#include "utils/acl.h"
+#include "utils/builtins.h"
+#include "utils/date.h"
+#include "utils/lsyscache.h"
+#include "utils/memutils.h"
+#include "utils/timestamp.h"
+#include "utils/typcache.h"
+#include "utils/xml.h"
+
+bool jit_expressions = false;
+
+static LLVMTypeRef StructExprState;
+static LLVMTypeRef StructExprContext;
+static LLVMTypeRef TypePGFunction;
+
+static void
+create_types(void)
+{
+   if (!StructExprState)
+   {
+       {
+           LLVMTypeRef members[12];
+
+           members[ 0] = LLVMInt32Type(); /* tag */
+           members[ 1] = LLVMInt8Type(); /* resnull */
+           members[ 2] = TypeSizeT; /* resvalue */
+           members[ 3] = LLVMPointerType(TypeSizeT, 0); /* steps */
+           members[ 4] = LLVMPointerType(StructTupleTableSlot, 0); /* resultslot */
+           members[ 5] = LLVMPointerType(TypeSizeT, 0); /* cb */
+           members[ 5] = LLVMPointerType(TypeSizeT, 0); /* expr */
+           members[ 6] = TypeSizeT; /* steps_alloc */
+           members[ 7] = TypeSizeT; /* steps_len */
+           members[ 8] = LLVMPointerType(TypeSizeT, 0); /* innermost caseval */
+           members[ 9] = LLVMPointerType(LLVMInt8Type(), 0); /* innermost casenull */
+           members[10] = LLVMPointerType(TypeSizeT, 0); /* innermost domainval */
+           members[11] = LLVMPointerType(LLVMInt8Type(), 0); /* innermost domainnull */
+
+           StructExprState = LLVMStructCreateNamed(LLVMGetGlobalContext(),
+                                                   "struct.ExprState");
+           LLVMStructSetBody(StructExprState, members, lengthof(members), false);
+       }
+
+       {
+           LLVMTypeRef members[16];
+
+           members[ 0] = LLVMInt32Type(); /* tag */
+           members[ 1] = LLVMPointerType(StructTupleTableSlot, 0); /* scantuple */
+           members[ 2] = LLVMPointerType(StructTupleTableSlot, 0); /* innertuple */
+           members[ 3] = LLVMPointerType(StructTupleTableSlot, 0); /* outertuple */
+
+           members[ 4] = LLVMPointerType(TypeSizeT, 0); /* per_query_memory */
+           members[ 5] = LLVMPointerType(TypeSizeT, 0); /* per_tuple_memory */
+
+           members[ 6] = LLVMPointerType(TypeSizeT, 0); /* param_exec */
+           members[ 7] = LLVMPointerType(TypeSizeT, 0); /* param_list_info */
+
+           members[ 8] = LLVMPointerType(TypeSizeT, 0); /* aggvalues */
+           members[ 9] = LLVMPointerType(LLVMInt8Type(), 0); /* aggnulls */
+
+           members[10] = TypeSizeT; /* casvalue */
+           members[11] = LLVMInt8Type(); /* casenull */
+
+           members[12] = TypeSizeT; /* domainvalue */
+           members[13] = LLVMInt8Type(); /* domainnull */
+
+           members[14] = LLVMPointerType(TypeSizeT, 0); /* estate */
+           members[15] = LLVMPointerType(TypeSizeT, 0); /* callbacks */
+
+           StructExprContext = LLVMStructCreateNamed(LLVMGetGlobalContext(),
+                                                   "struct.ExprContext");
+           LLVMStructSetBody(StructExprContext, members, lengthof(members), false);
+       }
+
+       {
+           LLVMTypeRef params[1];
+           params[0] = LLVMPointerType(TypeSizeT, 0); /* FIXME: define fmgrinfo properly */
+           TypePGFunction = LLVMFunctionType(TypeSizeT, params, lengthof(params), 0);
+       }
+   }
+}
+
+static LLVMValueRef
+create_slot_getsomeattrs(LLVMModuleRef mod)
+{
+   LLVMTypeRef sig;
+   LLVMValueRef fn;
+   LLVMTypeRef param_types[2];
+
+   param_types[0] = LLVMPointerType(StructTupleTableSlot, 0);
+   param_types[1] = LLVMInt32Type();
+
+   sig = LLVMFunctionType(LLVMInt64Type(), param_types, lengthof(param_types), 0);
+   fn = LLVMAddFunction(mod, "slot_getsomeattrs", sig);
+
+   return fn;
+}
+
+
+static LLVMValueRef
+create_heap_getsysattr(LLVMModuleRef mod)
+{
+   LLVMTypeRef sig;
+   LLVMValueRef fn;
+   LLVMTypeRef param_types[4];
+
+   param_types[0] = LLVMPointerType(StructHeapTupleData, 0);
+   param_types[1] = LLVMInt32Type();
+   param_types[2] = LLVMPointerType(TypeSizeT, 0);
+   param_types[3] = LLVMPointerType(LLVMInt8Type(), 0);
+
+   sig = LLVMFunctionType(LLVMInt64Type(), param_types, lengthof(param_types), 0);
+   fn = LLVMAddFunction(mod, "heap_getsysattr", sig);
+
+   return fn;
+}
+
+static LLVMValueRef
+create_EvalXFunc(LLVMModuleRef mod, const char *funcname)
+{
+   LLVMTypeRef sig;
+   LLVMValueRef fn;
+   LLVMTypeRef param_types[3];
+
+   param_types[0] = LLVMPointerType(StructExprState, 0);
+   param_types[1] = LLVMPointerType(TypeSizeT, 0);
+   param_types[2] = LLVMPointerType(StructExprContext, 0);
+
+   sig = LLVMFunctionType(LLVMVoidType(), param_types, lengthof(param_types), 0);
+   fn = LLVMAddFunction(mod, funcname, sig);
+
+   return fn;
+}
+
+static LLVMValueRef
+create_EvalArrayRefCheckSubscript(LLVMModuleRef mod)
+{
+   LLVMTypeRef sig;
+   LLVMValueRef fn;
+   LLVMTypeRef param_types[3];
+
+   param_types[0] = LLVMPointerType(StructExprState, 0);
+   param_types[1] = LLVMPointerType(TypeSizeT, 0);
+   param_types[2] = LLVMPointerType(StructExprContext, 0);
+
+   sig = LLVMFunctionType(LLVMInt8Type(), param_types, lengthof(param_types), 0);
+   fn = LLVMAddFunction(mod, "ExecEvalArrayRefCheckSubscript", sig);
+
+   return fn;
+}
+
+void
+ExecInstantiateCompiledExpr(ExprState *state)
+{
+   ExprEvalStep   *op;
+   int i = 0;
+   static int exprcounter = 0;
+   char *funcname;
+
+   LLVMBuilderRef builder;
+   LLVMModuleRef mod;
+   LLVMTypeRef eval_sig;
+   LLVMValueRef eval_fn;
+   LLVMBasicBlockRef entry;
+   LLVMBasicBlockRef *opblocks;
+
+   /* referenced functions */
+   LLVMValueRef l_slot_getsomeattrs;
+   LLVMValueRef l_heap_getsysattr = NULL;
+
+   LLVMValueRef l_EvalWholeRowVar = NULL;
+   LLVMValueRef l_EvalParamExec = NULL;
+   LLVMValueRef l_EvalParamExtern = NULL;
+   LLVMValueRef l_EvalRowNull = NULL;
+   LLVMValueRef l_EvalRowNotNull = NULL;
+   LLVMValueRef l_EvalSQLValueFunction = NULL;
+   LLVMValueRef l_EvalCurrentOfExpr = NULL;
+   LLVMValueRef l_EvalArrayExpr = NULL;
+   LLVMValueRef l_EvalArrayCoerce = NULL;
+   LLVMValueRef l_EvalRow = NULL;
+   LLVMValueRef l_EvalMinMax = NULL;
+   LLVMValueRef l_EvalFieldSelect = NULL;
+   LLVMValueRef l_EvalFieldStoreDeForm = NULL;
+   LLVMValueRef l_EvalFieldStoreForm = NULL;
+   LLVMValueRef l_EvalArrayRefCheckSubscript = NULL;
+   LLVMValueRef l_EvalArrayRefFetch = NULL;
+   LLVMValueRef l_EvalArrayRefAssign = NULL;
+   LLVMValueRef l_EvalArrayRefOld = NULL;
+   LLVMValueRef l_EvalConvertRowtype = NULL;
+   LLVMValueRef l_EvalScalarArrayOp = NULL;
+   LLVMValueRef l_EvalConstraintNotNull = NULL;
+   LLVMValueRef l_EvalConstraintCheck = NULL;
+   LLVMValueRef l_EvalXmlExpr = NULL;
+   LLVMValueRef l_EvalGroupingFunc = NULL;
+   LLVMValueRef l_EvalSubPlan = NULL;
+   LLVMValueRef l_EvalAlternativeSubPlan = NULL;
+
+   /* state itself */
+   LLVMValueRef v_state;
+   LLVMValueRef v_econtext;
+
+   /* returnvalue */
+   LLVMValueRef v_isnullp;
+
+   /* tmp vars in state */
+   LLVMValueRef v_tmpvaluep;
+   LLVMValueRef v_tmpisnullp;
+
+   /* slots */
+   LLVMValueRef v_innerslot;
+   LLVMValueRef v_outerslot;
+   LLVMValueRef v_scanslot;
+   LLVMValueRef v_resultslot;
+
+   /* nulls/values of slots */
+   LLVMValueRef v_innervalues;
+   LLVMValueRef v_innernulls;
+   LLVMValueRef v_outervalues;
+   LLVMValueRef v_outernulls;
+   LLVMValueRef v_scanvalues;
+   LLVMValueRef v_scannulls;
+   LLVMValueRef v_resultvalues;
+   LLVMValueRef v_resultnulls;
+
+   /* stuff in econtext */
+   LLVMValueRef v_aggvalues;
+   LLVMValueRef v_aggnulls;
+
+   /* only do JITing if enabled */
+   if (!jit_expressions)
+       return;
+
+   llvm_initialize();
+   create_types();
+
+   /* setup state */
+   op = state->steps;
+
+   funcname = psprintf("evalexpr%d", exprcounter);
+   exprcounter++;
+
+   builder = LLVMCreateBuilder();
+
+   /* Create the signature and function */
+   mod = LLVMModuleCreateWithName(funcname);
+   LLVMAddModule(llvm_engine, mod);
+
+   {
+       LLVMTypeRef param_types[] = {
+           LLVMPointerType(StructExprState, 0), /* state */
+           LLVMPointerType(StructExprContext, 0), /* econtext */
+           LLVMPointerType(LLVMInt8Type(), 0)}; /* isnull */
+       eval_sig = LLVMFunctionType(TypeSizeT, param_types, lengthof(param_types), 0);
+   }
+   eval_fn = LLVMAddFunction(mod, funcname, eval_sig);
+   LLVMSetLinkage(eval_fn, LLVMInternalLinkage);
+   entry = LLVMAppendBasicBlock(eval_fn, "entry");
+
+   /* build referenced functions */
+   l_slot_getsomeattrs = create_slot_getsomeattrs(mod);
+
+   /* build state */
+   v_state = LLVMGetParam(eval_fn, 0);
+   v_econtext = LLVMGetParam(eval_fn, 1);
+   v_isnullp = LLVMGetParam(eval_fn, 2);
+
+   LLVMPositionBuilderAtEnd(builder, entry);
+
+   v_tmpvaluep = LLVMBuildStructGEP(builder, v_state, 2, "v.state.resvalue");
+   v_tmpisnullp = LLVMBuildStructGEP(builder, v_state, 1, "v.state.resnull");
+
+   /* build global slots */
+   v_resultslot = LLVMBuildLoad(builder, LLVMBuildStructGEP(builder, v_state, 4, ""), "v_resultslot");
+   v_scanslot = LLVMBuildLoad(builder, LLVMBuildStructGEP(builder, v_econtext, 1, ""), "v_scanslot");
+   v_innerslot = LLVMBuildLoad(builder, LLVMBuildStructGEP(builder, v_econtext, 2, ""), "v_innerslot");
+   v_outerslot = LLVMBuildLoad(builder, LLVMBuildStructGEP(builder, v_econtext, 3, ""), "v_outerslot");
+
+   /* build global values/isnull pointers */
+   v_scanvalues = LLVMBuildLoad(builder, LLVMBuildStructGEP(builder, v_scanslot, 10, ""), "v_scanvalues");
+   v_scannulls = LLVMBuildLoad(builder, LLVMBuildStructGEP(builder, v_scanslot, 11, ""), "v_scannulls");
+   v_innervalues = LLVMBuildLoad(builder, LLVMBuildStructGEP(builder, v_innerslot, 10, ""), "v_innervalues");
+   v_innernulls = LLVMBuildLoad(builder, LLVMBuildStructGEP(builder, v_innerslot, 11, ""), "v_innernulls");
+   v_outervalues = LLVMBuildLoad(builder, LLVMBuildStructGEP(builder, v_outerslot, 10, ""), "v_outervalues");
+   v_outernulls = LLVMBuildLoad(builder, LLVMBuildStructGEP(builder, v_outerslot, 11, ""), "v_outernulls");
+   v_resultvalues = LLVMBuildLoad(builder, LLVMBuildStructGEP(builder, v_resultslot, 10, ""), "v_resultvalues");
+   v_resultnulls = LLVMBuildLoad(builder, LLVMBuildStructGEP(builder, v_resultslot, 11, ""), "v_resultnulls");
+
+   /* aggvalues/aggnulls */
+   v_aggvalues = LLVMBuildLoad(builder, LLVMBuildStructGEP(builder, v_econtext, 8, ""), "v.econtext.aggvalues");
+   v_aggnulls = LLVMBuildLoad(builder, LLVMBuildStructGEP(builder, v_econtext, 9, ""), "v.econtext.aggnulls");
+
+   /* allocate blocks for each op upfront, so we can do jumps easily */
+   opblocks = palloc(sizeof(LLVMBasicBlockRef) * state->steps_len);
+   for (i = 0; i < state->steps_len;i++)
+   {
+       char *blockname = psprintf("block.op.%d.start", i);
+       opblocks[i] = LLVMAppendBasicBlock(eval_fn, blockname);
+       pfree(blockname);
+   }
+
+   /* jump from entry to first block */
+   LLVMBuildBr(builder, opblocks[0]);
+
+   for (i = 0; i < state->steps_len;i++)
+   {
+       LLVMValueRef v_resvaluep; /* FIXME */
+       LLVMValueRef v_resnullp;
+
+       LLVMPositionBuilderAtEnd(builder, opblocks[i]);
+
+       op = &state->steps[i];
+
+       v_resvaluep = LLVMBuildIntToPtr(
+           builder,
+           LLVMConstInt(TypeSizeT, (intptr_t) op->resvalue, false),
+           LLVMPointerType(TypeSizeT, 0),
+           "v_resvaluep");
+       v_resnullp = LLVMBuildIntToPtr(
+           builder,
+           LLVMConstInt(TypeSizeT, (intptr_t) op->resnull, false),
+           LLVMPointerType(LLVMInt8Type(), 0),
+           "v_resnullp");
+
+       switch ((ExprEvalOp) op->opcode)
+       {
+           case EEO_DONE:
+               {
+                   LLVMValueRef v_tmpisnull, v_tmpvalue;
+
+                   v_tmpvalue = LLVMBuildLoad(builder, v_tmpvaluep, "");
+                   v_tmpisnull = LLVMBuildLoad(builder, v_tmpisnullp, "");
+
+                   LLVMBuildStore(builder, v_tmpisnull, v_isnullp);
+                   LLVMBuildRet(builder, v_tmpvalue);
+                   break;
+               }
+           case EEO_INNER_FETCHSOME:
+           case EEO_OUTER_FETCHSOME:
+           case EEO_SCAN_FETCHSOME:
+               {
+                   LLVMValueRef params[2];
+                   if (op->opcode == EEO_INNER_FETCHSOME)
+                       params[0] = v_innerslot;
+                   else if (op->opcode == EEO_OUTER_FETCHSOME)
+                       params[0] = v_outerslot;
+                   else
+                       params[0] = v_scanslot;
+
+                   params[1] = LLVMConstInt(LLVMInt32Type(), op->d.fetch.last_var, false);
+                   LLVMBuildCall(builder, l_slot_getsomeattrs, params, 2, "");
+
+                   LLVMBuildBr(builder, opblocks[i + 1]);
+                   break;
+               }
+
+       case EEO_INNER_VAR:
+               {
+                   LLVMValueRef value, isnull;
+                   LLVMValueRef v_attnum;
+
+                   v_attnum = LLVMConstInt(LLVMInt32Type(), op->d.var.attnum, false);
+                   value = LLVMBuildLoad(builder, LLVMBuildGEP(builder, v_innervalues, &v_attnum, 1, ""), "");
+                   isnull = LLVMBuildLoad(builder, LLVMBuildGEP(builder, v_innernulls, &v_attnum, 1, ""), "");
+                   LLVMBuildStore(builder, value, v_resvaluep);
+                   LLVMBuildStore(builder, isnull, v_resnullp);
+
+                   LLVMBuildBr(builder, opblocks[i + 1]);
+                   break;
+               }
+           case EEO_OUTER_VAR:
+               {
+                   LLVMValueRef value, isnull;
+                   LLVMValueRef v_attnum;
+
+                   v_attnum = LLVMConstInt(LLVMInt32Type(), op->d.var.attnum, false);
+                   value = LLVMBuildLoad(builder, LLVMBuildGEP(builder, v_outervalues, &v_attnum, 1, ""), "");
+                   isnull = LLVMBuildLoad(builder, LLVMBuildGEP(builder, v_outernulls, &v_attnum, 1, ""), "");
+                   LLVMBuildStore(builder, value, v_resvaluep);
+                   LLVMBuildStore(builder, isnull, v_resnullp);
+
+                   LLVMBuildBr(builder, opblocks[i + 1]);
+                   break;
+               }
+
+           case EEO_SCAN_VAR:
+               {
+                   LLVMValueRef value, isnull;
+                   LLVMValueRef v_attnum;
+
+                   v_attnum = LLVMConstInt(LLVMInt32Type(), op->d.var.attnum, false);
+                   value = LLVMBuildLoad(builder, LLVMBuildGEP(builder, v_scanvalues, &v_attnum, 1, ""), "");
+                   isnull = LLVMBuildLoad(builder, LLVMBuildGEP(builder, v_scannulls, &v_attnum, 1, ""), "");
+                   LLVMBuildStore(builder, value, v_resvaluep);
+                   LLVMBuildStore(builder, isnull, v_resnullp);
+
+                   LLVMBuildBr(builder, opblocks[i + 1]);
+                   break;
+               }
+
+           case EEO_ASSIGN_INNER_VAR:
+               {
+                   LLVMValueRef v_value, v_isnull;
+                   LLVMValueRef v_rvaluep, v_risnullp;
+                   LLVMValueRef v_attnum, v_resultnum;
+
+                   v_attnum = LLVMConstInt(LLVMInt32Type(), op->d.assign_var.attnum, false);
+                   v_resultnum = LLVMConstInt(LLVMInt32Type(), op->d.assign_var.resultnum, false);
+                   v_rvaluep = LLVMBuildGEP(builder, v_resultvalues, &v_resultnum, 1, "");
+                   v_risnullp = LLVMBuildGEP(builder, v_resultnulls, &v_resultnum, 1, "");
+
+                   v_value = LLVMBuildLoad(builder, LLVMBuildGEP(builder, v_innervalues, &v_attnum, 1, ""), "");
+                   v_isnull = LLVMBuildLoad(builder, LLVMBuildGEP(builder, v_innernulls, &v_attnum, 1, ""), "");
+
+                   LLVMBuildStore(builder, v_value, v_rvaluep);
+                   LLVMBuildStore(builder, v_isnull, v_risnullp);
+
+                   LLVMBuildBr(builder, opblocks[i + 1]);
+                   break;
+
+               }
+
+           case EEO_ASSIGN_OUTER_VAR:
+               {
+                   LLVMValueRef v_value, v_isnull;
+                   LLVMValueRef v_rvaluep, v_risnullp;
+                   LLVMValueRef v_attnum, v_resultnum;
+
+                   v_attnum = LLVMConstInt(LLVMInt32Type(), op->d.assign_var.attnum, false);
+                   v_resultnum = LLVMConstInt(LLVMInt32Type(), op->d.assign_var.resultnum, false);
+                   v_rvaluep = LLVMBuildGEP(builder, v_resultvalues, &v_resultnum, 1, "");
+                   v_risnullp = LLVMBuildGEP(builder, v_resultnulls, &v_resultnum, 1, "");
+
+                   v_value = LLVMBuildLoad(builder, LLVMBuildGEP(builder, v_outervalues, &v_attnum, 1, ""), "");
+                   v_isnull = LLVMBuildLoad(builder, LLVMBuildGEP(builder, v_outernulls, &v_attnum, 1, ""), "");
+
+                   LLVMBuildStore(builder, v_value, v_rvaluep);
+                   LLVMBuildStore(builder, v_isnull, v_risnullp);
+
+                   LLVMBuildBr(builder, opblocks[i + 1]);
+                   break;
+               }
+
+           case EEO_ASSIGN_SCAN_VAR:
+               {
+                   LLVMValueRef v_value, v_isnull;
+                   LLVMValueRef v_rvaluep, v_risnullp;
+                   LLVMValueRef v_attnum, v_resultnum;
+
+                   v_attnum = LLVMConstInt(LLVMInt32Type(), op->d.assign_var.attnum, false);
+                   v_resultnum = LLVMConstInt(LLVMInt32Type(), op->d.assign_var.resultnum, false);
+                   v_rvaluep = LLVMBuildGEP(builder, v_resultvalues, &v_resultnum, 1, "");
+                   v_risnullp = LLVMBuildGEP(builder, v_resultnulls, &v_resultnum, 1, "");
+
+                   v_value = LLVMBuildLoad(builder, LLVMBuildGEP(builder, v_scanvalues, &v_attnum, 1, ""), "");
+                   v_isnull = LLVMBuildLoad(builder, LLVMBuildGEP(builder, v_scannulls, &v_attnum, 1, ""), "");
+
+                   LLVMBuildStore(builder, v_value, v_rvaluep);
+                   LLVMBuildStore(builder, v_isnull, v_risnullp);
+
+                   LLVMBuildBr(builder, opblocks[i + 1]);
+                   break;
+               }
+
+           case EEO_ASSIGN_TMP:
+           case EEO_ASSIGN_TMP_UNEXPAND: /* FIXME: not correct */
+               {
+                   LLVMValueRef v_value, v_isnull;
+                   LLVMValueRef v_rvaluep, v_risnullp;
+                   LLVMValueRef v_resultnum;
+                   size_t resultnum = op->d.assign_tmp.resultnum;
+
+                   v_resultnum = LLVMConstInt(LLVMInt32Type(), resultnum, false);
+                   v_value = LLVMBuildLoad(builder, v_tmpvaluep, "");
+                   v_isnull = LLVMBuildLoad(builder, v_tmpisnullp, "");
+                   v_rvaluep = LLVMBuildGEP(builder, v_resultvalues, &v_resultnum, 1, "");
+                   v_risnullp = LLVMBuildGEP(builder, v_resultnulls, &v_resultnum, 1, "");
+
+                   LLVMBuildStore(builder, v_value, v_rvaluep);
+                   LLVMBuildStore(builder, v_isnull, v_risnullp);
+
+                   LLVMBuildBr(builder, opblocks[i + 1]);
+                   break;
+               }
+
+           case EEO_INNER_SYSVAR:
+               {
+                   int attnum = op->d.var.attnum;
+                   LLVMValueRef v_attnum;
+                   LLVMValueRef v_tuple;
+                   LLVMValueRef v_tupleDescriptor;
+                   LLVMValueRef v_params[4];
+                   LLVMValueRef v_syscol;
+
+                   Assert(op->d.var.attnum < 0);
+
+                   if (!l_heap_getsysattr)
+                       l_heap_getsysattr = create_heap_getsysattr(mod);
+
+                   v_tuple = LLVMBuildLoad(
+                       builder,
+                       LLVMBuildStructGEP(builder, v_innerslot, 5, "v.innertuple"),
+                       "");
+                   v_tupleDescriptor = LLVMBuildLoad(
+                       builder,
+                       LLVMBuildStructGEP(builder, v_innerslot, 6, "v.innertupledesc"),
+                       "");
+
+                   v_attnum = LLVMConstInt(LLVMInt32Type(), attnum, 0);
+
+                   v_params[0] = v_tuple;
+                   v_params[1] = v_attnum;
+                   v_params[2] = v_tupleDescriptor;
+                   v_params[3] = v_resnullp;
+                   v_syscol = LLVMBuildCall(builder, l_heap_getsysattr, v_params, lengthof(v_params), "");
+                   LLVMBuildStore(builder, v_syscol, v_resvaluep);
+
+                   LLVMBuildBr(builder, opblocks[i + 1]);
+
+                   break;
+               }
+
+           case EEO_OUTER_SYSVAR:
+               {
+                   int attnum = op->d.var.attnum;
+                   LLVMValueRef v_attnum;
+                   LLVMValueRef v_tuple;
+                   LLVMValueRef v_tupleDescriptor;
+                   LLVMValueRef v_params[4];
+                   LLVMValueRef v_syscol;
+
+                   Assert(op->d.var.attnum < 0);
+
+                   if (!l_heap_getsysattr)
+                       l_heap_getsysattr = create_heap_getsysattr(mod);
+
+                   v_tuple = LLVMBuildLoad(
+                       builder,
+                       LLVMBuildStructGEP(builder, v_outerslot, 5, "v.outertuple"),
+                       "");
+                   v_tupleDescriptor = LLVMBuildLoad(
+                       builder,
+                       LLVMBuildStructGEP(builder, v_outerslot, 6, "v.outertupledesc"),
+                       "");
+
+                   v_attnum = LLVMConstInt(LLVMInt32Type(), attnum, 0);
+
+                   v_params[0] = v_tuple;
+                   v_params[1] = v_attnum;
+                   v_params[2] = v_tupleDescriptor;
+                   v_params[3] = v_resnullp;
+                   v_syscol = LLVMBuildCall(builder, l_heap_getsysattr, v_params, lengthof(v_params), "");
+                   LLVMBuildStore(builder, v_syscol, v_resvaluep);
+
+                   LLVMBuildBr(builder, opblocks[i + 1]);
+               }
+
+           case EEO_SCAN_SYSVAR:
+               {
+                   int attnum = op->d.var.attnum;
+                   LLVMValueRef v_attnum;
+                   LLVMValueRef v_tuple;
+                   LLVMValueRef v_tupleDescriptor;
+                   LLVMValueRef v_params[4];
+                   LLVMValueRef v_syscol;
+
+                   Assert(op->d.var.attnum < 0);
+
+                   if (!l_heap_getsysattr)
+                       l_heap_getsysattr = create_heap_getsysattr(mod);
+
+                   v_tuple = LLVMBuildLoad(
+                       builder,
+                       LLVMBuildStructGEP(builder, v_scanslot, 5, "v.scantuple"),
+                       "");
+                   v_tupleDescriptor = LLVMBuildLoad(
+                       builder,
+                       LLVMBuildStructGEP(builder, v_scanslot, 6, "v.scantupledesc"),
+                       "");
+
+                   v_attnum = LLVMConstInt(LLVMInt32Type(), attnum, 0);
+
+                   v_params[0] = v_tuple;
+                   v_params[1] = v_attnum;
+                   v_params[2] = v_tupleDescriptor;
+                   v_params[3] = v_resnullp;
+                   v_syscol = LLVMBuildCall(builder, l_heap_getsysattr, v_params, lengthof(v_params), "");
+                   LLVMBuildStore(builder, v_syscol, v_resvaluep);
+
+                   LLVMBuildBr(builder, opblocks[i + 1]);
+
+                   break;
+               }
+
+           case EEO_CONST:
+               {
+                   LLVMValueRef v_constvalue, v_constnull;
+
+                   v_constvalue = LLVMConstInt(TypeSizeT, op->d.constval.value, false);
+                   v_constnull = LLVMConstInt(LLVMInt8Type(), op->d.constval.isnull, false);
+
+                   LLVMBuildStore(builder, v_constvalue, v_resvaluep);
+                   LLVMBuildStore(builder, v_constnull, v_resnullp);
+
+                   LLVMBuildBr(builder, opblocks[i + 1]);
+                   break;
+               }
+
+           case EEO_FUNCEXPR_STRICT:
+               {
+                   FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
+                   LLVMBasicBlockRef b_nonull = LLVMInsertBasicBlock(opblocks[i], "no-null-args");
+                   int argno;
+                   LLVMValueRef v_argnullp;
+                   LLVMBasicBlockRef *b_checkargnulls;
+
+                   /* should make sure they're optimized beforehand */
+                   if (op->d.func.nargs == 0)
+                       elog(ERROR, "argumentless strict functions are pointless");
+
+                   v_argnullp = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(TypeSizeT, (uintptr_t) fcinfo->argnull, false),
+                       LLVMPointerType(LLVMInt8Type(), 0),
+                       "v_argnullp");
+
+                   /* set resnull to true, if the function is actually called, it'll be reset */
+                   LLVMBuildStore(builder, LLVMConstInt(LLVMInt8Type(), 1, false), v_resnullp);
+
+                   /* create blocks for checking args */
+                   b_checkargnulls = palloc(sizeof(LLVMBasicBlockRef *) * op->d.func.nargs);
+                   for (argno = 0; argno < op->d.func.nargs;argno++)
+                   {
+                       b_checkargnulls[argno] = LLVMInsertBasicBlock(opblocks[i], "check-null-arg");
+                   }
+
+                   LLVMBuildBr(builder, b_checkargnulls[0]);
+
+                   /* strict function, check for NULL args */
+                   for (argno = 0; argno < op->d.func.nargs;argno++)
+                   {
+                       LLVMValueRef v_argno = LLVMConstInt(LLVMInt32Type(), argno, false);
+                       LLVMValueRef v_argisnull;
+                       LLVMBasicBlockRef b_argnotnull;
+
+                       LLVMPositionBuilderAtEnd(builder, b_checkargnulls[argno]);
+
+                       if (argno + 1 == op->d.func.nargs)
+                           b_argnotnull = b_nonull;
+                       else
+                           b_argnotnull = b_checkargnulls[argno + 1];
+
+                       v_argisnull = LLVMBuildLoad(builder, LLVMBuildGEP(builder, v_argnullp, &v_argno, 1, ""), "");
+
+                       LLVMBuildCondBr(
+                           builder,
+                           LLVMBuildICmp(builder, LLVMIntEQ, v_argisnull,
+                                         LLVMConstInt(LLVMInt8Type(), 1, false), ""),
+                           opblocks[i + 1],
+                           b_argnotnull);
+                   }
+
+                   LLVMPositionBuilderAtEnd(builder, b_nonull);
+               }
+               /* explicit fallthrough */
+           case EEO_FUNCEXPR:
+               {
+                   FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
+                   LLVMValueRef v_fcinfo;
+                   LLVMValueRef v_fn_addr;
+                   LLVMValueRef v_fcinfo_isnullp;
+                   LLVMValueRef v_fcinfo_isnull;
+                   LLVMValueRef v_retval;
+
+                   v_fcinfo = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(TypeSizeT, (intptr_t) fcinfo, false),
+                       LLVMPointerType(TypeSizeT, 0),
+                       "v_fcinfo");
+
+                   v_fn_addr = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(TypeSizeT, (intptr_t) op->d.func.fn_addr, false),
+                       LLVMPointerType(TypePGFunction, 0),
+                       "v_fn_addr");
+
+                   v_fcinfo_isnullp = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(TypeSizeT, (intptr_t) &fcinfo->isnull, false),
+                       LLVMPointerType(LLVMInt8Type(), 0),
+                       "v_fcinfo_isnull");
+
+                   LLVMBuildStore(builder, LLVMConstInt(LLVMInt8Type(), 0, false),
+                                  v_fcinfo_isnullp);
+                   v_retval = LLVMBuildCall(builder, v_fn_addr, &v_fcinfo, 1, "funccall");
+
+                   LLVMBuildStore(builder, v_retval, v_resvaluep);
+                   v_fcinfo_isnull = LLVMBuildLoad(builder, v_fcinfo_isnullp, "");
+                   LLVMBuildStore(builder, v_fcinfo_isnull, v_resnullp);
+
+                   LLVMBuildBr(builder, opblocks[i + 1]);
+                   break;
+               }
+
+           case EEO_AGGREF:
+               {
+                   AggrefExprState *aggref = op->d.aggref.astate;
+                   LLVMValueRef v_aggnop;
+                   LLVMValueRef v_aggno;
+                   LLVMValueRef value, isnull;
+
+                   /*
+                    * At this point aggref->aggno has necessarily been set
+                    * yet. So load it from memory each time round. Yes,
+                    * that's really ugly. XXX
+                    */
+                   v_aggnop = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(LLVMInt64Type(), (intptr_t) &aggref->aggno, false),
+                       LLVMPointerType(LLVMInt32Type(), 0),
+                       "aggnop");
+                   v_aggno = LLVMBuildLoad(builder, v_aggnop, "");
+                   value = LLVMBuildLoad(builder, LLVMBuildGEP(builder, v_aggvalues, &v_aggno, 1, ""), "aggvalue");
+                   isnull = LLVMBuildLoad(builder, LLVMBuildGEP(builder, v_aggnulls, &v_aggno, 1, ""), "aggnull");
+
+                   LLVMBuildStore(builder, value, v_resvaluep);
+                   LLVMBuildStore(builder, isnull, v_resnullp);
+
+                   LLVMBuildBr(builder, opblocks[i + 1]);
+                   break;
+               }
+           case EEO_WINDOW_FUNC:
+               {
+                   WindowFuncExprState *wfunc = op->d.window_func.wfstate;
+                   LLVMValueRef v_aggnop;// = LLVMConstInt(LLVMInt32Type(), wfunc->wfuncno, false);
+                   LLVMValueRef v_aggno;
+                   LLVMValueRef value, isnull;
+
+                   /*
+                    * At this point wfuncref->wfuncno has necessarily been set
+                    * yet. So load it from memory each time round. Yes,
+                    * that's really ugly. XXX
+                    */
+                   v_aggnop = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(LLVMInt64Type(), (intptr_t) &wfunc->wfuncno, false),
+                       LLVMPointerType(LLVMInt32Type(), 0),
+                       "aggnop");
+
+                   v_aggno = LLVMBuildLoad(builder, v_aggnop, "");
+                   value = LLVMBuildLoad(builder, LLVMBuildGEP(builder, v_aggvalues, &v_aggno, 1, ""), "windowvalue");
+                   isnull = LLVMBuildLoad(builder, LLVMBuildGEP(builder, v_aggnulls, &v_aggno, 1, ""), "windownull");
+
+                   LLVMBuildStore(builder, value, v_resvaluep);
+                   LLVMBuildStore(builder, isnull, v_resnullp);
+
+                   LLVMBuildBr(builder, opblocks[i + 1]);
+                   break;
+               }
+
+           case EEO_BOOL_AND_STEP_FIRST:
+               {
+                   LLVMValueRef v_boolanynullp;
+
+                   v_boolanynullp = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(LLVMInt64Type(), (intptr_t) op->d.boolexpr.anynull, false),
+                       LLVMPointerType(LLVMInt8Type(), 0),
+                       "boolanynull");
+                   LLVMBuildStore(builder, LLVMConstInt(LLVMInt8Type(), 0, false), v_boolanynullp);
+
+                   /* intentionally fall through */
+               }
+           case EEO_BOOL_AND_STEP:
+               {
+                   LLVMValueRef v_boolvaluep, v_boolvalue;
+                   LLVMValueRef v_boolnullp, v_boolnull;
+                   LLVMValueRef v_boolanynullp, v_boolanynull;
+                   LLVMBasicBlockRef boolisnullblock;
+                   LLVMBasicBlockRef boolcheckfalseblock;
+                   LLVMBasicBlockRef boolisfalseblock;
+                   LLVMBasicBlockRef boolcontblock;
+                   LLVMBasicBlockRef boolisanynullblock;
+                   char *blockname;
+
+                   blockname = psprintf("block.op.%d.boolisnull", i);
+                   boolisnullblock = LLVMAppendBasicBlock(eval_fn, blockname);
+                   pfree(blockname);
+
+                   blockname = psprintf("block.op.%d.boolcheckfalse", i);
+                   boolcheckfalseblock = LLVMAppendBasicBlock(eval_fn, blockname);
+                   pfree(blockname);
+
+                   blockname = psprintf("block.op.%d.boolisfalse", i);
+                   boolisfalseblock = LLVMAppendBasicBlock(eval_fn, blockname);
+                   pfree(blockname);
+
+                   blockname = psprintf("block.op.%d.boolisanynullblock", i);
+                   boolisanynullblock = LLVMAppendBasicBlock(eval_fn, blockname);
+                   pfree(blockname);
+
+                   blockname = psprintf("block.op.%d.boolcontblock", i);
+                   boolcontblock = LLVMAppendBasicBlock(eval_fn, blockname);
+                   pfree(blockname);
+
+                   v_boolvaluep = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(LLVMInt64Type(), (intptr_t) op->d.boolexpr.value, false),
+                       LLVMPointerType(TypeSizeT, 0),
+                       "boolvaluep");
+
+                   v_boolnullp = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(LLVMInt64Type(), (intptr_t) op->d.boolexpr.isnull, false),
+                       LLVMPointerType(LLVMInt8Type(), 0),
+                       "boolnullp");
+
+                   v_boolanynullp = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(LLVMInt64Type(), (intptr_t) op->d.boolexpr.anynull, false),
+                       LLVMPointerType(LLVMInt8Type(), 0),
+                       "anynull");
+
+                   v_boolnull = LLVMBuildLoad(builder, v_boolnullp, "");
+                   v_boolvalue = LLVMBuildLoad(builder, v_boolvaluep, "");
+
+                   /* set resnull to boolnull */
+                   LLVMBuildStore(builder, v_boolnull, v_resnullp);
+                   /* set revalue to boolvalue */
+                   LLVMBuildStore(builder, v_boolvalue, v_resvaluep);
+
+                   LLVMBuildCondBr(
+                       builder,
+                       LLVMBuildICmp(builder, LLVMIntEQ, v_boolnull,
+                                     LLVMConstInt(LLVMInt8Type(), 1, false), ""),
+                       boolisnullblock,
+                       boolcheckfalseblock);
+
+                   /* build block that checks that sets anynull */
+                   LLVMPositionBuilderAtEnd(builder, boolisnullblock);
+                   /* set boolanynull to true */
+                   LLVMBuildStore(builder, LLVMConstInt(LLVMInt8Type(), 1, false), v_boolanynullp);
+                   /* set resnull to true */
+                   LLVMBuildStore(builder, LLVMConstInt(LLVMInt8Type(), 1, false), v_resnullp);
+                   /* reset resvalue (cleanliness) */
+                   LLVMBuildStore(builder, LLVMConstInt(TypeSizeT, 0, false), v_resvaluep);
+                   /* and jump to next block */
+                   LLVMBuildBr(builder, boolcontblock);
+
+                   /* build block checking for false, which can jumps out at false */
+                   LLVMPositionBuilderAtEnd(builder, boolcheckfalseblock);
+                   LLVMBuildCondBr(
+                       builder,
+                       LLVMBuildICmp(builder, LLVMIntEQ, v_boolvalue,
+                                     LLVMConstInt(LLVMInt64Type(), 0, false), ""),
+                       boolisfalseblock,
+                       boolcontblock);
+
+                   /* Build block handling FALSE. Value is false, so short circuit. */
+                   LLVMPositionBuilderAtEnd(builder, boolisfalseblock);
+                   /* set resnull to false */
+                   LLVMBuildStore(builder, LLVMConstInt(LLVMInt8Type(), 0, false), v_resnullp);
+                   /* reset resvalue to false */
+                   LLVMBuildStore(builder, LLVMConstInt(TypeSizeT, 0, false), v_resvaluep);
+                   /* and jump to the end of the AND expression */
+                   LLVMBuildBr(builder, opblocks[op->d.boolexpr.jumpdone]);
+
+                   /* build block that continues if bool is TRUE */
+                   LLVMPositionBuilderAtEnd(builder, boolcontblock);
+
+                   v_boolanynull = LLVMBuildLoad(builder, v_boolanynullp, "");
+
+                   /* set value to NULL if any previous values were NULL */
+                   LLVMBuildCondBr(
+                       builder,
+                       LLVMBuildICmp(builder, LLVMIntEQ, v_boolanynull,
+                                     LLVMConstInt(LLVMInt8Type(), 0, false), ""),
+                       opblocks[i + 1], boolisanynullblock);
+
+                   LLVMPositionBuilderAtEnd(builder, boolisanynullblock);
+                   /* set resnull to true */
+                   LLVMBuildStore(builder, LLVMConstInt(LLVMInt8Type(), 1, true), v_resnullp);
+                   /* reset resvalue */
+                   LLVMBuildStore(builder, LLVMConstInt(TypeSizeT, 0, false), v_resvaluep);
+
+                   LLVMBuildBr(builder, opblocks[i + 1]);
+                   break;
+               }
+           case EEO_BOOL_OR_STEP_FIRST:
+               {
+                   LLVMValueRef v_boolanynullp;
+
+                   v_boolanynullp = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(LLVMInt64Type(), (intptr_t) op->d.boolexpr.anynull, false),
+                       LLVMPointerType(LLVMInt8Type(), 0),
+                       "boolanynull");
+                   LLVMBuildStore(builder, LLVMConstInt(LLVMInt8Type(), 0, false), v_boolanynullp);
+
+                   /* intentionally fall through */
+               }
+           case EEO_BOOL_OR_STEP:
+               {
+                   LLVMValueRef v_boolvaluep, v_boolvalue;
+                   LLVMValueRef v_boolnullp, v_boolnull;
+                   LLVMValueRef v_boolanynullp, v_boolanynull;
+                   LLVMBasicBlockRef boolisnullblock;
+                   LLVMBasicBlockRef boolchecktrueblock;
+                   LLVMBasicBlockRef boolistrueblock;
+                   LLVMBasicBlockRef boolcontblock;
+                   LLVMBasicBlockRef boolisanynullblock;
+                   char *blockname;
+
+                   blockname = psprintf("block.op.%d.boolisnull", i);
+                   boolisnullblock = LLVMAppendBasicBlock(eval_fn, blockname);
+                   pfree(blockname);
+
+                   blockname = psprintf("block.op.%d.boolchecktrue", i);
+                   boolchecktrueblock = LLVMAppendBasicBlock(eval_fn, blockname);
+                   pfree(blockname);
+
+                   blockname = psprintf("block.op.%d.boolistrue", i);
+                   boolistrueblock = LLVMAppendBasicBlock(eval_fn, blockname);
+                   pfree(blockname);
+
+                   blockname = psprintf("block.op.%d.boolisanynullblock", i);
+                   boolisanynullblock = LLVMAppendBasicBlock(eval_fn, blockname);
+                   pfree(blockname);
+
+                   blockname = psprintf("block.op.%d.boolcontblock", i);
+                   boolcontblock = LLVMAppendBasicBlock(eval_fn, blockname);
+                   pfree(blockname);
+
+                   v_boolvaluep = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(LLVMInt64Type(), (intptr_t) op->d.boolexpr.value, false),
+                       LLVMPointerType(TypeSizeT, 0),
+                       "boolvaluep");
+
+                   v_boolnullp = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(LLVMInt64Type(), (intptr_t) op->d.boolexpr.isnull, false),
+                       LLVMPointerType(LLVMInt8Type(), 0),
+                       "boolnullp");
+
+                   v_boolanynullp = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(LLVMInt64Type(), (intptr_t) op->d.boolexpr.anynull, false),
+                       LLVMPointerType(LLVMInt8Type(), 0),
+                       "anynull");
+
+                   v_boolnull = LLVMBuildLoad(builder, v_boolnullp, "");
+                   v_boolvalue = LLVMBuildLoad(builder, v_boolvaluep, "");
+
+                   /* set resnull to boolnull */
+                   LLVMBuildStore(builder, v_boolnull, v_resnullp);
+                   /* set revalue to boolvalue */
+                   LLVMBuildStore(builder, v_boolvalue, v_resvaluep);
+
+                   LLVMBuildCondBr(
+                       builder,
+                       LLVMBuildICmp(builder, LLVMIntEQ, v_boolnull,
+                                     LLVMConstInt(LLVMInt8Type(), 1, false), ""),
+                       boolisnullblock,
+                       boolchecktrueblock);
+
+                   /* build block that checks that sets anynull */
+                   LLVMPositionBuilderAtEnd(builder, boolisnullblock);
+                   /* set boolanynull to true */
+                   LLVMBuildStore(builder, LLVMConstInt(LLVMInt8Type(), 1, false), v_boolanynullp);
+                   /* set resnull to true */
+                   LLVMBuildStore(builder, LLVMConstInt(LLVMInt8Type(), 1, false), v_resnullp);
+                   /* reset resvalue (cleanliness) */
+                   LLVMBuildStore(builder, LLVMConstInt(TypeSizeT, 0, false), v_resvaluep);
+                   /* and jump to next block */
+                   LLVMBuildBr(builder, boolcontblock);
+
+                   /* build block checking for false, which can jumps out at false */
+                   LLVMPositionBuilderAtEnd(builder, boolchecktrueblock);
+                   LLVMBuildCondBr(
+                       builder,
+                       LLVMBuildICmp(builder, LLVMIntEQ, v_boolvalue,
+                                     LLVMConstInt(LLVMInt64Type(), 1, false), ""),
+                       boolistrueblock,
+                       boolcontblock);
+
+                   /* Build block handling TRUE. Value is true, so short circuit. */
+                   LLVMPositionBuilderAtEnd(builder, boolistrueblock);
+                   /* set resnull to false */
+                   LLVMBuildStore(builder, LLVMConstInt(LLVMInt8Type(), 0, false), v_resnullp);
+                   /* reset resvalue to true */
+                   LLVMBuildStore(builder, LLVMConstInt(TypeSizeT, 1, false), v_resvaluep);
+                   /* and jump to the end of the OR expression */
+                   LLVMBuildBr(builder, opblocks[op->d.boolexpr.jumpdone]);
+
+                   /* build block that continues if bool is FALSE */
+                   LLVMPositionBuilderAtEnd(builder, boolcontblock);
+
+                   v_boolanynull = LLVMBuildLoad(builder, v_boolanynullp, "");
+
+                   /* set value to NULL if any previous values were NULL */
+                   LLVMBuildCondBr(
+                       builder,
+                       LLVMBuildICmp(builder, LLVMIntEQ, v_boolanynull,
+                                     LLVMConstInt(LLVMInt8Type(), 0, false), ""),
+                       opblocks[i + 1], boolisanynullblock);
+
+                   LLVMPositionBuilderAtEnd(builder, boolisanynullblock);
+                   /* set resnull to true */
+                   LLVMBuildStore(builder, LLVMConstInt(LLVMInt8Type(), 1, true), v_resnullp);
+                   /* reset resvalue */
+                   LLVMBuildStore(builder, LLVMConstInt(TypeSizeT, 0, false), v_resvaluep);
+
+                   LLVMBuildBr(builder, opblocks[i + 1]);
+                   break;
+               }
+
+           case EEO_BOOL_NOT_STEP:
+               {
+                   LLVMValueRef v_boolvaluep, v_boolvalue;
+                   LLVMValueRef v_boolnullp, v_boolnull;
+                   LLVMValueRef v_negbool;
+
+                   v_boolvaluep = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(LLVMInt64Type(), (intptr_t) op->d.boolexpr.value, false),
+                       LLVMPointerType(TypeSizeT, 0),
+                       "boolvaluep");
+
+                   v_boolnullp = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(LLVMInt64Type(), (intptr_t) op->d.boolexpr.isnull, false),
+                       LLVMPointerType(LLVMInt8Type(), 0),
+                       "boolnullp");
+
+                   v_boolnull = LLVMBuildLoad(builder, v_boolnullp, "");
+                   v_boolvalue = LLVMBuildLoad(builder, v_boolvaluep, "");
+
+                   v_negbool = LLVMBuildZExt(
+                       builder,
+                       LLVMBuildICmp(builder, LLVMIntEQ, v_boolvalue,
+                                     LLVMConstInt(TypeSizeT, 0, false), ""),
+                       TypeSizeT, "");
+                   /* set resnull to boolnull */
+                   LLVMBuildStore(builder, v_boolnull, v_resnullp);
+                       /* set revalue to !boolvalue */
+                   LLVMBuildStore(builder, v_negbool, v_resvaluep);
+
+                   LLVMBuildBr(builder, opblocks[i + 1]);
+                   break;
+               }
+
+           case EEO_QUAL:
+               {
+                   LLVMValueRef v_resnull;
+                   LLVMValueRef v_resvalue;
+                   LLVMValueRef v_nullorfalse;
+                   LLVMBasicBlockRef qualfailblock;
+                   char *blockname;
+
+                   blockname = psprintf("block.op.%d.qualfail", i);
+                   qualfailblock = LLVMAppendBasicBlock(eval_fn, blockname);
+                   pfree(blockname);
+
+                   v_resvalue = LLVMBuildLoad(builder, v_resvaluep, "");
+                   v_resnull = LLVMBuildLoad(builder, v_resnullp, "");
+
+                   v_nullorfalse = LLVMBuildOr(
+                       builder,
+                       LLVMBuildICmp(
+                           builder, LLVMIntEQ, v_resnull,
+                           LLVMConstInt(LLVMInt8Type(), 1, false), ""),
+                       LLVMBuildICmp(
+                           builder, LLVMIntEQ, v_resvalue,
+                           LLVMConstInt(TypeSizeT, 0, false), ""),
+                       "");
+
+                   LLVMBuildCondBr(
+                       builder,
+                       v_nullorfalse,
+                       qualfailblock,
+                       opblocks[i + 1]);
+
+                   /* build block handling NULL or false */
+                   LLVMPositionBuilderAtEnd(builder, qualfailblock);
+                   /* set resnull to false */
+                   LLVMBuildStore(builder, LLVMConstInt(LLVMInt8Type(), 0, false), v_resnullp);
+                   /* set resvalue to false */
+                   LLVMBuildStore(builder, LLVMConstInt(TypeSizeT, 0, false), v_resvaluep);
+                   /* and jump out */
+                   LLVMBuildBr(builder, opblocks[op->d.qualexpr.jumpdone]);
+
+                   break;
+               }
+
+           case EEO_CASE_WHEN_STEP:
+               {
+                   LLVMBasicBlockRef b_isnotnullblock;
+                   LLVMValueRef v_whenisnullp, v_whenvaluep;
+                   LLVMValueRef v_whenisnull, v_whenvalue;
+                   char *blockname;
+
+                   blockname = psprintf("block.op.%d.when_step_notnull", i);
+                   b_isnotnullblock = LLVMInsertBasicBlock(opblocks[i + 1], blockname);
+                   pfree(blockname);
+
+                   v_whenisnullp = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(TypeSizeT, (uintptr_t) op->d.casewhen.isnull, false),
+                       LLVMPointerType(LLVMInt8Type(), 0),
+                       "");
+
+                   v_whenisnull = LLVMBuildLoad(builder, v_whenisnullp, "");
+
+                   /* if value is NULL, jump to false branch */
+                   LLVMBuildCondBr(
+                       builder,
+                       LLVMBuildICmp(builder, LLVMIntEQ, v_whenisnull,
+                                     LLVMConstInt(LLVMInt8Type(), 1, false), ""),
+                       opblocks[op->d.casewhen.jumpfalse],
+                       b_isnotnullblock);
+
+                   LLVMPositionBuilderAtEnd(builder, b_isnotnullblock);
+
+                   v_whenvaluep = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(TypeSizeT, (uintptr_t) op->d.casewhen.value, false),
+                       LLVMPointerType(TypeSizeT, 0),
+                       "");
+                   v_whenvalue = LLVMBuildLoad(builder, v_whenvaluep, "");
+
+                   /* if value is true, jump to true branch, otherwise false */
+                   LLVMBuildCondBr(
+                       builder,
+                       LLVMBuildICmp(builder, LLVMIntEQ, v_whenvalue,
+                                     LLVMConstInt(TypeSizeT, 1, false), ""),
+                       opblocks[i + 1],
+                       opblocks[op->d.casewhen.jumpfalse]);
+
+                   break;
+               }
+
+           case EEO_PARAM_EXEC:
+           case EEO_PARAM_EXTERN:
+           case EEO_SQLVALUEFUNCTION:
+           case EEO_CURRENTOFEXPR:
+           case EEO_ARRAYEXPR:
+           case EEO_ARRAYCOERCE:
+           case EEO_ROW:
+           case EEO_MINMAX:
+           case EEO_FIELDSELECT:
+           case EEO_FIELDSTORE_DEFORM:
+           case EEO_FIELDSTORE_FORM:
+           case EEO_ARRAYREF_ASSIGN:
+           case EEO_ARRAYREF_FETCH:
+           case EEO_ARRAYREF_OLD:
+           case EEO_CONVERT_ROWTYPE:
+           case EEO_SCALARARRAYOP:
+           case EEO_DOMAIN_NOTNULL:
+           case EEO_DOMAIN_CHECK:
+           case EEO_XMLEXPR:
+           case EEO_GROUPING_FUNC:
+           case EEO_SUBPLAN:
+           case EEO_ALTERNATIVE_SUBPLAN:
+           case EEO_NULLTEST_ROWISNULL:
+           case EEO_NULLTEST_ROWISNOTNULL:
+           case EEO_WHOLEROW:
+               {
+                   LLVMValueRef v_params[3];
+                   const char *funcname;
+                   LLVMValueRef *funcptr;
+
+                   if (op->opcode == EEO_PARAM_EXEC)
+                   {
+                       funcname = "ExecEvalParamExec";
+                       funcptr = &l_EvalParamExec;
+                   }
+                   else if (op->opcode == EEO_PARAM_EXTERN)
+                   {
+                       funcname = "ExecEvalParamExtern";
+                       funcptr = &l_EvalParamExtern;
+                   }
+                   else if (op->opcode == EEO_SQLVALUEFUNCTION)
+                   {
+                       funcname = "ExecEvalSQLValueFunction";
+                       funcptr = &l_EvalSQLValueFunction;
+                   }
+                   else if (op->opcode == EEO_CURRENTOFEXPR)
+                   {
+                       funcname = "ExecEvalCurrentOfExpr";
+                       funcptr = &l_EvalCurrentOfExpr;
+                   }
+                   else if (op->opcode == EEO_ARRAYEXPR)
+                   {
+                       funcname = "ExecEvalArrayExpr";
+                       funcptr = &l_EvalArrayExpr;
+                   }
+                   else if (op->opcode == EEO_ARRAYCOERCE)
+                   {
+                       funcname = "ExecEvalArrayCoerce";
+                       funcptr = &l_EvalArrayCoerce;
+                   }
+                   else if (op->opcode == EEO_ROW)
+                   {
+                       funcname = "ExecEvalRow";
+                       funcptr = &l_EvalRow;
+                   }
+                   else if (op->opcode == EEO_MINMAX)
+                   {
+                       funcname = "ExecEvalMinMax";
+                       funcptr = &l_EvalMinMax;
+                   }
+                   else if (op->opcode == EEO_FIELDSELECT)
+                   {
+                       funcname = "ExecEvalFieldSelect";
+                       funcptr = &l_EvalFieldSelect;
+                   }
+                   else if (op->opcode == EEO_FIELDSTORE_DEFORM)
+                   {
+                       funcname = "ExecEvalFieldStoreDeForm";
+                       funcptr = &l_EvalFieldStoreDeForm;
+                   }
+                   else if (op->opcode == EEO_FIELDSTORE_FORM)
+                   {
+                       funcname = "ExecEvalFieldStoreForm";
+                       funcptr = &l_EvalFieldStoreForm;
+                   }
+                   else if (op->opcode == EEO_ARRAYREF_FETCH)
+                   {
+                       funcname = "ExecEvalArrayRefFetch";
+                       funcptr = &l_EvalArrayRefFetch;
+                   }
+                   else if (op->opcode == EEO_ARRAYREF_ASSIGN)
+                   {
+                       funcname = "ExecEvalArrayRefAssign";
+                       funcptr = &l_EvalArrayRefAssign;
+                   }
+                   else if (op->opcode == EEO_ARRAYREF_OLD)
+                   {
+                       funcname = "ExecEvalArrayRefOld";
+                       funcptr = &l_EvalArrayRefOld;
+                   }
+                   else if (op->opcode == EEO_NULLTEST_ROWISNULL)
+                   {
+                       funcname = "ExecEvalRowNull";
+                       funcptr = &l_EvalRowNull;
+                   }
+                   else if (op->opcode == EEO_NULLTEST_ROWISNOTNULL)
+                   {
+                       funcname = "ExecEvalRowNotNull";
+                       funcptr = &l_EvalRowNotNull;
+                   }
+                   else if (op->opcode == EEO_CONVERT_ROWTYPE)
+                   {
+                       funcname = "ExecEvalConvertRowtype";
+                       funcptr = &l_EvalConvertRowtype;
+                   }
+                   else if (op->opcode == EEO_SCALARARRAYOP)
+                   {
+                       funcname = "ExecEvalScalarArrayOp";
+                       funcptr = &l_EvalScalarArrayOp;
+                   }
+                   else if (op->opcode == EEO_DOMAIN_NOTNULL)
+                   {
+                       funcname = "ExecEvalConstraintNotNull";
+                       funcptr = &l_EvalConstraintNotNull;
+                   }
+                   else if (op->opcode == EEO_DOMAIN_CHECK)
+                   {
+                       funcname = "ExecEvalConstraintCheck";
+                       funcptr = &l_EvalConstraintCheck;
+                   }
+                   else if (op->opcode == EEO_XMLEXPR)
+                   {
+                       funcname = "ExecEvalXmlExpr";
+                       funcptr = &l_EvalXmlExpr;
+                   }
+                   else if (op->opcode == EEO_GROUPING_FUNC)
+                   {
+                       funcname = "ExecEvalGroupingFunc";
+                       funcptr = &l_EvalGroupingFunc;
+                   }
+                   else if (op->opcode == EEO_SUBPLAN)
+                   {
+                       funcname = "ExecEvalSubPlan";
+                       funcptr = &l_EvalSubPlan;
+                   }
+                   else if (op->opcode == EEO_ALTERNATIVE_SUBPLAN)
+                   {
+                       funcname = "ExecEvalAlternativeSubPlan";
+                       funcptr = &l_EvalAlternativeSubPlan;
+                   }
+                   else if (op->opcode == EEO_WHOLEROW)
+                   {
+                       funcname = "ExecEvalWholeRowVar";
+                       funcptr = &l_EvalWholeRowVar;
+                   }
+                   else
+                   {
+                       Assert(false);
+                       funcptr = NULL; /* prevent compiler warning */
+                       funcname = NULL; /* prevent compiler warning */
+                   }
+
+                   if (!*funcptr)
+                       *funcptr = create_EvalXFunc(mod, funcname);
+
+                   v_params[0] = v_state;
+                   v_params[1] = LLVMBuildIntToPtr(builder,
+                                                   LLVMConstInt(TypeSizeT, (uintptr_t) op, false),
+                                                   LLVMPointerType(TypeSizeT, 0),
+                                                   "");
+                   v_params[2] = v_econtext;
+                   LLVMBuildCall(builder, *funcptr, v_params, lengthof(v_params), "");
+                   LLVMBuildBr(builder, opblocks[i + 1]);
+                   break;
+               }
+
+           case EEO_ARRAYREF_CHECKSUBSCRIPT:
+               {
+                   LLVMValueRef v_params[3];
+                   LLVMValueRef v_ret;
+
+                   if (!l_EvalArrayRefCheckSubscript)
+                       l_EvalArrayRefCheckSubscript = create_EvalArrayRefCheckSubscript(mod);
+
+                   v_params[0] = v_state;
+                   v_params[1] = LLVMBuildIntToPtr(builder,
+                                                   LLVMConstInt(TypeSizeT, (uintptr_t) op, false),
+                                                   LLVMPointerType(TypeSizeT, 0),
+                                                   "");
+                   v_params[2] = v_econtext;
+                   v_ret = LLVMBuildCall(builder, l_EvalArrayRefCheckSubscript, v_params, lengthof(v_params), "");
+
+                   LLVMBuildCondBr(builder,
+                                   LLVMBuildICmp(builder, LLVMIntEQ, v_ret,
+                                                 LLVMConstInt(LLVMInt8Type(), 1, false), ""),
+                                   opblocks[i + 1],
+                                   opblocks[op->d.arrayref_checksubscript.jumpdone]);
+                   break;
+               }
+
+           case EEO_CASE_THEN_STEP:
+               {
+                   LLVMBuildBr(builder, opblocks[op->d.casethen.jumpdone]);
+                   break;
+               }
+
+           case EEO_CASE_TESTVAL_UNEXPAND:
+           case EEO_CASE_TESTVAL:
+               {
+                   LLVMBasicBlockRef b_avail, b_notavail;
+                   LLVMValueRef v_casevaluep, v_casevalue;
+                   LLVMValueRef v_casenullp, v_casenull;
+
+                   b_avail = LLVMInsertBasicBlock(opblocks[i + 1], "");
+                   b_notavail = LLVMInsertBasicBlock(opblocks[i + 1], "");
+
+                   v_casevaluep = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(TypeSizeT, (uintptr_t) op->d.casetest.value, false),
+                       LLVMPointerType(TypeSizeT, 0),
+                       "");
+                   v_casenullp = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(TypeSizeT, (uintptr_t) op->d.casetest.isnull, false),
+                       LLVMPointerType(LLVMInt8Type(), 0),
+                       "");
+
+                   LLVMBuildCondBr(
+                       builder,
+                       LLVMBuildICmp(builder, LLVMIntEQ,
+                                     LLVMBuildPtrToInt(builder, v_casevaluep, TypeSizeT, ""),
+                                     LLVMConstInt(TypeSizeT, 0, false), ""),
+                       b_notavail, b_avail);
+
+                   /* if casetest != NULL */
+                   LLVMPositionBuilderAtEnd(builder, b_avail);
+                   v_casevalue = LLVMBuildLoad(builder, v_casevaluep, "");
+                   v_casenull = LLVMBuildLoad(builder, v_casenullp, "");
+                   LLVMBuildStore(builder, v_casevalue, v_resvaluep);
+                   LLVMBuildStore(builder, v_casenull, v_resnullp);
+                   LLVMBuildBr(builder, opblocks[i + 1]);
+
+                   /* if casetest == NULL */
+                   LLVMPositionBuilderAtEnd(builder, b_notavail);
+                   v_casevalue = LLVMBuildLoad(
+                       builder,
+                       LLVMBuildStructGEP(builder, v_econtext, 10, ""), "");
+                   v_casenull = LLVMBuildLoad(
+                       builder,
+                       LLVMBuildStructGEP(builder, v_econtext, 11, ""), "");
+                   LLVMBuildStore(builder, v_casevalue, v_resvaluep);
+                   LLVMBuildStore(builder, v_casenull, v_resnullp);
+                   LLVMBuildBr(builder, opblocks[i + 1]);
+
+                   break;
+               }
+
+           case EEO_DOMAIN_TESTVAL_UNEXPAND: /* FIXME: not correct */
+           case EEO_DOMAIN_TESTVAL:
+               {
+                   LLVMBasicBlockRef b_avail, b_notavail;
+                   LLVMValueRef v_casevaluep, v_casevalue;
+                   LLVMValueRef v_casenullp, v_casenull;
+
+                   b_avail = LLVMInsertBasicBlock(opblocks[i + 1], "");
+                   b_notavail = LLVMInsertBasicBlock(opblocks[i + 1], "");
+
+                   v_casevaluep = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(TypeSizeT, (uintptr_t) op->d.casetest.value, false),
+                       LLVMPointerType(TypeSizeT, 0),
+                       "");
+                   v_casenullp = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(TypeSizeT, (uintptr_t) op->d.casetest.isnull, false),
+                       LLVMPointerType(LLVMInt8Type(), 0),
+                       "");
+
+                   LLVMBuildCondBr(
+                       builder,
+                       LLVMBuildICmp(builder, LLVMIntEQ,
+                                     LLVMBuildPtrToInt(builder, v_casevaluep, TypeSizeT, ""),
+                                     LLVMConstInt(TypeSizeT, 0, false), ""),
+                       b_notavail, b_avail);
+
+                   /* if casetest != NULL */
+                   LLVMPositionBuilderAtEnd(builder, b_avail);
+                   v_casevalue = LLVMBuildLoad(builder, v_casevaluep, "");
+                   v_casenull = LLVMBuildLoad(builder, v_casenullp, "");
+                   LLVMBuildStore(builder, v_casevalue, v_resvaluep);
+                   LLVMBuildStore(builder, v_casenull, v_resnullp);
+                   LLVMBuildBr(builder, opblocks[i + 1]);
+
+                   /* if casetest == NULL */
+                   LLVMPositionBuilderAtEnd(builder, b_notavail);
+                   v_casevalue = LLVMBuildLoad(
+                       builder,
+                       LLVMBuildStructGEP(builder, v_econtext, 12, ""), "");
+                   v_casenull = LLVMBuildLoad(
+                       builder,
+                       LLVMBuildStructGEP(builder, v_econtext, 13, ""), "");
+                   LLVMBuildStore(builder, v_casevalue, v_resvaluep);
+                   LLVMBuildStore(builder, v_casenull, v_resnullp);
+                   LLVMBuildBr(builder, opblocks[i + 1]);
+
+                   break;
+               }
+
+           case EEO_BOOLTEST_IS_UNKNOWN:
+           case EEO_NULLTEST_ISNULL:
+               {
+                   LLVMValueRef v_resnull = LLVMBuildLoad(builder, v_resnullp, "");
+                   LLVMValueRef v_resvalue;
+
+                   v_resvalue = LLVMBuildSelect(
+                       builder,
+                       LLVMBuildICmp(builder, LLVMIntEQ, v_resnull,
+                                     LLVMConstInt(LLVMInt8Type(), 1, false), ""),
+                       LLVMConstInt(TypeSizeT, 1, false),
+                       LLVMConstInt(TypeSizeT, 0, false),
+                       "");
+                   LLVMBuildStore(
+                       builder,
+                       v_resvalue,
+                       v_resvaluep);
+                   LLVMBuildStore(
+                       builder,
+                       LLVMConstInt(LLVMInt8Type(), 0, false),
+                       v_resnullp);
+                   LLVMBuildBr(builder, opblocks[i + 1]);
+
+                   break;
+               }
+
+           case EEO_BOOLTEST_IS_NOT_UNKNOWN:
+           case EEO_NULLTEST_ISNOTNULL:
+               {
+                   LLVMValueRef v_resnull = LLVMBuildLoad(builder, v_resnullp, "");
+                   LLVMValueRef v_resvalue;
+
+                   v_resvalue = LLVMBuildSelect(
+                       builder,
+                       LLVMBuildICmp(builder, LLVMIntEQ, v_resnull,
+                                     LLVMConstInt(LLVMInt8Type(), 1, false), ""),
+                       LLVMConstInt(TypeSizeT, 0, false),
+                       LLVMConstInt(TypeSizeT, 1, false),
+                       "");
+                   LLVMBuildStore(
+                       builder,
+                       v_resvalue,
+                       v_resvaluep);
+                   LLVMBuildStore(
+                       builder,
+                       LLVMConstInt(LLVMInt8Type(), 0, false),
+                       v_resnullp);
+                   LLVMBuildBr(builder, opblocks[i + 1]);
+
+                   break;
+               }
+
+           case EEO_BOOLTEST_IS_TRUE:
+           case EEO_BOOLTEST_IS_NOT_FALSE:
+           case EEO_BOOLTEST_IS_FALSE:
+           case EEO_BOOLTEST_IS_NOT_TRUE:
+               {
+                   LLVMBasicBlockRef b_isnull, b_notnull;
+                   LLVMValueRef v_resnull = LLVMBuildLoad(builder, v_resnullp, "");
+
+                   b_isnull = LLVMInsertBasicBlock(opblocks[i + 1], "");
+                   b_notnull = LLVMInsertBasicBlock(opblocks[i + 1], "");
+
+                   /* result's always not null */
+                   LLVMBuildStore(
+                       builder,
+                       LLVMConstInt(LLVMInt8Type(), 0, false),
+                       v_resnullp);
+
+                   /* check if value is NULL */
+                   LLVMBuildCondBr(
+                       builder,
+                       LLVMBuildICmp(builder, LLVMIntEQ, v_resnull,
+                                     LLVMConstInt(LLVMInt8Type(), 1, false), ""),
+                       b_isnull, b_notnull);
+
+                   /* if value is NULL, return false */
+                   LLVMPositionBuilderAtEnd(builder, b_isnull);
+                   LLVMBuildStore(
+                       builder,
+                       LLVMConstInt(TypeSizeT, 0, false),
+                       v_resvaluep);
+                   LLVMBuildBr(builder, opblocks[i + 1]);
+
+                   LLVMPositionBuilderAtEnd(builder, b_notnull);
+
+                   if (op->opcode == EEO_BOOLTEST_IS_TRUE ||
+                       op->opcode == EEO_BOOLTEST_IS_NOT_FALSE)
+                   {
+                       /* if value is not null NULL, return value (already set) */
+                   }
+                   else
+                   {
+                       LLVMValueRef v_value = LLVMBuildLoad(
+                           builder, v_resvaluep, "");
+
+                       v_value = LLVMBuildZExt(
+                           builder,
+                           LLVMBuildICmp(builder, LLVMIntEQ, v_value,
+                                         LLVMConstInt(TypeSizeT, 0, false), ""),
+                           TypeSizeT, "");
+                       LLVMBuildStore(
+                           builder,
+                           v_value,
+                           v_resvaluep);
+                   }
+                   LLVMBuildBr(builder, opblocks[i + 1]);
+                   break;
+               }
+
+           case EEO_COALESCE:
+               {
+                   LLVMValueRef v_resnull = LLVMBuildLoad(builder, v_resnullp, "");
+
+                   LLVMBuildCondBr(
+                       builder,
+                       LLVMBuildICmp(builder, LLVMIntEQ, v_resnull,
+                                     LLVMConstInt(LLVMInt8Type(), 1, false), ""),
+                       opblocks[i + 1],
+                       opblocks[op->d.coalesce.jumpdone]);
+
+                   break;
+               }
+
+           case EEO_NULLIF:
+               {
+                   FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
+                   LLVMValueRef v_fcinfo;
+                   LLVMValueRef v_fn_addr;
+                   LLVMValueRef v_fcinfo_isnullp;
+                   LLVMValueRef v_fcinfo_isnull;
+
+                   LLVMValueRef v_argnullp;
+                   LLVMValueRef v_argnull0;
+                   LLVMValueRef v_argnull1;
+                   LLVMValueRef v_anyargisnull;
+                   LLVMValueRef v_argp;
+                   LLVMValueRef v_arg0;
+                   LLVMValueRef v_argno;
+                   LLVMBasicBlockRef b_hasnull =
+                       LLVMInsertBasicBlock(opblocks[i + 1], "null-args");
+                   LLVMBasicBlockRef b_nonull =
+                       LLVMInsertBasicBlock(opblocks[i + 1], "no-null-args");
+                   LLVMBasicBlockRef b_argsequal =
+                       LLVMInsertBasicBlock(opblocks[i + 1], "argsequal");
+                   LLVMValueRef v_retval;
+                   LLVMValueRef v_argsequal;
+
+
+                   v_fcinfo = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(TypeSizeT, (intptr_t) fcinfo, false),
+                       LLVMPointerType(TypeSizeT, 0),
+                       "v_fcinfo");
+
+                   v_fn_addr = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(TypeSizeT, (intptr_t) op->d.func.fn_addr, false),
+                       LLVMPointerType(TypePGFunction, 0),
+                       "v_fn_addr");
+
+                   v_fcinfo_isnullp = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(TypeSizeT, (intptr_t) &fcinfo->isnull, false),
+                       LLVMPointerType(LLVMInt8Type(), 0),
+                       "v_fcinfo_isnull");
+
+                   v_argnullp = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(TypeSizeT, (uintptr_t) fcinfo->argnull, false),
+                       LLVMPointerType(LLVMInt8Type(), 0),
+                       "v_argnullp");
+
+                   v_argp = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(TypeSizeT, (uintptr_t) fcinfo->arg, false),
+                       LLVMPointerType(TypeSizeT, 0),
+                       "v_arg");
+
+                   /* if either argument is NULL they can't be equal */
+                   v_argno = LLVMConstInt(LLVMInt32Type(), 0, false);
+                   v_argnull0 = LLVMBuildLoad(
+                       builder,
+                       LLVMBuildGEP(builder, v_argnullp, &v_argno, 1, "")
+                       , "");
+                   v_argno = LLVMConstInt(LLVMInt32Type(), 1, false);
+                   v_argnull1 = LLVMBuildLoad(
+                       builder,
+                       LLVMBuildGEP(builder, v_argnullp, &v_argno, 1, "")
+                       , "");
+
+                   v_anyargisnull = LLVMBuildOr(
+                       builder,
+                       LLVMBuildICmp(
+                           builder, LLVMIntEQ, v_argnull0,
+                           LLVMConstInt(LLVMInt8Type(), 1, false), ""),
+                       LLVMBuildICmp(
+                           builder, LLVMIntEQ, v_argnull1,
+                           LLVMConstInt(LLVMInt8Type(), 1, false), ""),
+                       "");
+
+                   LLVMBuildCondBr(
+                       builder,
+                       v_anyargisnull,
+                       b_hasnull,
+                       b_nonull);
+
+                   /* one (or both) of the arguments are null, return arg[0] */
+                   LLVMPositionBuilderAtEnd(builder, b_hasnull);
+                   v_argno = LLVMConstInt(LLVMInt32Type(), 0, false);
+                   v_arg0 = LLVMBuildLoad(
+                       builder,
+                       LLVMBuildGEP(builder, v_argp, &v_argno, 1, "")
+                       , "");
+                   LLVMBuildStore(
+                       builder,
+                       v_argnull0,
+                       v_resnullp);
+                   LLVMBuildStore(
+                       builder,
+                       v_arg0,
+                       v_resvaluep);
+                   LLVMBuildBr(builder, opblocks[i + 1]);
+
+                   /* build block to invoke function and check result */
+                   LLVMPositionBuilderAtEnd(builder, b_nonull);
+
+                   /* reset fcinfo->isnull */
+                   LLVMBuildStore(
+                       builder, LLVMConstInt(LLVMInt8Type(), 0, false),
+                       v_fcinfo_isnullp);
+
+                   /* call function */
+                   v_retval = LLVMBuildCall(
+                       builder, v_fn_addr, &v_fcinfo, 1, "funccall_nullif");
+
+                   v_fcinfo_isnull = LLVMBuildLoad(
+                       builder, v_fcinfo_isnullp, "");
+
+                   /* if result not null, and arguments are equal return null, */
+                   v_argsequal = LLVMBuildAnd(
+                       builder,
+                       LLVMBuildICmp(
+                           builder, LLVMIntEQ, v_fcinfo_isnull,
+                           LLVMConstInt(LLVMInt8Type(), 0, false), ""),
+                       LLVMBuildICmp(
+                           builder, LLVMIntEQ, v_retval,
+                           LLVMConstInt(TypeSizeT, 1, false), ""),
+                       "");
+                   LLVMBuildCondBr(
+                       builder,
+                       v_argsequal,
+                       b_argsequal,
+                       b_hasnull);
+
+                   /* build block setting result to NULL, if args are equal */
+                   LLVMPositionBuilderAtEnd(builder, b_argsequal);
+                   LLVMBuildStore(
+                       builder,
+                       LLVMConstInt(LLVMInt8Type(), 1, false),
+                       v_resnullp);
+                   LLVMBuildStore(
+                       builder,
+                       LLVMConstInt(TypeSizeT, 0, false),
+                       v_resvaluep);
+                   LLVMBuildStore(builder, v_retval, v_resvaluep);
+                   LLVMBuildBr(builder, opblocks[i + 1]);
+
+                   break;
+               }
+
+           case EEO_IOCOERCE:
+               {
+                   FunctionCallInfo fcinfo_out, fcinfo_in;
+                   LLVMValueRef v_fcinfo_out, v_fcinfo_in;
+                   LLVMValueRef v_fn_addr_out, v_fn_addr_in;
+                   LLVMValueRef v_fcinfo_in_isnullp;
+                   LLVMValueRef v_in_argp, v_out_argp;
+                   LLVMValueRef v_in_argnullp, v_out_argnullp;
+                   LLVMValueRef v_retval;
+                   LLVMValueRef v_resvalue;
+                   LLVMValueRef v_resnull;
+
+                   LLVMValueRef v_output_skip;
+                   LLVMValueRef v_output;
+
+                   LLVMValueRef v_argno;
+
+                   LLVMBasicBlockRef b_skipoutput =
+                       LLVMInsertBasicBlock(opblocks[i + 1], "skipoutputnull");
+                   LLVMBasicBlockRef b_calloutput =
+                       LLVMInsertBasicBlock(opblocks[i + 1], "calloutput");
+                   LLVMBasicBlockRef b_input =
+                       LLVMInsertBasicBlock(opblocks[i + 1], "input");
+                   LLVMBasicBlockRef b_inputcall =
+                       LLVMInsertBasicBlock(opblocks[i + 1], "inputcall");
+
+                   fcinfo_out = op->d.iocoerce.fcinfo_data_out;
+                   fcinfo_in = op->d.iocoerce.fcinfo_data_in;
+
+                   v_fcinfo_out = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(TypeSizeT, (intptr_t) fcinfo_out, false),
+                       LLVMPointerType(TypeSizeT, 0),
+                       "v_fcinfo");
+
+                   v_fcinfo_in = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(TypeSizeT, (intptr_t) fcinfo_in, false),
+                       LLVMPointerType(TypeSizeT, 0),
+                       "v_fcinfo");
+
+                   v_fn_addr_out = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(TypeSizeT, (intptr_t) fcinfo_out->flinfo->fn_addr, false),
+                       LLVMPointerType(TypePGFunction, 0),
+                       "v_fn_addr");
+
+                   v_fn_addr_in = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(TypeSizeT, (intptr_t) fcinfo_in->flinfo->fn_addr, false),
+                       LLVMPointerType(TypePGFunction, 0),
+                       "v_fn_addr");
+
+                   v_fcinfo_in_isnullp = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(TypeSizeT, (intptr_t) &fcinfo_in->isnull, false),
+                       LLVMPointerType(LLVMInt8Type(), 0),
+                       "v_fcinfo_isnull");
+
+                   v_out_argnullp = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(TypeSizeT, (uintptr_t) fcinfo_out->argnull, false),
+                       LLVMPointerType(LLVMInt8Type(), 0),
+                       "v_out_argnullp");
+
+                   v_in_argnullp = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(TypeSizeT, (uintptr_t) fcinfo_in->argnull, false),
+                       LLVMPointerType(LLVMInt8Type(), 0),
+                       "v_in_argnullp");
+
+                   v_out_argp = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(TypeSizeT, (uintptr_t) fcinfo_out->arg, false),
+                       LLVMPointerType(TypeSizeT, 0),
+                       "v_out_arg");
+
+                   v_in_argp = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(TypeSizeT, (uintptr_t) fcinfo_in->arg, false),
+                       LLVMPointerType(TypeSizeT, 0),
+                       "v_in_arg");
+
+                   /*
+                    * If input is NULL, don't call output functions, as
+                    * they're not called on NULL.
+                    */
+                   v_resnull = LLVMBuildLoad(builder, v_resnullp, "");
+                   LLVMBuildCondBr(
+                       builder,
+                       LLVMBuildICmp(
+                           builder, LLVMIntEQ, v_resnull,
+                           LLVMConstInt(LLVMInt8Type(), 1, false), ""),
+                       b_skipoutput,
+                       b_calloutput);
+
+                   LLVMPositionBuilderAtEnd(builder, b_skipoutput);
+                   v_output_skip = LLVMConstInt(TypeSizeT, 0, false);
+                   LLVMBuildBr(builder, b_input);
+
+                   LLVMPositionBuilderAtEnd(builder, b_calloutput);
+                   v_resvalue = LLVMBuildLoad(builder, v_resvaluep, "");
+                   /* set arg[0] */
+                   v_argno = LLVMConstInt(LLVMInt32Type(), 0, false);
+                   LLVMBuildStore(
+                       builder,
+                       v_resvalue,
+                       LLVMBuildGEP(builder, v_out_argp, &v_argno, 1, ""));
+                   LLVMBuildStore(
+                       builder,
+                       LLVMConstInt(LLVMInt8Type(), 0, false),
+                       LLVMBuildGEP(builder, v_out_argnullp, &v_argno, 1, ""));
+                   /* and call output function (can never return NULL) */
+                   v_output = LLVMBuildCall(
+                       builder, v_fn_addr_out, &v_fcinfo_out, 1, "funccall_coerce_out");
+                   LLVMBuildBr(builder, b_input);
+
+                   /* build block handling input function call */
+                   LLVMPositionBuilderAtEnd(builder, b_input);
+                   {
+                       LLVMValueRef incoming_values[] =
+                           {v_output_skip, v_output};
+                       LLVMBasicBlockRef incoming_blocks[] =
+                           {b_skipoutput, b_calloutput};
+                       v_output = LLVMBuildPhi(builder, TypeSizeT, "output");
+                       LLVMAddIncoming(v_output,
+                                       incoming_values, incoming_blocks,
+                                       lengthof(incoming_blocks));
+
+                   }
+
+                   /* if input function is strict, skip if input string is NULL */
+                   if (op->d.iocoerce.finfo_in->fn_strict)
+                   {
+                       LLVMBuildCondBr(
+                           builder,
+                           LLVMBuildICmp(
+                               builder, LLVMIntEQ, v_output,
+                               LLVMConstInt(TypeSizeT, 0, false), ""),
+                           opblocks[i + 1],
+                           b_inputcall);
+                   }
+                   else
+                   {
+                       LLVMBuildBr(builder, b_inputcall);
+                   }
+
+                   LLVMPositionBuilderAtEnd(builder, b_inputcall);
+                   /* set arguments */
+                   /* arg0: output */
+                   v_argno = LLVMConstInt(LLVMInt32Type(), 0, false);
+                   LLVMBuildStore(
+                       builder,
+                       v_output,
+                       LLVMBuildGEP(builder, v_in_argp, &v_argno, 1, ""));
+                   LLVMBuildStore(
+                       builder,
+                       v_resnull,
+                       LLVMBuildGEP(builder, v_in_argnullp, &v_argno, 1, ""));
+                   /* arg1: ioparam */
+                   v_argno = LLVMConstInt(LLVMInt32Type(), 1, false);
+                   LLVMBuildStore(
+                       builder,
+                       LLVMConstInt(TypeSizeT, op->d.iocoerce.intypioparam, false),
+                       LLVMBuildGEP(builder, v_in_argp, &v_argno, 1, ""));
+                   LLVMBuildStore(
+                       builder,
+                       LLVMConstInt(LLVMInt8Type(), 0, false),
+                       LLVMBuildGEP(builder, v_in_argnullp, &v_argno, 1, ""));
+                   /* arg2: typmod */
+                   v_argno = LLVMConstInt(LLVMInt32Type(), 2, false);
+                   LLVMBuildStore(
+                       builder,
+                       LLVMConstInt(TypeSizeT, -1, false),
+                       LLVMBuildGEP(builder, v_in_argp, &v_argno, 1, ""));
+                   LLVMBuildStore(
+                       builder,
+                       LLVMConstInt(LLVMInt8Type(), 0, false),
+                       LLVMBuildGEP(builder, v_in_argnullp, &v_argno, 1, ""));
+                   /* reset fcinfo_in->isnull */
+                   LLVMBuildStore(
+                       builder, LLVMConstInt(LLVMInt8Type(), 0, false),
+                       v_fcinfo_in_isnullp);
+                   /* and call function */
+                   v_retval = LLVMBuildCall(
+                       builder, v_fn_addr_in, &v_fcinfo_in, 1,
+                       "funccall_iocoerce_in");
+                   LLVMBuildStore(builder, v_retval, v_resvaluep);
+                   LLVMBuildBr(builder, opblocks[i + 1]);
+
+                   break;
+               }
+
+           case EEO_DISTINCT:
+               {
+                   FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
+
+                   LLVMValueRef v_fcinfo;
+                   LLVMValueRef v_fn_addr;
+                   LLVMValueRef v_fcinfo_isnullp;
+                   LLVMValueRef v_fcinfo_isnull;
+
+                   LLVMValueRef v_argnullp;
+                   LLVMValueRef v_argnull0, v_argisnull0;
+                   LLVMValueRef v_argnull1, v_argisnull1;
+
+                   LLVMValueRef v_anyargisnull;
+                   LLVMValueRef v_bothargisnull;
+
+                   LLVMValueRef v_argno;
+                   LLVMValueRef v_result;
+
+                   LLVMBasicBlockRef b_noargnull =
+                       LLVMInsertBasicBlock(opblocks[i + 1], "nonull");
+                   LLVMBasicBlockRef b_checkbothargnull =
+                       LLVMInsertBasicBlock(opblocks[i + 1], "checkbothargnull");
+                   LLVMBasicBlockRef b_bothargnull =
+                       LLVMInsertBasicBlock(opblocks[i + 1], "bothargnull");
+                   LLVMBasicBlockRef b_anyargnull =
+                       LLVMInsertBasicBlock(opblocks[i + 1], "anyargnull");
+
+
+                   v_fcinfo = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(TypeSizeT, (intptr_t) fcinfo, false),
+                       LLVMPointerType(TypeSizeT, 0),
+                       "v_fcinfo");
+
+                   v_fn_addr = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(TypeSizeT, (intptr_t) op->d.func.fn_addr, false),
+                       LLVMPointerType(TypePGFunction, 0),
+                       "v_fn_addr");
+
+                   v_fcinfo_isnullp = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(TypeSizeT, (intptr_t) &fcinfo->isnull, false),
+                       LLVMPointerType(LLVMInt8Type(), 0),
+                       "v_fcinfo_isnull");
+
+                   v_argnullp = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(TypeSizeT, (uintptr_t) fcinfo->argnull, false),
+                       LLVMPointerType(LLVMInt8Type(), 0),
+                       "v_argnullp");
+
+                   /* load argnull[0|1] for both arguments */
+                   v_argno = LLVMConstInt(LLVMInt32Type(), 0, false);
+                   v_argnull0 = LLVMBuildLoad(
+                       builder,
+                       LLVMBuildGEP(builder, v_argnullp, &v_argno, 1, "")
+                       , "");
+                   v_argisnull0 = LLVMBuildICmp(
+                       builder, LLVMIntEQ, v_argnull0,
+                       LLVMConstInt(LLVMInt8Type(), 1, false), "");
+
+                   v_argno = LLVMConstInt(LLVMInt32Type(), 1, false);
+                   v_argnull1 = LLVMBuildLoad(
+                       builder,
+                       LLVMBuildGEP(builder, v_argnullp, &v_argno, 1, "")
+                       , "");
+                   v_argisnull1 = LLVMBuildICmp(
+                       builder, LLVMIntEQ, v_argnull1,
+                       LLVMConstInt(LLVMInt8Type(), 1, false), "");
+
+                   v_anyargisnull = LLVMBuildOr(
+                       builder, v_argisnull0, v_argisnull1, "");
+                   v_bothargisnull = LLVMBuildAnd(
+                       builder, v_argisnull0, v_argisnull1, "");
+
+                   /*
+                    * Check function arguments for NULLness: If either is
+                    * NULL, we check if both args are NULL. Otherwise call
+                    * comparator.
+                    */
+                   LLVMBuildCondBr(
+                       builder,
+                       v_anyargisnull,
+                       b_checkbothargnull,
+                       b_noargnull);
+
+                   /*
+                    * build block checking if any arg is null
+                    */
+                   LLVMPositionBuilderAtEnd(builder, b_checkbothargnull);
+                   LLVMBuildCondBr(
+                       builder,
+                       v_bothargisnull,
+                       b_bothargnull,
+                       b_anyargnull);
+
+
+                   /* Both NULL? Then is not distinct... */
+                   LLVMPositionBuilderAtEnd(builder, b_bothargnull);
+                   LLVMBuildStore(
+                       builder,
+                       LLVMConstInt(LLVMInt8Type(), 0, false),
+                       v_resnullp);
+                   LLVMBuildStore(
+                       builder,
+                       LLVMConstInt(TypeSizeT, 0, false),
+                       v_resvaluep);
+                   LLVMBuildBr(builder, opblocks[i + 1]);
+
+                   /* Only one is NULL? Then is distinct... */
+                   LLVMPositionBuilderAtEnd(builder, b_anyargnull);
+                   LLVMBuildStore(
+                       builder,
+                       LLVMConstInt(LLVMInt8Type(), 0, false),
+                       v_resnullp);
+                   LLVMBuildStore(
+                       builder,
+                       LLVMConstInt(TypeSizeT, 1, false),
+                       v_resvaluep);
+                   LLVMBuildBr(builder, opblocks[i + 1]);
+
+                   /* neither argument is null: compare */
+                   LLVMPositionBuilderAtEnd(builder, b_noargnull);
+
+                   /* reset fcinfo->isnull */
+                   LLVMBuildStore(
+                       builder, LLVMConstInt(LLVMInt8Type(), 0, false),
+                       v_fcinfo_isnullp);
+
+                   v_result = LLVMBuildCall(
+                       builder, v_fn_addr, &v_fcinfo, 1, "funccall_distinct");
+
+                   /* Must invert result of "=" */
+                   v_result = LLVMBuildZExt(
+                       builder,
+                       LLVMBuildICmp(builder, LLVMIntEQ, v_result,
+                                     LLVMConstInt(TypeSizeT, 0, false), ""),
+                       TypeSizeT, "");
+                   v_fcinfo_isnull = LLVMBuildLoad(
+                       builder, v_fcinfo_isnullp, "");
+
+                   LLVMBuildStore(
+                       builder,
+                       v_fcinfo_isnull,
+                       v_resnullp);
+                   LLVMBuildStore(
+                       builder,
+                       v_result,
+                       v_resvaluep);
+                   LLVMBuildBr(builder, opblocks[i + 1]);
+
+                   break;
+               }
+
+           case EEO_ARRAYREF_CHECKINPUT:
+               {
+                   LLVMValueRef v_resnull;
+
+                   v_resnull = LLVMBuildLoad(builder, v_resnullp, "");
+
+                   /*
+                    * If refexpr yields NULL, and it's a fetch, then result
+                    * is NULL.
+                    */
+                   LLVMBuildCondBr(
+                       builder,
+                       LLVMBuildICmp(
+                           builder, LLVMIntEQ, v_resnull,
+                           LLVMConstInt(LLVMInt8Type(), 0, false), ""),
+                       opblocks[i + 1],
+                       opblocks[op->d.arrayref.jumpdone]);
+                   break;
+               }
+
+           case EEO_ROWCOMPARE_STEP:
+               {
+                   FunctionCallInfo fcinfo = op->d.rowcompare_step.fcinfo_data;
+                   LLVMValueRef v_fcinfo;
+                   LLVMValueRef v_fn_addr;
+                   LLVMValueRef v_fcinfo_isnullp;
+                   LLVMValueRef v_fcinfo_isnull;
+
+                   LLVMBasicBlockRef b_null =
+                       LLVMInsertBasicBlock(opblocks[i + 1], "row-null");
+                   LLVMBasicBlockRef b_compare =
+                       LLVMInsertBasicBlock(opblocks[i + 1], "row-compare");
+                   LLVMBasicBlockRef b_compare_result =
+                       LLVMInsertBasicBlock(opblocks[i + 1], "row-compare-result");
+
+                   LLVMValueRef v_retval;
+
+                   v_fcinfo = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(TypeSizeT, (intptr_t) fcinfo, false),
+                       LLVMPointerType(TypeSizeT, 0),
+                       "v_fcinfo");
+
+                   v_fn_addr = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(TypeSizeT, (intptr_t) op->d.rowcompare_step.fn_addr, false),
+                       LLVMPointerType(TypePGFunction, 0),
+                       "v_fn_addr");
+
+                   v_fcinfo_isnullp = LLVMBuildIntToPtr(
+                       builder,
+                       LLVMConstInt(TypeSizeT, (intptr_t) &fcinfo->isnull, false),
+                       LLVMPointerType(LLVMInt8Type(), 0),
+                       "v_fcinfo_isnull");
+
+                   /* if function is strict, and either arg is null, we're done */
+                   if (op->d.rowcompare_step.finfo->fn_strict)
+                   {
+                       LLVMValueRef v_argnullp;
+                       LLVMValueRef v_argnull0;
+                       LLVMValueRef v_argnull1;
+                       LLVMValueRef v_argno;
+                       LLVMValueRef v_anyargisnull;
+
+                       v_argnullp = LLVMBuildIntToPtr(
+                           builder,
+                           LLVMConstInt(TypeSizeT, (uintptr_t) fcinfo->argnull, false),
+                           LLVMPointerType(LLVMInt8Type(), 0),
+                           "v_argnullp");
+
+                       v_argno = LLVMConstInt(LLVMInt32Type(), 0, false);
+                       v_argnull0 = LLVMBuildLoad(
+                           builder,
+                           LLVMBuildGEP(builder, v_argnullp, &v_argno, 1, "")
+                           , "");
+                       v_argno = LLVMConstInt(LLVMInt32Type(), 1, false);
+                       v_argnull1 = LLVMBuildLoad(
+                           builder,
+                           LLVMBuildGEP(builder, v_argnullp, &v_argno, 1, "")
+                           , "");
+
+                       v_anyargisnull = LLVMBuildOr(
+                           builder,
+                           LLVMBuildICmp(
+                               builder, LLVMIntEQ, v_argnull0,
+                               LLVMConstInt(LLVMInt8Type(), 1, false), ""),
+                           LLVMBuildICmp(
+                               builder, LLVMIntEQ, v_argnull1,
+                           LLVMConstInt(LLVMInt8Type(), 1, false), ""),
+                           "");
+
+                       LLVMBuildCondBr(
+                           builder,
+                           v_anyargisnull,
+                           b_null,
+                           b_compare);
+                   }
+                   else
+                   {
+                       LLVMBuildBr(builder, b_compare);
+                   }
+
+                   /* build block invoking comparison function */
+                   LLVMPositionBuilderAtEnd(builder, b_compare);
+
+                   /* reset fcinfo->isnull */
+                   LLVMBuildStore(
+                       builder, LLVMConstInt(LLVMInt8Type(), 0, false),
+                       v_fcinfo_isnullp);
+
+                   /* call function */
+                   v_retval = LLVMBuildCall(
+                       builder, v_fn_addr, &v_fcinfo, 1, "funccall_rowcompare");
+                   LLVMBuildStore(builder, v_retval, v_resvaluep);
+
+                   v_fcinfo_isnull = LLVMBuildLoad(
+                       builder, v_fcinfo_isnullp, "");
+
+                   /* if result of function is NULL, force NULL result */
+                   LLVMBuildCondBr(
+                       builder,
+                       LLVMBuildICmp(
+                           builder, LLVMIntEQ, v_fcinfo_isnull,
+                           LLVMConstInt(LLVMInt8Type(), 0, false), ""),
+                       b_compare_result,
+                       b_null);
+
+                   /* build block analying the !NULL comparator result */
+                   LLVMPositionBuilderAtEnd(builder, b_compare_result);
+
+                   /* if results equal, compare next, otherwise done */
+                   LLVMBuildCondBr(
+                       builder,
+                       LLVMBuildICmp(
+                           builder, LLVMIntEQ, v_retval,
+                           LLVMConstInt(TypeSizeT, 0, false), ""),
+                       opblocks[i + 1],
+                       opblocks[op->d.rowcompare_step.jumpdone]);
+
+                   /* build block handling NULL input or NULL comparator result */
+                   LLVMPositionBuilderAtEnd(builder, b_null);
+                   LLVMBuildStore(
+                       builder,
+                       LLVMConstInt(LLVMInt8Type(), 1, false),
+                       v_resnullp);
+                   LLVMBuildBr(
+                       builder,
+                       opblocks[op->d.rowcompare_step.jumpnull]);
+
+                   break;
+               }
+
+           case EEO_ROWCOMPARE_FINAL:
+               {
+                   RowCompareType rctype = op->d.rowcompare_final.rctype;
+
+                   LLVMValueRef v_cmpresult;
+                   LLVMValueRef v_result;
+                   LLVMIntPredicate predicate;
+
+                   /*
+                    * Btree comparators return 32 bit results, need to be
+                    * careful about sign (used as a 64 bit value it's
+                    * otherwise wrong).
+                    */
+                   v_cmpresult = LLVMBuildTrunc(
+                       builder,
+                       LLVMBuildLoad(builder, v_resvaluep, ""),
+                       LLVMInt32Type(), "");
+
+                   switch (rctype)
+                   {
+                       /* EQ and NE cases aren't allowed here */
+                       case ROWCOMPARE_LT:
+                           predicate = LLVMIntSLT;
+                           break;
+                       case ROWCOMPARE_LE:
+                           predicate = LLVMIntSLE;
+                           break;
+                       case ROWCOMPARE_GT:
+                           predicate = LLVMIntSGT;
+                           break;
+                       case ROWCOMPARE_GE:
+                           predicate = LLVMIntSGE;
+                           break;
+                       default:
+                           Assert(false);
+                           predicate = 0; /* prevent compiler warning */
+                           break;
+                   }
+
+                   v_result = LLVMBuildZExt(
+                       builder,
+                       LLVMBuildICmp(
+                           builder,
+                           predicate,
+                           v_cmpresult,
+                           LLVMConstInt(LLVMInt32Type(), 0, false), ""),
+                       TypeSizeT, "");
+
+                   LLVMBuildStore(
+                       builder,
+                       LLVMConstInt(LLVMInt8Type(), 0, false),
+                       v_resnullp);
+                   LLVMBuildStore(
+                       builder,
+                       v_result,
+                       v_resvaluep);
+
+                   LLVMBuildBr(builder, opblocks[i + 1]);
+
+                   break;
+               }
+
+           case EEO_FUNCEXPR_FUSAGE:
+           case EEO_FUNCEXPR_STRICT_FUSAGE:
+
+               elog(ERROR, "unimplemented in jit: %zu", op->opcode);
+
+           case EEO_LAST:
+               Assert(false);
+               break;
+       }
+   }
+
+   llvm_add_module(mod, funcname);
+
+   state->cb = (ExecEvalExprCB) llvm_get_function(funcname);
+
+   LLVMDisposeBuilder(builder);
+   llvm_dispose_module(mod, funcname);
+}
+
+#endif
index 4cf08834350895fc13bd2bbc22f11756c421df46..d6e5337bf2d0e9e196f88c4364819ca63b736c1c 100644 (file)
@@ -523,7 +523,15 @@ ExecCheck(ExprState *state, ExprContext *econtext)
 static void
 ExecInstantiateExpr(ExprState *state)
 {
-   ExecInstantiateInterpretedExpr(state);
+#ifdef USE_LLVM
+   ExecInstantiateCompiledExpr(state);
+
+   if (!state->cb)
+#endif
+   {
+       ExecInstantiateInterpretedExpr(state);
+   }
+
 }
 
 /*
@@ -2265,6 +2273,7 @@ ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref, PlanState *parent,
    }
 }
 
+
 /*
  * Helper for preparing ArrayRef expressions for evaluation: is expr a nested
  * FieldStore or ArrayRef that might need the old element value passed down?
index c80022ee1a0ffa5f700a1b4bdbfcadd48b81517e..6e4b1012c73a3739a9fc523dc5d3b0bcabbdf2aa 100644 (file)
@@ -1021,6 +1021,17 @@ static struct config_bool ConfigureNamesBool[] =
        NULL, NULL, NULL
    },
 
+   {
+       {"jit_expressions", PGC_USERSET, DEVELOPER_OPTIONS,
+           gettext_noop("just-in-time compile expression evaluation"),
+           NULL,
+           GUC_NOT_IN_SAMPLE
+       },
+       &jit_expressions,
+       false,
+       NULL, NULL, NULL
+   },
+
 #endif
 
    {
index 003f4faede0510a547f24d039c2f28ac563469aa..62adc5bfdf6d0c6e1bccf24a71905dbf1bc48fc3 100644 (file)
@@ -418,6 +418,7 @@ typedef struct ArrayRefState
 }  ArrayRefState;
 
 extern void ExecInstantiateInterpretedExpr(ExprState *state);
+extern void ExecInstantiateCompiledExpr(ExprState *state);
 
 extern ExprEvalOp ExecEvalStepOp(ExprState *state, ExprEvalStep *op);
 
index 1e6609f1668e71f8aa086b44bcd8b161a8ad5a19..d01f9777440d411f608ad038ac1714d0be4c6a4e 100644 (file)
@@ -96,6 +96,10 @@ extern PGDLLIMPORT ExecutorEnd_hook_type ExecutorEnd_hook;
 typedef bool (*ExecutorCheckPerms_hook_type) (List *, bool);
 extern PGDLLIMPORT ExecutorCheckPerms_hook_type ExecutorCheckPerms_hook;
 
+/* GUC variables for JITing */
+#ifdef USE_LLVM
+extern bool jit_expressions;
+#endif
 
 /*
  * prototypes from functions in execAmi.c