Heavily-WIP: JITing of tuple deforming.
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:03 +0000 (23:34 -0700)
src/backend/access/common/heaptuple.c
src/backend/access/common/tupdesc.c
src/backend/utils/misc/guc.c
src/include/access/tupdesc.h
src/include/executor/executor.h
src/include/executor/tuptable.h

index 2fbbd6822d1df40784d892aa5ef5e3ae07507628..472e405f7596b694b794c4b11cbfde1c9c91ea35 100644 (file)
@@ -62,6 +62,7 @@
 #include "executor/tuptable.h"
 #include "utils/expandeddatum.h"
 
+#include "lib/llvmjit.h"
 
 /* Does att's datatype allow packing into the 1-byte-header varlena format? */
 #define ATT_IS_PACKABLE(att) \
 
 static void * slot_deform_tuple(TupleTableSlot *slot, int natts);
 
+#ifdef USE_LLVM
+bool jit_tuple_deforming = false;
+
+static void *jit_compile_deform(TupleDesc desc);
+
+/* define to verify that the JITed deform returns the correct results */
+#undef VERIFY_LLVM_RESULT
+
+#endif /* USE_LLVM */
 
 /* FIXME: use computed goto only on gcc / clang */
 #define USE_COMPUTED_GOTO
@@ -1470,6 +1480,24 @@ slot_deform_tuple(TupleTableSlot *slot, int natts)
 
    }
 
+#ifdef USE_LLVM
+   if (!slot->tts_tupleDescriptor->tddeform && jit_tuple_deforming)
+   {
+       slot->tts_tupleDescriptor->tddeform =
+           jit_compile_deform(slot->tts_tupleDescriptor);
+   }
+
+   /* if we're verifying only run the compiled version after plain deforming */
+#ifndef VERIFY_LLVM_RESULT
+   if (slot->tts_tupleDescriptor->tddeform)
+   {
+       PartiallyJittedDeform deform = slot->tts_tupleDescriptor->tddeform;
+       deform(slot, (char *) tup + tup->t_hoff, slot->tts_off, natts);
+       return NULL;
+   }
+#endif
+#endif
+
    /*
     * To avoid checking "progress" in every loop iteration, temporarily set
     * the last step + 1 to DONE. That'll cause the loop below to exit.
@@ -1679,6 +1707,69 @@ out:
    slot->tts_dp[natts].attopcode_p = SD_OPCODE(oldop);
 #endif
 
+#if defined(USE_LLVM) && defined(VERIFY_LLVM_RESULT)
+   /* verify results */
+   if (slot->tts_tupleDescriptor->tddeform)
+   {
+       Datum *save_values = slot->tts_values;
+       bool *save_isnull = slot->tts_isnull;
+       int save_nvalid = slot->tts_nvalid;
+       int save_off = slot->tts_off;
+       Datum checkvalues[MaxTupleAttributeNumber];
+       bool checknulls[MaxTupleAttributeNumber];
+       int i;
+       PartiallyJittedDeform deform = slot->tts_tupleDescriptor->tddeform;
+
+       memcpy(checknulls, slot->tts_isnull, sizeof(bool) * slot->tts_tupleDescriptor->natts);
+       memset(checkvalues, 0xef, sizeof(Datum) * natts);
+       //memcpy(checkvalues, slot->tts_values, sizeof(bool) * slot->tts_nvalid);
+
+       slot->tts_values = checkvalues;
+       slot->tts_isnull = checknulls;
+       //slot->tts_nvalid = 0;
+       //slot->tts_off = 0;
+
+       deform(slot, (char *) tup + tup->t_hoff, slot->tts_off, natts);
+
+       if (slot->tts_nvalid != attnum)
+       {
+           elog(WARNING, "nvalid differs: %d %d prev: %d, natts: %d",
+                slot->tts_nvalid, attnum, save_nvalid, natts);
+       }
+
+       if (slot->tts_off != -1 && slot->tts_off != tpc - ((char *) tup + tup->t_hoff))
+       {
+           elog(WARNING, "offs differ: %d %zd",
+                slot->tts_off,
+                tpc - ((char *) tup + tup->t_hoff));
+       }
+
+       slot->tts_off = save_off;
+       slot->tts_nvalid = save_nvalid;
+       slot->tts_values = save_values;
+       slot->tts_isnull = save_isnull;
+
+       for (i = slot->tts_nvalid; i < natts; i++)
+       {
+           if (slot->tts_isnull[i] != checknulls[i])
+           {
+               elog(ERROR, "att[%u] has differing nulls: is %c shouldbe %c", i, checknulls[i], slot->tts_isnull[i]);
+           }
+           if (checknulls[i])
+           {
+               if (checkvalues[i] != 0)
+                   elog(ERROR, "att[%u] should be 0", i);
+               continue;
+           }
+           if(checkvalues[i] != slot->tts_values[i])
+           {
+               elog(ERROR, "att[%u] values differ is %lu should be %lu", i, checkvalues[i], slot->tts_values[i]);
+           }
+       }
+   }
+#endif
+
+
    /*
     * Save state for next execution
     */
