LCOV - code coverage report
Current view: top level - src/backend/jit/llvm - llvmjit_deform.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 0.0 % 218 0
Test Date: 2026-07-03 19:57:34 Functions: 0.0 % 1 0
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 0.0 % 80 0

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

Generated by: LCOV version 2.0-1