PostgreSQL Source Code git master
Loading...
Searching...
No Matches
llvmjit_deform.c File Reference
#include "postgres.h"
#include <llvm-c/Core.h>
#include "access/htup_details.h"
#include "access/tupdesc_details.h"
#include "executor/tuptable.h"
#include "jit/llvmjit.h"
#include "jit/llvmjit_emit.h"
Include dependency graph for llvmjit_deform.c:

Go to the source code of this file.

Functions

LLVMValueRef slot_compile_deform (LLVMJitContext *context, TupleDesc desc, const TupleTableSlotOps *ops, int natts)
 

Function Documentation

◆ slot_compile_deform()

LLVMValueRef slot_compile_deform ( LLVMJitContext context,
TupleDesc  desc,
const TupleTableSlotOps ops,
int  natts 
)

Definition at line 34 of file llvmjit_deform.c.

36{
37 char *funcname;
38
42
45
49
58
60
68
70
76
78
80
81 /* last column (0 indexed) guaranteed to exist */
83
84 /* current known alignment */
85 int known_alignment = 0;
86
87 /* if true, known_alignment describes definite offset of column */
88 bool attguaranteedalign = true;
89
90 int attnum;
91
92 /* virtual tuples never need deforming, so don't generate code */
93 if (ops == &TTSOpsVirtual)
94 return NULL;
95
96 /* decline to JIT for slot types we don't know to handle */
97 if (ops != &TTSOpsHeapTuple && ops != &TTSOpsBufferHeapTuple &&
98 ops != &TTSOpsMinimalTuple)
99 return NULL;
100
101 mod = llvm_mutable_module(context);
103
104 funcname = llvm_expand_funcname(context, "deform");
105
106 /*
107 * Check which columns have to exist, so we don't have to check the row's
108 * natts unnecessarily.
109 */
110 for (attnum = 0; attnum < desc->natts; attnum++)
111 {
113
114 /*
115 * If the column is declared NOT NULL then it must be present in every
116 * tuple, unless there's a "missing" entry that could provide a
117 * non-NULL value for it. That in turn guarantees that the NULL bitmap
118 * - if there are any NULLable columns - is at least long enough to
119 * cover columns up to attnum.
120 *
121 * Be paranoid and also check !attisdropped, even though the
122 * combination of attisdropped && attnotnull combination shouldn't
123 * exist.
124 */
125 if (att->attnullability == ATTNULLABLE_VALID &&
126 !att->atthasmissing &&
127 !att->attisdropped)
129 }
130
131 /* Create the signature and function */
132 {
133 LLVMTypeRef param_types[1];
134
135 param_types[0] = l_ptr(StructTupleTableSlot);
136
138 param_types, lengthof(param_types), 0);
139 }
144
145 b_entry =
148 LLVMAppendBasicBlockInContext(lc, v_deform_fn, "adjust_unavail_cols");
150 LLVMAppendBasicBlockInContext(lc, v_deform_fn, "find_startblock");
151 b_out =
153 b_dead =
155
157
164
165 known_alignment = 0;
166
168
169 /* perform allocas first, llvm only converts those to registers */
170 v_offp = LLVMBuildAlloca(b, TypeSizeT, "v_offp");
171
173
176 "tts_values");
179 "tts_ISNULL");
181
182 if (ops == &TTSOpsHeapTuple || ops == &TTSOpsBufferHeapTuple)
183 {
185
186 v_heapslot =
188 v_slot,
190 "heapslot");
194 "tupleheader");
195 }
196 else if (ops == &TTSOpsMinimalTuple)
197 {
199
202 v_slot,
204 "minimalslot");
214 "tupleheader");
215 }
216 else
217 {
218 /* should've returned at the start of the function */
220 }
221
222 v_tuplep =
227 "tuple");
228 v_bits =
232 v_tuplep,
234 ""),
236 "t_bits");
240 v_tuplep,
242 "infomask1");
247 "infomask2");
248
249 /* t_infomask & HEAP_HASNULL */
250 v_hasnulls =
254 v_infomask1, ""),
255 l_int16_const(lc, 0),
256 "hasnulls");
257
258 /* t_infomask2 & HEAP_NATTS_MASK */
262 "maxatt");
263
264 /*
265 * Need to zext, as getelementptr otherwise treats hoff as a signed 8bit
266 * integer, which'd yield a negative offset for t_hoff > 127.
267 */
268 v_hoff =
272 v_tuplep,
274 ""),
275 LLVMInt32TypeInContext(lc), "t_hoff");
276
280 v_tuplep,
282 ""),
283 &v_hoff, 1,
284 "v_tupdata_base");
285
286 /*
287 * Load tuple start offset from slot. Will be reset below in case there's
288 * no existing deformed columns in slot.
289 */
290 {
292
296 }
297
298 /* build the basic block for each attribute, need them as jump target */
299 for (attnum = 0; attnum < natts; attnum++)
300 {
302 l_bb_append_v(v_deform_fn, "block.attr.%d.attcheckattno", attnum);
304 l_bb_append_v(v_deform_fn, "block.attr.%d.start", attnum);
306 l_bb_append_v(v_deform_fn, "block.attr.%d.attisnull", attnum);
308 l_bb_append_v(v_deform_fn, "block.attr.%d.attcheckalign", attnum);
310 l_bb_append_v(v_deform_fn, "block.attr.%d.align", attnum);
312 l_bb_append_v(v_deform_fn, "block.attr.%d.store", attnum);
313 }
314
315 /*
316 * Check if it is guaranteed that all the desired attributes are available
317 * in the tuple (but still possibly NULL), by dint of either the last
318 * to-be-deformed column being NOT NULL, or subsequent ones not accessed
319 * here being NOT NULL. If that's not guaranteed the tuple headers natt's
320 * has to be checked, and missing attributes potentially have to be
321 * fetched (using slot_getmissingattrs().
322 */
323 if ((natts - 1) <= guaranteed_column_number)
324 {
325 /* just skip through unnecessary blocks */
329 }
330 else
331 {
333 LLVMValueRef f;
334
335 /* branch if not all columns available */
338 v_maxatt,
339 l_int16_const(lc, natts),
340 ""),
343
344 /* if not, memset tts_isnull of relevant cols to true */
346
347 v_params[0] = v_slot;
349 v_params[2] = l_int32_const(lc, natts);
350 f = llvm_pg_func(mod, "slot_getmissingattrs");
351 l_call(b,
355 }
356
358
360
361 /*
362 * Build switch to go from nvalid to the right startblock. Callers
363 * currently don't have the knowledge, but it'd be good for performance to
364 * avoid this check when it's known that the slot is empty (e.g. in scan
365 * nodes).
366 */
367 if (true)
368 {
370 b_dead, natts);
371
372 for (attnum = 0; attnum < natts; attnum++)
373 {
375
377 }
378 }
379 else
380 {
381 /* jump from entry block to first block */
383 }
384
387
388 /*
389 * Iterate over each attribute that needs to be deformed, build code to
390 * deform it.
391 */
392 for (attnum = 0; attnum < natts; attnum++)
393 {
396 int alignto = att->attalignby;
400
401 /* build block checking whether we did all the necessary attributes */
403
404 /*
405 * If this is the first attribute, slot->tts_nvalid was 0. Therefore
406 * also reset offset to 0, it may be from a previous execution.
407 */
408 if (attnum == 0)
409 {
411 }
412
413 /*
414 * Build check whether column is available (i.e. whether the tuple has
415 * that many columns stored). We can avoid the branch if we know
416 * there's a subsequent NOT NULL column.
417 */
419 {
421 }
422 else
423 {
425
427 l_attno,
428 v_maxatt,
429 "heap_natts");
431 }
433
434 /*
435 * Check for nulls if necessary. No need to take missing attributes
436 * into account, because if they're present the heaptuple's natts
437 * would have indicated that a slot_getmissingattrs() is needed.
438 */
439 if (att->attnullability != ATTNULLABLE_VALID)
440 {
449
452
453 if (attnum + 1 == natts)
454 b_next = b_out;
455 else
457
459 v_nullbytemask = l_int8_const(lc, 1 << ((attnum) & 0x07));
461
463 LLVMIntEQ,
465 l_int8_const(lc, 0),
466 "attisnull");
467
469
471
473
474 /* store null-byte */
476 l_int8_const(lc, 1),
478 /* store zero datum */
480 l_datum_const(0),
481 l_gep(b, TypeDatum, v_tts_values, &l_attno, 1, ""));
482
484 attguaranteedalign = false;
485 }
486 else
487 {
488 /* nothing to do */
492 }
494
495 /* ------
496 * Even if alignment is required, we can skip doing it if provably
497 * unnecessary:
498 * - first column is guaranteed to be aligned
499 * - columns following a NOT NULL fixed width datum have known
500 * alignment, can skip alignment computation if that known alignment
501 * is compatible with current column.
502 * ------
503 */
504 if (alignto > 1 &&
506 {
507 /*
508 * When accessing a varlena field, we have to "peek" to see if we
509 * are looking at a pad byte or the first byte of a 1-byte-header
510 * datum. A zero byte must be either a pad byte, or the first
511 * byte of a correctly aligned 4-byte length word; in either case,
512 * we can align safely. A non-zero byte must be either a 1-byte
513 * length word, or the first byte of a correctly aligned 4-byte
514 * length word; in either case, we need not align.
515 */
516 if (att->attlen == -1)
517 {
521
522 /* don't know if short varlena or not */
523 attguaranteedalign = false;
524
525 v_off = l_load(b, TypeSizeT, v_offp, "");
526
529 v_ispad =
532 "ispadbyte");
536 }
537 else
538 {
540 }
541
543
544 /* translation of alignment code (cf TYPEALIGN()) */
545 {
548
549 /* ((ALIGNVAL) - 1) */
551
552 /* ((uintptr_t) (LEN) + ((ALIGNVAL) - 1)) */
554
555 /* ~((uintptr_t) ((ALIGNVAL) - 1)) */
557
558 v_off_aligned = LLVMBuildAnd(b, v_lh, v_rh, "aligned_offset");
559
561 }
562
563 /*
564 * As alignment either was unnecessary or has been performed, we
565 * now know the current alignment. This is only safe because this
566 * value isn't used for varlena and nullable columns.
567 */
568 if (known_alignment >= 0)
569 {
572 }
573
576 }
577 else
578 {
583 }
585
586 /*
587 * Store the current offset if known to be constant. That allows LLVM
588 * to generate better code. Without that LLVM can't figure out that
589 * the offset might be constant due to the jumps for previously
590 * decoded columns.
591 */
593 {
596 }
597
598 /* compute what following columns are aligned to */
599 if (att->attlen < 0)
600 {
601 /* can't guarantee any alignment after variable length field */
602 known_alignment = -1;
603 attguaranteedalign = false;
604 }
605 else if (att->attnullability == ATTNULLABLE_VALID &&
607 {
608 /*
609 * If the offset to the column was previously known, a NOT NULL &
610 * fixed-width column guarantees that alignment is just the
611 * previous alignment plus column width.
612 */
613 Assert(att->attlen > 0);
614 known_alignment += att->attlen;
615 }
616 else if (att->attnullability == ATTNULLABLE_VALID &&
617 (att->attlen % alignto) == 0)
618 {
619 /*
620 * After a NOT NULL fixed-width column with a length that is a
621 * multiple of its alignment requirement, we know the following
622 * column is aligned to at least the current column's alignment.
623 */
624 Assert(att->attlen > 0);
627 attguaranteedalign = false;
628 }
629 else
630 {
631 known_alignment = -1;
632 attguaranteedalign = false;
633 }
634
635
636 /* compute address to load data from */
637 {
639
640 v_attdatap =
642 }
643
644 /* compute address to store value at */
646
647 /* store null-byte (false) */
650
651 /*
652 * Store datum. For byval: datums copy the value, extend to Datum's
653 * width, and store. For byref types: store pointer to data.
654 */
655 if (att->attbyval)
656 {
658 LLVMTypeRef vartype = LLVMIntTypeInContext(lc, att->attlen * 8);
660
663 v_tmp_loaddata = l_load(b, vartype, v_tmp_loaddata, "attr_byval");
665
667 }
668 else
669 {
671
672 /* store pointer */
676 TypeDatum,
677 "attr_ptr");
679 }
680
681 /* increment data pointer */
682 if (att->attlen > 0)
683 {
684 v_incby = l_sizet_const(att->attlen);
685 }
686 else if (att->attlen == -1)
687 {
688 v_incby = l_call(b,
689 llvm_pg_var_func_type("varsize_any"),
690 llvm_pg_func(mod, "varsize_any"),
691 &v_attdatap, 1,
692 "varsize_any");
695 }
696 else if (att->attlen == -2)
697 {
698 v_incby = l_call(b,
699 llvm_pg_var_func_type("strlen"),
700 llvm_pg_func(mod, "strlen"),
701 &v_attdatap, 1, "strlen");
702
704
705 /* add 1 for NUL byte */
707 }
708 else
709 {
710 Assert(false);
711 v_incby = NULL; /* silence compiler */
712 }
713
715 {
718 }
719 else
720 {
722
723 v_off = LLVMBuildAdd(b, v_off, v_incby, "increment_offset");
725 }
726
727 /*
728 * jump to next block, unless last possible column, or all desired
729 * (available) attributes have been fetched.
730 */
731 if (attnum + 1 == natts)
732 {
733 /* jump out */
735 }
736 else
737 {
739 }
740 }
741
742
743 /* build block that returns */
745
746 {
748
753 }
754
756
757 return v_deform_fn;
758}
#define TYPEALIGN(ALIGNVAL, LEN)
Definition c.h:888
#define Assert(condition)
Definition c.h:942
#define pg_unreachable()
Definition c.h:361
#define lengthof(array)
Definition c.h:872
const TupleTableSlotOps TTSOpsVirtual
Definition execTuples.c:84
const TupleTableSlotOps TTSOpsBufferHeapTuple
Definition execTuples.c:87
const TupleTableSlotOps TTSOpsHeapTuple
Definition execTuples.c:85
const TupleTableSlotOps TTSOpsMinimalTuple
Definition execTuples.c:86
#define palloc_array(type, count)
Definition fe_memutils.h:76
#define FIELDNO_HEAPTUPLEDATA_DATA
Definition htup.h:67
#define HEAP_NATTS_MASK
#define HEAP_HASNULL
#define FIELDNO_HEAPTUPLEHEADERDATA_INFOMASK
#define FIELDNO_HEAPTUPLEHEADERDATA_HOFF
#define FIELDNO_HEAPTUPLEHEADERDATA_BITS
#define FIELDNO_HEAPTUPLEHEADERDATA_INFOMASK2
#define funcname
int b
Definition isn.c:74
LLVMTypeRef StructMinimalTupleTableSlot
Definition llvmjit.c:68
LLVMValueRef llvm_pg_func(LLVMModuleRef mod, const char *funcname)
Definition llvmjit.c:465
LLVMTypeRef TypeSizeT
Definition llvmjit.c:56
char * llvm_expand_funcname(struct LLVMJitContext *context, const char *basename)
Definition llvmjit.c:342
LLVMTypeRef llvm_pg_var_func_type(const char *varname)
Definition llvmjit.c:443
LLVMTypeRef StructTupleTableSlot
Definition llvmjit.c:65
LLVMTypeRef TypeStorageBool
Definition llvmjit.c:59
LLVMTypeRef TypeDatum
Definition llvmjit.c:57
LLVMTypeRef StructHeapTupleTableSlot
Definition llvmjit.c:67
LLVMModuleRef llvm_mutable_module(LLVMJitContext *context)
Definition llvmjit.c:317
LLVMValueRef AttributeTemplate
Definition llvmjit.c:79
LLVMTypeRef StructHeapTupleHeaderData
Definition llvmjit.c:66
LLVMTypeRef StructHeapTupleData
Definition llvmjit.c:62
void llvm_copy_attributes(LLVMValueRef v_from, LLVMValueRef v_to)
Definition llvmjit.c:517
LLVMTypeRef LLVMGetFunctionType(LLVMValueRef r)
int16 attnum
static int fb(int x)
#define ATTNULLABLE_VALID
Definition tupdesc.h:86
static CompactAttribute * TupleDescCompactAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:193
#define FIELDNO_HEAPTUPLETABLESLOT_OFF
Definition tuptable.h:280
#define FIELDNO_HEAPTUPLETABLESLOT_TUPLE
Definition tuptable.h:278
#define FIELDNO_TUPLETABLESLOT_ISNULL
Definition tuptable.h:132
#define FIELDNO_MINIMALTUPLETABLESLOT_TUPLE
Definition tuptable.h:314
#define FIELDNO_MINIMALTUPLETABLESLOT_OFF
Definition tuptable.h:318
#define FIELDNO_TUPLETABLESLOT_VALUES
Definition tuptable.h:130
#define FIELDNO_TUPLETABLESLOT_NVALID
Definition tuptable.h:125

