| 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 | |