@@ -2135,3 +2226,526 @@ minimal_tuple_from_heap_tuple(HeapTuple htup)
    result->t_len = len;
    return result;
 }
+
+
+extern size_t varsize_any(void *p);
+
+size_t
+varsize_any(void *p)
+{
+   return VARSIZE_ANY(p);
+}
+
+#ifdef USE_LLVM
+
+/* build extern reference for varsize_any */
+static LLVMValueRef
+create_varsize_any(LLVMModuleRef mod)
+{
+   LLVMTypeRef *param_types = palloc(sizeof(LLVMTypeRef) * 1);
+   LLVMTypeRef sig;
+   LLVMValueRef fn;
+
+   param_types[0] = LLVMPointerType(LLVMInt8Type(), 0);
+   sig = LLVMFunctionType(LLVMInt64Type(), param_types, 1, 0);
+   fn = LLVMAddFunction(mod, "varsize_any", sig);
+
+   {
+       char argname[] = "readonly";
+       LLVMAttributeRef ref =
+           LLVMCreateStringAttribute(LLVMGetGlobalContext(), argname, strlen(argname), NULL, 0);
+       LLVMAddAttributeAtIndex(fn, LLVMAttributeFunctionIndex, ref);
+   }
+   {
+       char argname[] = "argmemonly";
+       LLVMAttributeRef ref =
+           LLVMCreateStringAttribute(LLVMGetGlobalContext(), argname, strlen(argname), NULL, 0);
+       LLVMAddAttributeAtIndex(fn, LLVMAttributeFunctionIndex, ref);
+   }
+
+   return fn;
+}
+
+/* build extern reference for strlen */
+static LLVMValueRef
+create_strlen(LLVMModuleRef mod)
+{
+   LLVMTypeRef *param_types = palloc(sizeof(LLVMTypeRef) * 1);
+   LLVMTypeRef sig;
+   LLVMValueRef fn;
+
+   param_types[0] = LLVMPointerType(LLVMInt8Type(), 0);
+   sig = LLVMFunctionType(TypeSizeT, param_types, 1, 0);
+   fn = LLVMAddFunction(mod, "strlen", sig);
+
+   return fn;
+}
+
+static void*
+jit_compile_deform(TupleDesc desc)
+{
+   static int deformcounter = 0;
+   char *funcname;
+   void *funcptr = NULL;
+
+   LLVMModuleRef mod;
+   LLVMTypeRef deform_sig;
+   LLVMValueRef deform_fn;
+   LLVMBuilderRef builder;
+   LLVMBasicBlockRef entry;
+   LLVMBasicBlockRef outblock;
+   LLVMBasicBlockRef deadblock;
+   LLVMBasicBlockRef *attcheckattnoblocks;
+   LLVMBasicBlockRef *attstartblocks;
+   LLVMBasicBlockRef *attcheckalignblocks;
+   LLVMBasicBlockRef *attalignblocks;
+   LLVMBasicBlockRef *attstoreblocks;
+   LLVMBasicBlockRef *attoutblocks;
+   LLVMValueRef tupdata_base;
+   LLVMValueRef v_off, v_off_inc, v_off_start;
+   LLVMValueRef resval;
+   LLVMValueRef resnull;
+   LLVMValueRef v_slotoffp;
+   LLVMValueRef v_nvalidp, v_nvalid;
+   LLVMValueRef l_varsize_any;
+   LLVMValueRef l_strlen;
+   LLVMValueRef v_maxatt;
+   int attnum;
+   int attcuralign = 0;
+   bool lastcouldbenull = false;
+
+   llvm_initialize();
+
+   funcname = psprintf("deform%d", deformcounter);
+   deformcounter++;
+
+   /* Create the signature and function */
+   mod = LLVMModuleCreateWithName(funcname);
+   {
+       LLVMTypeRef param_types[] = {
+           LLVMPointerType(StructTupleTableSlot, 0),
+           LLVMPointerType(LLVMInt8Type(), 0),
+           LLVMInt32Type(),
+           LLVMInt16Type()};
+       deform_sig = LLVMFunctionType(LLVMVoidType(), param_types,
+                                     lengthof(param_types), 0);
+   }
+   deform_fn = LLVMAddFunction(mod, funcname, deform_sig);
+   entry = LLVMAppendBasicBlock(deform_fn, "entry");
+   outblock = LLVMAppendBasicBlock(deform_fn, "out");
+   deadblock = LLVMAppendBasicBlock(deform_fn, "deadblock");
+   builder = LLVMCreateBuilder();
+   attcheckattnoblocks = palloc(sizeof(LLVMBasicBlockRef) * desc->natts);
+   attstartblocks = palloc(sizeof(LLVMBasicBlockRef) * desc->natts);
+   attcheckalignblocks = palloc(sizeof(LLVMBasicBlockRef) * desc->natts);
+   attalignblocks = palloc(sizeof(LLVMBasicBlockRef) * desc->natts);
+   attstoreblocks = palloc(sizeof(LLVMBasicBlockRef) * desc->natts);
+   attoutblocks = palloc(sizeof(LLVMBasicBlockRef) * desc->natts);
+
+   l_varsize_any = create_varsize_any(mod);
+   l_strlen = create_strlen(mod);
+
+   attcuralign = 0;
+   lastcouldbenull = false;
+
+   LLVMAddModule(llvm_engine, mod);
+
+   LLVMSetLinkage(deform_fn, LLVMInternalLinkage);
+   LLVMPositionBuilderAtEnd(builder, entry);
+
+   LLVMSetParamAlignment(LLVMGetParam(deform_fn, 0), MAXIMUM_ALIGNOF);
+
+   resval = LLVMBuildLoad(builder,
+                          LLVMBuildStructGEP(builder, LLVMGetParam(deform_fn, 0), 10, ""),
+                          "tts_values");
+   resnull = LLVMBuildLoad(builder,
+                           LLVMBuildStructGEP(builder, LLVMGetParam(deform_fn, 0), 11, ""),
+                           "tts_isnull");
+   v_slotoffp = LLVMBuildStructGEP(builder, LLVMGetParam(deform_fn, 0), 15, "");
+   v_nvalidp = LLVMBuildStructGEP(builder, LLVMGetParam(deform_fn, 0), 9, "");
+
+   tupdata_base = LLVMGetParam(deform_fn, 1);
+   v_off_inc = v_off = v_off_start = LLVMGetParam(deform_fn, 2);
+   v_maxatt = LLVMGetParam(deform_fn, 3);
+
+   /* build the basic block for each attribute, need them as jump target */
+   for (attnum = 0; attnum < desc->natts; attnum++)
+   {
+       char *blockname;
+
+       blockname = psprintf("block.attr.%d.attcheckattno", attnum);
+       attcheckattnoblocks[attnum] = LLVMAppendBasicBlock(deform_fn, blockname);
+       pfree(blockname);
+       blockname = psprintf("block.attr.%d.start", attnum);
+       attstartblocks[attnum] = LLVMAppendBasicBlock(deform_fn, blockname);
+       pfree(blockname);
+       blockname = psprintf("block.attr.%d.attcheckalign", attnum);
+       attcheckalignblocks[attnum] = LLVMAppendBasicBlock(deform_fn, blockname);
+       pfree(blockname);
+       blockname = psprintf("block.attr.%d.align", attnum);
+       attalignblocks[attnum] = LLVMAppendBasicBlock(deform_fn, blockname);
+       pfree(blockname);
+       blockname = psprintf("block.attr.%d.store", attnum);
+       attstoreblocks[attnum] = LLVMAppendBasicBlock(deform_fn, blockname);
+       pfree(blockname);
+       blockname = psprintf("block.attr.%d.out", attnum);
+       attoutblocks[attnum] = LLVMAppendBasicBlock(deform_fn, blockname);
+       pfree(blockname);
+   }
+
+   v_nvalid = LLVMBuildLoad(builder, v_nvalidp, "");
+
+   /* build switch to go from nvalid to the right startblock */
+   if (true)
+   {
+       LLVMValueRef v_switch = LLVMBuildSwitch(builder, v_nvalid,
+                                               deadblock, desc->natts);
+       for (attnum = 0; attnum < desc->natts; attnum++)
+       {
+           LLVMValueRef v_attno = LLVMConstInt(LLVMInt32Type(), attnum, false);
+           LLVMAddCase(v_switch, v_attno, attstartblocks[attnum]);
+       }
+
+   }
+   else
+   {
+       /* jump from entry block to first block */
+       LLVMBuildBr(builder, attstartblocks[0]);
+   }
+
+   LLVMPositionBuilderAtEnd(builder, deadblock);
+   LLVMBuildUnreachable(builder);
+
+   for (attnum = 0; attnum < desc->natts; attnum++)
+   {
+       Form_pg_attribute att = desc->attrs[attnum];
+       LLVMValueRef incby;
+       int alignto;
+       LLVMValueRef l_attno = LLVMConstInt(LLVMInt32Type(), attnum, false);
+       LLVMValueRef v_attdatap;
+       LLVMValueRef v_resultp;
+       LLVMValueRef v_islast;
+
+       /* build block checking whether we did all the necessary attributes */
+       LLVMPositionBuilderAtEnd(builder, attcheckattnoblocks[attnum]);
+
+       /*
+        * Build phi node, unless first block. This can be reached from:
+        * - store block of last attribute
+        * - start block of last attribute if null
+        */
+       if (lastcouldbenull)
+       {
+           LLVMValueRef incoming_values[] =
+               {v_off, v_off_inc};
+           LLVMBasicBlockRef incoming_blocks[] =
+               {attstartblocks[attnum - 1], attstoreblocks[attnum - 1]};
+           v_off = LLVMBuildPhi(builder, LLVMInt32Type(), "off");
+           LLVMAddIncoming(v_off,
+                           incoming_values, incoming_blocks,
+                           lengthof(incoming_blocks));
+       }
+       else
+       {
+           v_off = v_off_inc;
+       }
+
+       /* check if done */
+       v_islast = LLVMBuildICmp(builder, LLVMIntEQ,
+                                LLVMConstInt(LLVMInt16Type(), attnum, false),
+                                v_maxatt, "");
+       LLVMBuildCondBr(
+           builder,
+           v_islast,
+           attoutblocks[attnum], attstartblocks[attnum]);
+
+       /* bould block to jump out */
+       LLVMPositionBuilderAtEnd(builder, attoutblocks[attnum]);
+       LLVMBuildStore(builder, LLVMConstInt(LLVMInt32Type(), attnum, false), v_nvalidp);
+       LLVMBuildStore(builder, v_off, v_slotoffp);
+       LLVMBuildRetVoid(builder);
+
+       LLVMPositionBuilderAtEnd(builder, attstartblocks[attnum]);
+
+       /*
+        * This block can be reached because
+        * - we've been directly jumped through to continue deforming
+        * - this attribute's checkattno block
+        * Build the appropriate phi node.
+        */
+       {
+           LLVMValueRef incoming_values[] =
+               {v_off_start, v_off};
+           LLVMBasicBlockRef incoming_blocks[] =
+               {entry, attcheckattnoblocks[attnum]};
+
+           v_off = LLVMBuildPhi(builder, LLVMInt32Type(), "off");
+           LLVMAddIncoming(v_off,
+                           incoming_values, incoming_blocks,
+                           lengthof(incoming_blocks));
+       }
+
+       /* check for nulls if necessary */
+       if (!att->attnotnull)
+       {
+           LLVMBasicBlockRef blockifnotnull;
+           LLVMBasicBlockRef blockifnull;
+           LLVMValueRef attisnull;
+
+           blockifnotnull = attcheckalignblocks[attnum];
+           if (attnum + 1 == desc->natts)
+               blockifnull = outblock;
+           else
+               blockifnull = attcheckattnoblocks[attnum + 1];
+
+           /* zero Datum, FIXME: this should better only be done in the NULL case */
+           v_resultp = LLVMBuildGEP(builder, resval, &l_attno, 1, "");
+           LLVMBuildStore(builder, LLVMConstInt(TypeSizeT, 0, false), v_resultp);
+
+           attisnull = LLVMBuildLoad(builder,
+                                     LLVMBuildGEP(builder, resnull, &l_attno, 1, ""),
+                                     "");
+           attisnull = LLVMBuildICmp(builder, LLVMIntEQ, attisnull,
+                                     LLVMConstInt(LLVMInt8Type(), 1, false), "attisnull");
+           LLVMBuildCondBr(builder, attisnull, blockifnull, blockifnotnull);
+           lastcouldbenull = true;
+       }
+       else
+       {
+           LLVMBuildBr(builder, attcheckalignblocks[attnum]);
+           lastcouldbenull = false;
+       }
+       LLVMPositionBuilderAtEnd(builder, attcheckalignblocks[attnum]);
+
+       /* perform alignment */
+       if (att->attalign == 'i')
+       {
+           alignto = ALIGNOF_INT;
+       }
+       else if (att->attalign == 'c')
+       {
+           alignto = 1;
+       }
+       else if (att->attalign == 'd')
+       {
+           alignto = ALIGNOF_DOUBLE;
+       }
+       else if (att->attalign == 's')
+       {
+           alignto = ALIGNOF_SHORT;
+       }
+       else
+       {
+           elog(ERROR, "unknown alignment");
+           alignto = 0;
+       }
+
+       if ((alignto > 1 &&
+            (attcuralign < 0 || attcuralign != TYPEALIGN(alignto, attcuralign))))
+       {
+           LLVMValueRef v_off_aligned;
+           bool conditional_alignment;
+
+           /*
+            * If varlena, do only alignment if not short varlena. Check if
+            * the byte is padding for that.
+            */
+           if (att->attlen == -1)
+           {
+               LLVMValueRef possible_padbyte;
+               LLVMValueRef ispad;
+               possible_padbyte =
+                   LLVMBuildLoad(builder,
+                                 LLVMBuildGEP(builder, tupdata_base, &v_off, 1, ""),
+                                 "padbyte");
+               ispad =
+                   LLVMBuildICmp(builder, LLVMIntEQ, possible_padbyte,
+                                 LLVMConstInt(LLVMInt8Type(), 0, false),
+                                 "ispadbyte");
+               LLVMBuildCondBr(builder, ispad,
+                               attalignblocks[attnum],
+                               attstoreblocks[attnum]);
+               conditional_alignment = true;
+           }
+           else
+           {
+               LLVMBuildBr(builder, attalignblocks[attnum]);
+               conditional_alignment = false;
+           }
+
+           LLVMPositionBuilderAtEnd(builder, attalignblocks[attnum]);
+
+           {
+               /* translation of alignment code */
+#if 0
+#define TYPEALIGN(ALIGNVAL,LEN)  \
+               (((uintptr_t) (LEN) + ((ALIGNVAL) - 1)) & ~((uintptr_t) ((ALIGNVAL) - 1)))
+/* used like */
+               ptr = (char *) TYPEALIGN(ALIGNOF_DOUBLE, ptr);
+#endif
+               /* ((ALIGNVAL) - 1) */
+               LLVMValueRef alignval = LLVMConstInt(LLVMInt32Type(), alignto - 1, false);
+               /* ((uintptr_t) (LEN) + ((ALIGNVAL) - 1)) */
+               LLVMValueRef lh = LLVMBuildAdd(builder, v_off, alignval, "");
+               /* ~((uintptr_t) ((ALIGNVAL) - 1))*/
+               LLVMValueRef rh = LLVMConstInt(LLVMInt32Type(), ~(alignto - 1), false);
+
+               v_off_aligned = LLVMBuildAnd(builder, lh, rh, "aligned_offset");
+           }
+
+           LLVMBuildBr(builder, attstoreblocks[attnum]);
+           LLVMPositionBuilderAtEnd(builder, attstoreblocks[attnum]);
+
+           if (conditional_alignment)
+           {
+               LLVMValueRef incoming_values[] =
+                   {v_off, v_off_aligned};
+               LLVMBasicBlockRef incoming_blocks[] =
+                   {attcheckalignblocks[attnum], attalignblocks[attnum]};
+               v_off_inc = LLVMBuildPhi(builder, LLVMInt32Type(), "");
+               LLVMAddIncoming(v_off_inc,
+                               incoming_values, incoming_blocks,
+                               lengthof(incoming_values));
+           }
+           else
+           {
+               v_off_inc = v_off_aligned;
+           }
+       }
+       else
+       {
+           LLVMPositionBuilderAtEnd(builder, attcheckalignblocks[attnum]);
+           LLVMBuildBr(builder, attalignblocks[attnum]);
+           LLVMPositionBuilderAtEnd(builder, attalignblocks[attnum]);
+           LLVMBuildBr(builder, attstoreblocks[attnum]);
+           v_off_inc = v_off;
+       }
+       LLVMPositionBuilderAtEnd(builder, attstoreblocks[attnum]);
+
+
+       /* compute what following columns are aligned to */
+       if (att->attlen < 0)
+       {
+           /* can't guarantee any alignment after varlen field */
+           attcuralign = -1;
+       }
+       else if (att->attnotnull && attcuralign >= 0)
+       {
+           Assert(att->attlen > 0);
+           attcuralign += att->attlen;
+       }
+       else if (att->attnotnull)
+       {
+           /*
+            * After a NOT NULL fixed-width column, alignment is
+            * guaranteed to be the minimum of the forced alignment and
+            * length.  XXX
+            */
+           attcuralign = alignto + att->attlen;
+           Assert(attcuralign > 0);
+       }
+       else
+       {
+           //elog(LOG, "attnotnullreset: %d", attnum);
+           attcuralign = -1;
+       }
+
+       /* compute address to load data from */
+       v_attdatap =
+           LLVMBuildGEP(builder, tupdata_base, &v_off_inc, 1, "");
+       /* compute address to store value at */
+       v_resultp = LLVMBuildGEP(builder, resval, &l_attno, 1, "");
+
+       if (att->attbyval)
+       {
+           LLVMValueRef tmp_loaddata;
+           LLVMTypeRef vartypep =
+               LLVMPointerType(LLVMIntType(att->attlen*8), 0);
+           tmp_loaddata =
+               LLVMBuildPointerCast(builder, v_attdatap, vartypep, "");
+           tmp_loaddata = LLVMBuildLoad(builder, tmp_loaddata, "attr_byval");
+           tmp_loaddata = LLVMBuildZExt(builder, tmp_loaddata, TypeSizeT, "");
+
+           LLVMBuildStore(builder, tmp_loaddata, v_resultp);
+       }
+       else
+       {
+           LLVMValueRef tmp_loaddata;
+
+           /* store pointer */
+           tmp_loaddata =
+               LLVMBuildPtrToInt(builder,
+                                 v_attdatap,
+                                 TypeSizeT,
+                                 "attr_ptr");
+           LLVMBuildStore(builder, tmp_loaddata, v_resultp);
+       }
+
+       /* increment data pointer */
+       if (att->attlen > 0)
+       {
+           incby = LLVMConstInt(LLVMInt32Type(), att->attlen, false);
+       }
+       else if (att->attlen == -1)
+       {
+           incby =
+               LLVMBuildCall(builder, l_varsize_any,
+                             &v_attdatap, 1,
+                             "varsize_any");
+           {
+               char argname[] = "readonly";
+               LLVMAttributeRef ref =
+                   LLVMCreateStringAttribute(LLVMGetGlobalContext(), argname, strlen(argname), NULL, 0);
+               LLVMAddCallSiteAttribute(incby, LLVMAttributeFunctionIndex, ref);
+           }
+           incby = LLVMBuildTrunc(builder, incby,
+                                  LLVMInt32Type(), "");
+       }
+       else if (att->attlen == -2)
+       {
+           incby = LLVMBuildCall(builder, l_strlen, &v_attdatap, 1, "strlen");
+           incby = LLVMBuildTrunc(builder, incby,
+                                  LLVMInt32Type(), "");
+           /* add 1 for NULL byte */
+           incby =
+               LLVMBuildAdd(builder, incby,
+                            LLVMConstInt(LLVMInt32Type(), 1, false), "");
+       }
+       else
+       {
+           Assert(false);
+           incby = NULL; /* silence compiler */
+       }
+
+       v_off_inc = LLVMBuildAdd(builder, v_off_inc, incby, "increment_offset");
+
+       /*
+        * jump to next block, unless last possible column, or all desired
+        * (available) attributes have been fetched.
+        */
+       if (attnum + 1 == desc->natts)
+       {
+           LLVMBuildBr(builder, outblock);
+       }
+       else
+       {
+           LLVMBuildBr(builder, attcheckattnoblocks[attnum + 1]);
+       }
+   }
+
+   /* jump out */
+   LLVMPositionBuilderAtEnd(builder, outblock);
+   LLVMBuildStore(builder, LLVMBuildZExt(builder, v_maxatt, LLVMInt32Type(), ""), v_nvalidp);
+   LLVMBuildStore(builder, LLVMConstInt(LLVMInt32Type(), -1, false), v_slotoffp);
+   LLVMBuildRetVoid(builder);
+
+   llvm_add_module(mod, funcname);
+
+   funcptr = llvm_get_function(funcname);
+
+   LLVMDisposeBuilder(builder);
+   llvm_dispose_module(mod, funcname);
+
+   return funcptr;
+}
+#endif
index 4e2ebe1ae7efdf529e3335c27d810001ce824c6c..9f0b2849a6bbd70a2d401a7f0c24585c04aeee8a 100644 (file)
@@ -93,6 +93,9 @@ CreateTemplateTupleDesc(int natts, bool hasoid)
    desc->tdtypmod = -1;
    desc->tdhasoid = hasoid;
    desc->tdrefcount = -1;      /* assume not reference-counted */
