LCOV - code coverage report
Current view: top level - src/backend/jit/llvm - llvmjit_deform.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 211 222 95.0 %
Date: 2024-11-21 09:14:53 Functions: 1 1 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14