Branch data Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * llvmjit_deform.c
4 : : * Generate code for deforming a heap tuple.
5 : : *
6 : : * This gains performance benefits over unJITed deforming from compile-time
7 : : * knowledge of the tuple descriptor. Fixed column widths, NOT NULLness, etc
8 : : * can be taken advantage of.
9 : : *
10 : : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
11 : : * Portions Copyright (c) 1994, Regents of the University of California
12 : : *
13 : : * IDENTIFICATION
14 : : * src/backend/jit/llvm/llvmjit_deform.c
15 : : *
16 : : *-------------------------------------------------------------------------
17 : : */
18 : :
19 : : #include "postgres.h"
20 : :
21 : : #include <llvm-c/Core.h>
22 : :
23 : : #include "access/htup_details.h"
24 : : #include "access/tupdesc_details.h"
25 : : #include "executor/tuptable.h"
26 : : #include "jit/llvmjit.h"
27 : : #include "jit/llvmjit_emit.h"
28 : :
29 : :
30 : : /*
31 : : * Create a function that deforms a tuple of type desc up to natts columns.
32 : : */
33 : : LLVMValueRef
34 : 0 : slot_compile_deform(LLVMJitContext *context, TupleDesc desc,
35 : : const TupleTableSlotOps *ops, int natts)
36 : : {
37 : : char *funcname;
38 : :
39 : : LLVMModuleRef mod;
40 : : LLVMContextRef lc;
41 : : LLVMBuilderRef b;
42 : :
43 : : LLVMTypeRef deform_sig;
44 : : LLVMValueRef v_deform_fn;
45 : :
46 : : LLVMBasicBlockRef b_entry;
47 : : LLVMBasicBlockRef b_adjust_unavail_cols;
48 : : LLVMBasicBlockRef b_find_start;
49 : :
50 : : LLVMBasicBlockRef b_out;
51 : : LLVMBasicBlockRef b_dead;
52 : : LLVMBasicBlockRef *attcheckattnoblocks;
53 : : LLVMBasicBlockRef *attstartblocks;
54 : : LLVMBasicBlockRef *attisnullblocks;
55 : : LLVMBasicBlockRef *attcheckalignblocks;
56 : : LLVMBasicBlockRef *attalignblocks;
57 : : LLVMBasicBlockRef *attstoreblocks;
58 : :
59 : : LLVMValueRef v_offp;
60 : :
61 : : LLVMValueRef v_tupdata_base;
62 : : LLVMValueRef v_tts_values;
63 : : LLVMValueRef v_tts_nulls;
64 : : LLVMValueRef v_slotoffp;
65 : : LLVMValueRef v_nvalidp;
66 : : LLVMValueRef v_nvalid;
67 : : LLVMValueRef v_maxatt;
68 : :
69 : : LLVMValueRef v_slot;
70 : :
71 : : LLVMValueRef v_tupleheaderp;
72 : : LLVMValueRef v_tuplep;
73 : : LLVMValueRef v_infomask1;
74 : : LLVMValueRef v_infomask2;
75 : : LLVMValueRef v_bits;
76 : :
77 : : LLVMValueRef v_hoff;
78 : :
79 : : LLVMValueRef v_hasnulls;
80 : :
81 : : /* last column (0 indexed) guaranteed to exist */
82 : 0 : int guaranteed_column_number = -1;
83 : :
84 : : /* current known alignment */
85 : 0 : int known_alignment = 0;
86 : :
87 : : /* if true, known_alignment describes definite offset of column */
88 : 0 : bool attguaranteedalign = true;
89 : :
90 : : int attnum;
91 : :
92 : : /* virtual tuples never need deforming, so don't generate code */
93 [ # # ]: 0 : if (ops == &TTSOpsVirtual)
94 : 0 : return NULL;
95 : :
96 : : /* decline to JIT for slot types we don't know to handle */
97 [ # # # # : 0 : if (ops != &TTSOpsHeapTuple && ops != &TTSOpsBufferHeapTuple &&
# # ]
98 : : ops != &TTSOpsMinimalTuple)
99 : 0 : return NULL;
100 : :
101 : 0 : mod = llvm_mutable_module(context);
102 : 0 : lc = LLVMGetModuleContext(mod);
103 : :
104 : 0 : funcname = llvm_expand_funcname(context, "deform");
105 : :
106 : : /*
107 : : * Check which columns have to exist in all tuples, so we don't have to
108 : : * check the row's natts unnecessarily.
109 : : */
110 [ # # ]: 0 : for (attnum = 0; attnum < desc->natts; attnum++)
111 : : {
112 : 0 : CompactAttribute *catt = TupleDescCompactAttr(desc, attnum);
113 : 0 : Form_pg_attribute attr = TupleDescAttr(desc, attnum);
114 : :
115 : : /*
116 : : * If the column is declared NOT NULL then it must be present in every
117 : : * tuple, unless there's a "missing" entry that could provide a
118 : : * non-NULL value for it. That in turn guarantees that the NULL bitmap
119 : : * - if there are any NULLable columns - is at least long enough to
120 : : * cover columns up to attnum. We treat virtual generated columns
121 : : * similar to atthasmissing columns, as these columns could either not
122 : : * be represented in the tuple or could have the column represented as
123 : : * a NULL in the null bitmap.
124 : : *
125 : : * Be paranoid and also check !attisdropped, even though the
126 : : * combination of attisdropped && attnotnull combination shouldn't
127 : : * exist.
128 : : */
129 [ # # ]: 0 : if (catt->attnullability == ATTNULLABLE_VALID &&
130 [ # # ]: 0 : !catt->atthasmissing &&
131 [ # # ]: 0 : !catt->attisdropped &&
132 [ # # ]: 0 : attr->attgenerated != ATTRIBUTE_GENERATED_VIRTUAL)
133 : 0 : guaranteed_column_number = attnum;
134 : : }
135 : :
136 : : /* Create the signature and function */
137 : : {
138 : : LLVMTypeRef param_types[1];
139 : :
140 : 0 : param_types[0] = l_ptr(StructTupleTableSlot);
141 : :
142 : 0 : deform_sig = LLVMFunctionType(LLVMVoidTypeInContext(lc),
143 : : param_types, lengthof(param_types), 0);
144 : : }
145 : 0 : v_deform_fn = LLVMAddFunction(mod, funcname, deform_sig);
146 : 0 : LLVMSetLinkage(v_deform_fn, LLVMInternalLinkage);
147 : 0 : LLVMSetParamAlignment(LLVMGetParam(v_deform_fn, 0), MAXIMUM_ALIGNOF);
148 : 0 : llvm_copy_attributes(AttributeTemplate, v_deform_fn);
149 : :
150 : : b_entry =
151 : 0 : LLVMAppendBasicBlockInContext(lc, v_deform_fn, "entry");
152 : : b_adjust_unavail_cols =
153 : 0 : LLVMAppendBasicBlockInContext(lc, v_deform_fn, "adjust_unavail_cols");
154 : : b_find_start =
155 : 0 : LLVMAppendBasicBlockInContext(lc, v_deform_fn, "find_startblock");
156 : : b_out =
157 : 0 : LLVMAppendBasicBlockInContext(lc, v_deform_fn, "outblock");
158 : : b_dead =
159 : 0 : LLVMAppendBasicBlockInContext(lc, v_deform_fn, "deadblock");
160 : :
161 : 0 : b = LLVMCreateBuilderInContext(lc);
162 : :
163 : 0 : attcheckattnoblocks = palloc_array(LLVMBasicBlockRef, natts);
164 : 0 : attstartblocks = palloc_array(LLVMBasicBlockRef, natts);
165 : 0 : attisnullblocks = palloc_array(LLVMBasicBlockRef, natts);
166 : 0 : attcheckalignblocks = palloc_array(LLVMBasicBlockRef, natts);
167 : 0 : attalignblocks = palloc_array(LLVMBasicBlockRef, natts);
168 : 0 : attstoreblocks = palloc_array(LLVMBasicBlockRef, natts);
169 : :
170 : 0 : known_alignment = 0;
171 : :
172 : 0 : LLVMPositionBuilderAtEnd(b, b_entry);
173 : :
174 : : /* perform allocas first, llvm only converts those to registers */
175 : 0 : v_offp = LLVMBuildAlloca(b, TypeSizeT, "v_offp");
176 : :
177 : 0 : v_slot = LLVMGetParam(v_deform_fn, 0);
178 : :
179 : : v_tts_values =
180 : 0 : l_load_struct_gep(b, StructTupleTableSlot, v_slot, FIELDNO_TUPLETABLESLOT_VALUES,
181 : : "tts_values");
182 : : v_tts_nulls =
183 : 0 : l_load_struct_gep(b, StructTupleTableSlot, v_slot, FIELDNO_TUPLETABLESLOT_ISNULL,
184 : : "tts_ISNULL");
185 : 0 : v_nvalidp = l_struct_gep(b, StructTupleTableSlot, v_slot, FIELDNO_TUPLETABLESLOT_NVALID, "");
186 : :
187 [ # # # # ]: 0 : if (ops == &TTSOpsHeapTuple || ops == &TTSOpsBufferHeapTuple)
188 : 0 : {
189 : : LLVMValueRef v_heapslot;
190 : :
191 : : v_heapslot =
192 : 0 : LLVMBuildBitCast(b,
193 : : v_slot,
194 : : l_ptr(StructHeapTupleTableSlot),
195 : : "heapslot");
196 : 0 : v_slotoffp = l_struct_gep(b, StructHeapTupleTableSlot, v_heapslot, FIELDNO_HEAPTUPLETABLESLOT_OFF, "");
197 : : v_tupleheaderp =
198 : 0 : l_load_struct_gep(b, StructHeapTupleTableSlot, v_heapslot, FIELDNO_HEAPTUPLETABLESLOT_TUPLE,
199 : : "tupleheader");
200 : : }
201 [ # # ]: 0 : else if (ops == &TTSOpsMinimalTuple)
202 : : {
203 : : LLVMValueRef v_minimalslot;
204 : :
205 : : v_minimalslot =
206 : 0 : LLVMBuildBitCast(b,
207 : : v_slot,
208 : : l_ptr(StructMinimalTupleTableSlot),
209 : : "minimalslot");
210 : 0 : v_slotoffp = l_struct_gep(b,
211 : : StructMinimalTupleTableSlot,
212 : : v_minimalslot,
213 : : FIELDNO_MINIMALTUPLETABLESLOT_OFF, "");
214 : : v_tupleheaderp =
215 : 0 : l_load_struct_gep(b,
216 : : StructMinimalTupleTableSlot,
217 : : v_minimalslot,
218 : : FIELDNO_MINIMALTUPLETABLESLOT_TUPLE,
219 : : "tupleheader");
220 : : }
221 : : else
222 : : {
223 : : /* should've returned at the start of the function */
224 : 0 : pg_unreachable();
225 : : }
226 : :
227 : : v_tuplep =
228 : 0 : l_load_struct_gep(b,
229 : : StructHeapTupleData,
230 : : v_tupleheaderp,
231 : : FIELDNO_HEAPTUPLEDATA_DATA,
232 : : "tuple");
233 : : v_bits =
234 : 0 : LLVMBuildBitCast(b,
235 : : l_struct_gep(b,
236 : : StructHeapTupleHeaderData,
237 : : v_tuplep,
238 : : FIELDNO_HEAPTUPLEHEADERDATA_BITS,
239 : : ""),
240 : : l_ptr(LLVMInt8TypeInContext(lc)),
241 : : "t_bits");
242 : : v_infomask1 =
243 : 0 : l_load_struct_gep(b,
244 : : StructHeapTupleHeaderData,
245 : : v_tuplep,
246 : : FIELDNO_HEAPTUPLEHEADERDATA_INFOMASK,
247 : : "infomask1");
248 : : v_infomask2 =
249 : 0 : l_load_struct_gep(b,
250 : : StructHeapTupleHeaderData,
251 : : v_tuplep, FIELDNO_HEAPTUPLEHEADERDATA_INFOMASK2,
252 : : "infomask2");
253 : :
254 : : /* t_infomask & HEAP_HASNULL */
255 : : v_hasnulls =
256 : 0 : LLVMBuildICmp(b, LLVMIntNE,
257 : : LLVMBuildAnd(b,
258 : : l_int16_const(lc, HEAP_HASNULL),
259 : : v_infomask1, ""),
260 : : l_int16_const(lc, 0),
261 : : "hasnulls");
262 : :
263 : : /* t_infomask2 & HEAP_NATTS_MASK */
264 : 0 : v_maxatt = LLVMBuildAnd(b,
265 : : l_int16_const(lc, HEAP_NATTS_MASK),
266 : : v_infomask2,
267 : : "maxatt");
268 : :
269 : : /*
270 : : * Need to zext, as getelementptr otherwise treats hoff as a signed 8bit
271 : : * integer, which'd yield a negative offset for t_hoff > 127.
272 : : */
273 : 0 : v_hoff =
274 : 0 : LLVMBuildZExt(b,
275 : : l_load_struct_gep(b,
276 : : StructHeapTupleHeaderData,
277 : : v_tuplep,
278 : : FIELDNO_HEAPTUPLEHEADERDATA_HOFF,
279 : : ""),
280 : : LLVMInt32TypeInContext(lc), "t_hoff");
281 : :
282 : 0 : v_tupdata_base = l_gep(b,
283 : : LLVMInt8TypeInContext(lc),
284 : : LLVMBuildBitCast(b,
285 : : v_tuplep,
286 : : l_ptr(LLVMInt8TypeInContext(lc)),
287 : : ""),
288 : : &v_hoff, 1,
289 : : "v_tupdata_base");
290 : :
291 : : /*
292 : : * Load tuple start offset from slot. Will be reset below in case there's
293 : : * no existing deformed columns in slot.
294 : : */
295 : : {
296 : : LLVMValueRef v_off_start;
297 : :
298 : 0 : v_off_start = l_load(b, LLVMInt32TypeInContext(lc), v_slotoffp, "v_slot_off");
299 : 0 : v_off_start = LLVMBuildZExt(b, v_off_start, TypeSizeT, "");
300 : 0 : LLVMBuildStore(b, v_off_start, v_offp);
301 : : }
302 : :
303 : : /* build the basic block for each attribute, need them as jump target */
304 [ # # ]: 0 : for (attnum = 0; attnum < natts; attnum++)
305 : : {
306 : 0 : attcheckattnoblocks[attnum] =
307 : 0 : l_bb_append_v(v_deform_fn, "block.attr.%d.attcheckattno", attnum);
308 : 0 : attstartblocks[attnum] =
309 : 0 : l_bb_append_v(v_deform_fn, "block.attr.%d.start", attnum);
310 : 0 : attisnullblocks[attnum] =
311 : 0 : l_bb_append_v(v_deform_fn, "block.attr.%d.attisnull", attnum);
312 : 0 : attcheckalignblocks[attnum] =
313 : 0 : l_bb_append_v(v_deform_fn, "block.attr.%d.attcheckalign", attnum);
314 : 0 : attalignblocks[attnum] =
315 : 0 : l_bb_append_v(v_deform_fn, "block.attr.%d.align", attnum);
316 : 0 : attstoreblocks[attnum] =
317 : 0 : l_bb_append_v(v_deform_fn, "block.attr.%d.store", attnum);
318 : : }
319 : :
320 : : /*
321 : : * Check if it is guaranteed that all the desired attributes are available
322 : : * in the tuple (but still possibly NULL), by dint of either the last
323 : : * to-be-deformed column being NOT NULL, or subsequent ones not accessed
324 : : * here being NOT NULL. If that's not guaranteed the tuple headers natt's
325 : : * has to be checked, and missing attributes potentially have to be
326 : : * fetched (using slot_getmissingattrs().
327 : : */
328 [ # # ]: 0 : if ((natts - 1) <= guaranteed_column_number)
329 : : {
330 : : /* just skip through unnecessary blocks */
331 : 0 : LLVMBuildBr(b, b_adjust_unavail_cols);
332 : 0 : LLVMPositionBuilderAtEnd(b, b_adjust_unavail_cols);
333 : 0 : LLVMBuildBr(b, b_find_start);
334 : : }
335 : : else
336 : : {
337 : : LLVMValueRef v_params[3];
338 : : LLVMValueRef f;
339 : :
340 : : /* branch if not all columns available */
341 : 0 : LLVMBuildCondBr(b,
342 : : LLVMBuildICmp(b, LLVMIntULT,
343 : : v_maxatt,
344 : : l_int16_const(lc, natts),
345 : : ""),
346 : : b_adjust_unavail_cols,
347 : : b_find_start);
348 : :
349 : : /* if not, memset tts_isnull of relevant cols to true */
350 : 0 : LLVMPositionBuilderAtEnd(b, b_adjust_unavail_cols);
351 : :
352 : 0 : v_params[0] = v_slot;
353 : 0 : v_params[1] = LLVMBuildZExt(b, v_maxatt, LLVMInt32TypeInContext(lc), "");
354 : 0 : v_params[2] = l_int32_const(lc, natts);
355 : 0 : f = llvm_pg_func(mod, "slot_getmissingattrs");
356 : 0 : l_call(b,
357 : : LLVMGetFunctionType(f), f,
358 : : v_params, lengthof(v_params), "");
359 : 0 : LLVMBuildBr(b, b_find_start);
360 : : }
361 : :
362 : 0 : LLVMPositionBuilderAtEnd(b, b_find_start);
363 : :
364 : 0 : v_nvalid = l_load(b, LLVMInt16TypeInContext(lc), v_nvalidp, "");
365 : :
366 : : /*
367 : : * Build switch to go from nvalid to the right startblock. Callers
368 : : * currently don't have the knowledge, but it'd be good for performance to
369 : : * avoid this check when it's known that the slot is empty (e.g. in scan
370 : : * nodes).
371 : : */
372 : : if (true)
373 : : {
374 : 0 : LLVMValueRef v_switch = LLVMBuildSwitch(b, v_nvalid,
375 : : b_dead, natts);
376 : :
377 [ # # ]: 0 : for (attnum = 0; attnum < natts; attnum++)
378 : : {
379 : 0 : LLVMValueRef v_attno = l_int16_const(lc, attnum);
380 : :
381 : 0 : LLVMAddCase(v_switch, v_attno, attcheckattnoblocks[attnum]);
382 : : }
383 : : }
384 : : else
385 : : {
386 : : /* jump from entry block to first block */
387 : : LLVMBuildBr(b, attcheckattnoblocks[0]);
388 : : }
389 : :
390 : 0 : LLVMPositionBuilderAtEnd(b, b_dead);
391 : 0 : LLVMBuildUnreachable(b);
392 : :
393 : : /*
394 : : * Iterate over each attribute that needs to be deformed, build code to
395 : : * deform it.
396 : : */
397 [ # # ]: 0 : for (attnum = 0; attnum < natts; attnum++)
398 : : {
399 : 0 : CompactAttribute *att = TupleDescCompactAttr(desc, attnum);
400 : 0 : Form_pg_attribute attr = TupleDescAttr(desc, attnum);
401 : :
402 : : LLVMValueRef v_incby;
403 : 0 : int alignto = att->attalignby;
404 : 0 : LLVMValueRef l_attno = l_int16_const(lc, attnum);
405 : : LLVMValueRef v_attdatap;
406 : : LLVMValueRef v_resultp;
407 : :
408 : : /* build block checking whether we did all the necessary attributes */
409 : 0 : LLVMPositionBuilderAtEnd(b, attcheckattnoblocks[attnum]);
410 : :
411 : : /*
412 : : * If this is the first attribute, slot->tts_nvalid was 0. Therefore
413 : : * also reset offset to 0, it may be from a previous execution.
414 : : */
415 [ # # ]: 0 : if (attnum == 0)
416 : : {
417 : 0 : LLVMBuildStore(b, l_sizet_const(0), v_offp);
418 : : }
419 : :
420 : : /*
421 : : * Build check whether column is available (i.e. whether the tuple has
422 : : * that many columns stored). We can avoid the branch if we know
423 : : * there's a subsequent NOT NULL column.
424 : : */
425 [ # # ]: 0 : if (attnum <= guaranteed_column_number)
426 : : {
427 : 0 : LLVMBuildBr(b, attstartblocks[attnum]);
428 : : }
429 : : else
430 : : {
431 : : LLVMValueRef v_islast;
432 : :
433 : 0 : v_islast = LLVMBuildICmp(b, LLVMIntUGE,
434 : : l_attno,
435 : : v_maxatt,
436 : : "heap_natts");
437 : 0 : LLVMBuildCondBr(b, v_islast, b_out, attstartblocks[attnum]);
438 : : }
439 : 0 : LLVMPositionBuilderAtEnd(b, attstartblocks[attnum]);
440 : :
441 : : /*
442 : : * Check for nulls if necessary. No need to take missing attributes
443 : : * into account, because if they're present the heaptuple's natts
444 : : * would have indicated that a slot_getmissingattrs() is needed. When
445 : : * present in the tuple, virtual generated columns are always stored
446 : : * as NULL, so we must always perform NULL checks for these.
447 : : */
448 [ # # ]: 0 : if (att->attnullability != ATTNULLABLE_VALID ||
449 [ # # ]: 0 : attr->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
450 : 0 : {
451 : : LLVMBasicBlockRef b_ifnotnull;
452 : : LLVMBasicBlockRef b_ifnull;
453 : : LLVMBasicBlockRef b_next;
454 : : LLVMValueRef v_attisnull;
455 : : LLVMValueRef v_nullbyteno;
456 : : LLVMValueRef v_nullbytemask;
457 : : LLVMValueRef v_nullbyte;
458 : : LLVMValueRef v_nullbit;
459 : :
460 : 0 : b_ifnotnull = attcheckalignblocks[attnum];
461 : 0 : b_ifnull = attisnullblocks[attnum];
462 : :
463 [ # # ]: 0 : if (attnum + 1 == natts)
464 : 0 : b_next = b_out;
465 : : else
466 : 0 : b_next = attcheckattnoblocks[attnum + 1];
467 : :
468 : 0 : v_nullbyteno = l_int32_const(lc, attnum >> 3);
469 : 0 : v_nullbytemask = l_int8_const(lc, 1 << ((attnum) & 0x07));
470 : 0 : v_nullbyte = l_load_gep1(b, LLVMInt8TypeInContext(lc), v_bits, v_nullbyteno, "attnullbyte");
471 : :
472 : 0 : v_nullbit = LLVMBuildICmp(b,
473 : : LLVMIntEQ,
474 : : LLVMBuildAnd(b, v_nullbyte, v_nullbytemask, ""),
475 : : l_int8_const(lc, 0),
476 : : "attisnull");
477 : :
478 : 0 : v_attisnull = LLVMBuildAnd(b, v_hasnulls, v_nullbit, "");
479 : :
480 : 0 : LLVMBuildCondBr(b, v_attisnull, b_ifnull, b_ifnotnull);
481 : :
482 : 0 : LLVMPositionBuilderAtEnd(b, b_ifnull);
483 : :
484 : : /* store null-byte */
485 : 0 : LLVMBuildStore(b,
486 : : l_int8_const(lc, 1),
487 : : l_gep(b, LLVMInt8TypeInContext(lc), v_tts_nulls, &l_attno, 1, ""));
488 : : /* store zero datum */
489 : 0 : LLVMBuildStore(b,
490 : : l_datum_const(0),
491 : : l_gep(b, TypeDatum, v_tts_values, &l_attno, 1, ""));
492 : :
493 : 0 : LLVMBuildBr(b, b_next);
494 : 0 : attguaranteedalign = false;
495 : : }
496 : : else
497 : : {
498 : : /* nothing to do */
499 : 0 : LLVMBuildBr(b, attcheckalignblocks[attnum]);
500 : 0 : LLVMPositionBuilderAtEnd(b, attisnullblocks[attnum]);
501 : 0 : LLVMBuildBr(b, attcheckalignblocks[attnum]);
502 : : }
503 : 0 : LLVMPositionBuilderAtEnd(b, attcheckalignblocks[attnum]);
504 : :
505 : : /* ------
506 : : * Even if alignment is required, we can skip doing it if provably
507 : : * unnecessary:
508 : : * - first column is guaranteed to be aligned
509 : : * - columns following a NOT NULL fixed width datum have known
510 : : * alignment, can skip alignment computation if that known alignment
511 : : * is compatible with current column.
512 : : * ------
513 : : */
514 [ # # # # ]: 0 : if (alignto > 1 &&
515 [ # # ]: 0 : (known_alignment < 0 || known_alignment != TYPEALIGN(alignto, known_alignment)))
516 : : {
517 : : /*
518 : : * When accessing a varlena field, we have to "peek" to see if we
519 : : * are looking at a pad byte or the first byte of a 1-byte-header
520 : : * datum. A zero byte must be either a pad byte, or the first
521 : : * byte of a correctly aligned 4-byte length word; in either case,
522 : : * we can align safely. A non-zero byte must be either a 1-byte
523 : : * length word, or the first byte of a correctly aligned 4-byte
524 : : * length word; in either case, we need not align.
525 : : */
526 [ # # ]: 0 : if (att->attlen == -1)
527 : : {
528 : : LLVMValueRef v_possible_padbyte;
529 : : LLVMValueRef v_ispad;
530 : : LLVMValueRef v_off;
531 : :
532 : : /* don't know if short varlena or not */
533 : 0 : attguaranteedalign = false;
534 : :
535 : 0 : v_off = l_load(b, TypeSizeT, v_offp, "");
536 : :
537 : : v_possible_padbyte =
538 : 0 : l_load_gep1(b, LLVMInt8TypeInContext(lc), v_tupdata_base, v_off, "padbyte");
539 : : v_ispad =
540 : 0 : LLVMBuildICmp(b, LLVMIntEQ,
541 : : v_possible_padbyte, l_int8_const(lc, 0),
542 : : "ispadbyte");
543 : 0 : LLVMBuildCondBr(b, v_ispad,
544 : 0 : attalignblocks[attnum],
545 : 0 : attstoreblocks[attnum]);
546 : : }
547 : : else
548 : : {
549 : 0 : LLVMBuildBr(b, attalignblocks[attnum]);
550 : : }
551 : :
552 : 0 : LLVMPositionBuilderAtEnd(b, attalignblocks[attnum]);
553 : :
554 : : /* translation of alignment code (cf TYPEALIGN()) */
555 : : {
556 : : LLVMValueRef v_off_aligned;
557 : 0 : LLVMValueRef v_off = l_load(b, TypeSizeT, v_offp, "");
558 : :
559 : : /* ((ALIGNVAL) - 1) */
560 : 0 : LLVMValueRef v_alignval = l_sizet_const(alignto - 1);
561 : :
562 : : /* ((uintptr_t) (LEN) + ((ALIGNVAL) - 1)) */
563 : 0 : LLVMValueRef v_lh = LLVMBuildAdd(b, v_off, v_alignval, "");
564 : :
565 : : /* ~((uintptr_t) ((ALIGNVAL) - 1)) */
566 : 0 : LLVMValueRef v_rh = l_sizet_const(~(alignto - 1));
567 : :
568 : 0 : v_off_aligned = LLVMBuildAnd(b, v_lh, v_rh, "aligned_offset");
569 : :
570 : 0 : LLVMBuildStore(b, v_off_aligned, v_offp);
571 : : }
572 : :
573 : : /*
574 : : * As alignment either was unnecessary or has been performed, we
575 : : * now know the current alignment. This is only safe because this
576 : : * value isn't used for varlena and nullable columns.
577 : : */
578 [ # # ]: 0 : if (known_alignment >= 0)
579 : : {
580 : : Assert(known_alignment != 0);
581 : 0 : known_alignment = TYPEALIGN(alignto, known_alignment);
582 : : }
583 : :
584 : 0 : LLVMBuildBr(b, attstoreblocks[attnum]);
585 : 0 : LLVMPositionBuilderAtEnd(b, attstoreblocks[attnum]);
586 : : }
587 : : else
588 : : {
589 : 0 : LLVMPositionBuilderAtEnd(b, attcheckalignblocks[attnum]);
590 : 0 : LLVMBuildBr(b, attalignblocks[attnum]);
591 : 0 : LLVMPositionBuilderAtEnd(b, attalignblocks[attnum]);
592 : 0 : LLVMBuildBr(b, attstoreblocks[attnum]);
593 : : }
594 : 0 : LLVMPositionBuilderAtEnd(b, attstoreblocks[attnum]);
595 : :
596 : : /*
597 : : * Store the current offset if known to be constant. That allows LLVM
598 : : * to generate better code. Without that LLVM can't figure out that
599 : : * the offset might be constant due to the jumps for previously
600 : : * decoded columns.
601 : : */
602 [ # # ]: 0 : if (attguaranteedalign)
603 : : {
604 : : Assert(known_alignment >= 0);
605 : 0 : LLVMBuildStore(b, l_sizet_const(known_alignment), v_offp);
606 : : }
607 : :
608 : : /* compute what following columns are aligned to */
609 [ # # ]: 0 : if (att->attlen < 0)
610 : : {
611 : : /* can't guarantee any alignment after variable length field */
612 : 0 : known_alignment = -1;
613 : 0 : attguaranteedalign = false;
614 : : }
615 [ # # # # ]: 0 : else if (att->attnullability == ATTNULLABLE_VALID &&
616 [ # # ]: 0 : attguaranteedalign && known_alignment >= 0)
617 : : {
618 : : /*
619 : : * If the offset to the column was previously known, a NOT NULL &
620 : : * fixed-width column guarantees that alignment is just the
621 : : * previous alignment plus column width.
622 : : */
623 : : Assert(att->attlen > 0);
624 : 0 : known_alignment += att->attlen;
625 : : }
626 [ # # ]: 0 : else if (att->attnullability == ATTNULLABLE_VALID &&
627 [ # # ]: 0 : attr->attgenerated != ATTRIBUTE_GENERATED_VIRTUAL &&
628 [ # # ]: 0 : (att->attlen % alignto) == 0)
629 : : {
630 : : /*
631 : : * After a NOT NULL (and not virtual generated) fixed-width column
632 : : * with a length that is a multiple of its alignment requirement,
633 : : * we know the following column is aligned to at least the current
634 : : * column's alignment.
635 : : */
636 : : Assert(att->attlen > 0);
637 : 0 : known_alignment = alignto;
638 : : Assert(known_alignment > 0);
639 : 0 : attguaranteedalign = false;
640 : : }
641 : : else
642 : : {
643 : 0 : known_alignment = -1;
644 : 0 : attguaranteedalign = false;
645 : : }
646 : :
647 : :
648 : : /* compute address to load data from */
649 : : {
650 : 0 : LLVMValueRef v_off = l_load(b, TypeSizeT, v_offp, "");
651 : :
652 : 0 : v_attdatap =
653 : 0 : l_gep(b, LLVMInt8TypeInContext(lc), v_tupdata_base, &v_off, 1, "");
654 : : }
655 : :
656 : : /* compute address to store value at */
657 : 0 : v_resultp = l_gep(b, TypeDatum, v_tts_values, &l_attno, 1, "");
658 : :
659 : : /* store null-byte (false) */
660 : 0 : LLVMBuildStore(b, l_int8_const(lc, 0),
661 : : l_gep(b, TypeStorageBool, v_tts_nulls, &l_attno, 1, ""));
662 : :
663 : : /*
664 : : * Store datum. For byval: datums copy the value, extend to Datum's
665 : : * width, and store. For byref types: store pointer to data.
666 : : */
667 [ # # ]: 0 : if (att->attbyval)
668 : : {
669 : : LLVMValueRef v_tmp_loaddata;
670 : 0 : LLVMTypeRef vartype = LLVMIntTypeInContext(lc, att->attlen * 8);
671 : 0 : LLVMTypeRef vartypep = LLVMPointerType(vartype, 0);
672 : :
673 : : v_tmp_loaddata =
674 : 0 : LLVMBuildPointerCast(b, v_attdatap, vartypep, "");
675 : 0 : v_tmp_loaddata = l_load(b, vartype, v_tmp_loaddata, "attr_byval");
676 : 0 : v_tmp_loaddata = LLVMBuildSExt(b, v_tmp_loaddata, TypeDatum, "");
677 : :
678 : 0 : LLVMBuildStore(b, v_tmp_loaddata, v_resultp);
679 : : }
680 : : else
681 : : {
682 : : LLVMValueRef v_tmp_loaddata;
683 : :
684 : : /* store pointer */
685 : : v_tmp_loaddata =
686 : 0 : LLVMBuildPtrToInt(b,
687 : : v_attdatap,
688 : : TypeDatum,
689 : : "attr_ptr");
690 : 0 : LLVMBuildStore(b, v_tmp_loaddata, v_resultp);
691 : : }
692 : :
693 : : /* increment data pointer */
694 [ # # ]: 0 : if (att->attlen > 0)
695 : : {
696 : 0 : v_incby = l_sizet_const(att->attlen);
697 : : }
698 [ # # ]: 0 : else if (att->attlen == -1)
699 : : {
700 : 0 : v_incby = l_call(b,
701 : : llvm_pg_var_func_type("varsize_any"),
702 : : llvm_pg_func(mod, "varsize_any"),
703 : : &v_attdatap, 1,
704 : : "varsize_any");
705 : 0 : l_callsite_ro(v_incby);
706 : 0 : l_callsite_alwaysinline(v_incby);
707 : : }
708 [ # # ]: 0 : else if (att->attlen == -2)
709 : : {
710 : 0 : v_incby = l_call(b,
711 : : llvm_pg_var_func_type("strlen"),
712 : : llvm_pg_func(mod, "strlen"),
713 : : &v_attdatap, 1, "strlen");
714 : :
715 : 0 : l_callsite_ro(v_incby);
716 : :
717 : : /* add 1 for NUL byte */
718 : 0 : v_incby = LLVMBuildAdd(b, v_incby, l_sizet_const(1), "");
719 : : }
720 : : else
721 : : {
722 : : Assert(false);
723 : 0 : v_incby = NULL; /* silence compiler */
724 : : }
725 : :
726 [ # # ]: 0 : if (attguaranteedalign)
727 : : {
728 : : Assert(known_alignment >= 0);
729 : 0 : LLVMBuildStore(b, l_sizet_const(known_alignment), v_offp);
730 : : }
731 : : else
732 : : {
733 : 0 : LLVMValueRef v_off = l_load(b, TypeSizeT, v_offp, "");
734 : :
735 : 0 : v_off = LLVMBuildAdd(b, v_off, v_incby, "increment_offset");
736 : 0 : LLVMBuildStore(b, v_off, v_offp);
737 : : }
738 : :
739 : : /*
740 : : * jump to next block, unless last possible column, or all desired
741 : : * (available) attributes have been fetched.
742 : : */
743 [ # # ]: 0 : if (attnum + 1 == natts)
744 : : {
745 : : /* jump out */
746 : 0 : LLVMBuildBr(b, b_out);
747 : : }
748 : : else
749 : : {
750 : 0 : LLVMBuildBr(b, attcheckattnoblocks[attnum + 1]);
751 : : }
752 : : }
753 : :
754 : :
755 : : /* build block that returns */
756 : 0 : LLVMPositionBuilderAtEnd(b, b_out);
757 : :
758 : : {
759 : 0 : LLVMValueRef v_off = l_load(b, TypeSizeT, v_offp, "");
760 : :
761 : 0 : LLVMBuildStore(b, l_int16_const(lc, natts), v_nvalidp);
762 : 0 : v_off = LLVMBuildTrunc(b, v_off, LLVMInt32TypeInContext(lc), "");
763 : 0 : LLVMBuildStore(b, v_off, v_slotoffp);
764 : 0 : LLVMBuildRetVoid(b);
765 : : }
766 : :
767 : 0 : LLVMDisposeBuilder(b);
768 : :
769 : 0 : return v_deform_fn;
770 : : }
|