From: Andres Freund Date: Tue, 14 Mar 2017 03:22:10 +0000 (-0700) Subject: Heavily-WIP: JITing of tuple deforming. X-Git-Url: http://waps.l3s.uni-hannover.de/gitweb/?a=commitdiff_plain;h=9286b0a727183cc9ccb0e21fd7160a22b58ff7ce;p=users%2Fandresfreund%2Fpostgres.git Heavily-WIP: JITing of tuple deforming. --- diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c index 2fbbd6822d..472e405f75 100644 --- a/src/backend/access/common/heaptuple.c +++ b/src/backend/access/common/heaptuple.c @@ -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) \ @@ -72,6 +73,15 @@ 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 diff --git a/src/backend/access/common/tupdesc.c b/src/backend/access/common/tupdesc.c index 4e2ebe1ae7..9f0b2849a6 100644 --- a/src/backend/access/common/tupdesc.c +++ b/src/backend/access/common/tupdesc.c @@ -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; } diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 6e4b1012c7..c2124c6b75 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -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 { diff --git a/src/include/access/tupdesc.h b/src/include/access/tupdesc.h index b48f839028..2a37b0c103 100644 --- a/src/include/access/tupdesc.h +++ b/src/include/access/tupdesc.h @@ -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; diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index d01f977744..c8def4ceff 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -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 /* diff --git a/src/include/executor/tuptable.h b/src/include/executor/tuptable.h index 0906f1c03f..8abb4b0d38 100644 --- a/src/include/executor/tuptable.h +++ b/src/include/executor/tuptable.h @@ -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) \