+#ifdef USE_LLVM
+   desc->tddeform = NULL;
+#endif
 
    return desc;
 }
@@ -126,6 +129,9 @@ CreateTupleDesc(int natts, bool hasoid, Form_pg_attribute *attrs)
    desc->tdtypmod = -1;
    desc->tdhasoid = hasoid;
    desc->tdrefcount = -1;      /* assume not reference-counted */
+#ifdef USE_LLVM
+   desc->tddeform = NULL;
+#endif
 
    return desc;
 }
index 6e4b1012c73a3739a9fc523dc5d3b0bcabbdf2aa..c2124c6b75aff97404895b8fd16d4f00f6546aa2 100644 (file)
@@ -40,6 +40,7 @@
 #include "commands/vacuum.h"
 #include "commands/variable.h"
 #include "commands/trigger.h"
+#include "executor/executor.h"
 #include "funcapi.h"
 #include "lib/llvmjit.h"
 #include "libpq/auth.h"
@@ -1032,6 +1033,17 @@ static struct config_bool ConfigureNamesBool[] =
        NULL, NULL, NULL
    },
 
+   {
+       {"jit_tuple_deforming", PGC_USERSET, DEVELOPER_OPTIONS,
+           gettext_noop("just-in-time compile tuple deforming"),
+           NULL,
+           GUC_NOT_IN_SAMPLE
+       },
+       &jit_tuple_deforming,
+       false,
+       NULL, NULL, NULL
+   },
+
 #endif
 
    {
index b48f839028b8fbef6dcb5c81f54c7b4df4cbb220..2a37b0c1033cc3d8e518c10e7be1e3166111b9f8 100644 (file)
@@ -68,6 +68,11 @@ typedef struct tupleConstr
  * field of such a descriptor to -1, while reference-counted descriptors
  * always have tdrefcount >= 0.
  */
+#ifdef USE_LLVM
+struct TupleTableSlot;
+typedef void (*PartiallyJittedDeform)(struct TupleTableSlot *tupleDesc, char *data, int off, int16 numatts);
+#endif
+
 typedef struct tupleDesc
 {
    int         natts;          /* number of attributes in the tuple */
@@ -78,6 +83,9 @@ typedef struct tupleDesc
    int32       tdtypmod;       /* typmod for tuple type */
    bool        tdhasoid;       /* tuple has oid attribute in its header */
    int         tdrefcount;     /* reference count, or -1 if not counting */
+#ifdef USE_LLVM
+   PartiallyJittedDeform tddeform;
+#endif
 }  *TupleDesc;
 
 
index d01f9777440d411f608ad038ac1714d0be4c6a4e..c8def4ceff6bfa6995a190c0b41295eef9768b1a 100644 (file)
@@ -99,6 +99,7 @@ extern PGDLLIMPORT ExecutorCheckPerms_hook_type ExecutorCheckPerms_hook;
 /* GUC variables for JITing */
 #ifdef USE_LLVM
 extern bool jit_expressions;
+extern bool jit_tuple_deforming;
 #endif
 
 /*
index 0906f1c03fc51089088ff4b76a6a1285f7c1b94f..8abb4b0d38544eac8f44807507621f5b6ddd7018 100644 (file)
@@ -127,7 +127,7 @@ typedef struct TupleTableSlot
    struct DeparseSlotState *tts_dp;
    MinimalTuple tts_mintuple;  /* minimal tuple, or NULL if none */
    HeapTupleData tts_minhdr;   /* workspace for minimal-tuple-only case */
-   long        tts_off;        /* saved state for slot_deform_tuple */
+   int32       tts_off;        /* saved state for slot_deform_tuple */
 } TupleTableSlot;
 
 #define TTS_HAS_PHYSICAL_TUPLE(slot)  \