References Assert, ATTNULLABLE_VALID, attnum, AttributeTemplate, b, fb(), FIELDNO_HEAPTUPLEDATA_DATA, FIELDNO_HEAPTUPLEHEADERDATA_BITS, FIELDNO_HEAPTUPLEHEADERDATA_HOFF, FIELDNO_HEAPTUPLEHEADERDATA_INFOMASK, FIELDNO_HEAPTUPLEHEADERDATA_INFOMASK2, FIELDNO_HEAPTUPLETABLESLOT_OFF, FIELDNO_HEAPTUPLETABLESLOT_TUPLE, FIELDNO_MINIMALTUPLETABLESLOT_OFF, FIELDNO_MINIMALTUPLETABLESLOT_TUPLE, FIELDNO_TUPLETABLESLOT_ISNULL, FIELDNO_TUPLETABLESLOT_NVALID, FIELDNO_TUPLETABLESLOT_VALUES, funcname, HEAP_HASNULL, HEAP_NATTS_MASK, lengthof, llvm_copy_attributes(), llvm_expand_funcname(), llvm_mutable_module(), llvm_pg_func(), llvm_pg_var_func_type(), LLVMGetFunctionType(), TupleDescData::natts, palloc_array, pg_unreachable, StructHeapTupleData, StructHeapTupleHeaderData, StructHeapTupleTableSlot, StructMinimalTupleTableSlot, StructTupleTableSlot, TTSOpsBufferHeapTuple, TTSOpsHeapTuple, TTSOpsMinimalTuple, TTSOpsVirtual, TupleDescCompactAttr(), TYPEALIGN, TypeDatum, TypeSizeT, and TypeStorageBool.

Referenced by llvm_compile_expr().