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