Home | History | Annotate | Line # | Download | only in m4
      1 dnl Support macro file for intrinsic functions.
      2 dnl Contains the generic sections of the array functions.
      3 dnl This file is part of the GNU Fortran Runtime Library (libgfortran)
      4 dnl Distributed under the GNU GPL with exception.  See COPYING for details.
      5 dnl
      6 dnl Pass the implementation for a single section as the parameter to
      7 dnl {MASK_}ARRAY_FUNCTION.
      8 dnl The variables base, delta, and len describe the input section.
      9 dnl For masked section the mask is described by mbase and mdelta.
     10 dnl These should not be modified. The result should be stored in *dest.
     11 dnl The names count, extent, sstride, dstride, base, dest, rank, dim
     12 dnl retarray, array, pdim and mstride should not be used.
     13 dnl The variable n is declared as index_type and may be used.
     14 dnl Other variable declarations may be placed at the start of the code,
     15 dnl The types of the array parameter and the return value are
     16 dnl atype_name and rtype_name respectively.
     17 dnl Execution should be allowed to continue to the end of the block.
     18 dnl You should not return or break from the inner loop of the implementation.
     19 dnl Care should also be taken to avoid using the names defined in iparm.m4
     20 define(START_ARRAY_FUNCTION,
     21 `#include <string.h>
     22 #include <assert.h>
     23 
     24 static inline int
     25 compare_fcn (const atype_name *a, const atype_name *b, gfc_charlen_type n)
     26 {
     27   if (sizeof ('atype_name`) == 1)
     28     return memcmp (a, b, n);
     29   else
     30     return memcmp_char4 (a, b, n);
     31 }
     32 
     33 extern void name`'rtype_qual`_'atype_code (rtype` * const restrict, 
     34 	'atype` * const restrict, const index_type * const restrict 'back_arg`,
     35 	gfc_charlen_type);
     36 export_proto('name`'rtype_qual`_'atype_code`);
     37 
     38 void
     39 'name`'rtype_qual`_'atype_code` ('rtype` * const restrict retarray, 
     40 	'atype` * const restrict array, 
     41 	const index_type * const restrict pdim'back_arg`,
     42 	gfc_charlen_type string_len)
     43 {
     44   index_type count[GFC_MAX_DIMENSIONS];
     45   index_type extent[GFC_MAX_DIMENSIONS];
     46   index_type sstride[GFC_MAX_DIMENSIONS];
     47   index_type dstride[GFC_MAX_DIMENSIONS];
     48   const 'atype_name * restrict base;
     49   rtype_name * restrict dest;
     50   index_type rank;
     51   index_type n;
     52   index_type len;
     53   index_type delta;
     54   index_type dim;
     55   int continue_loop;
     56 
     57   /* Make dim zero based to avoid confusion.  */
     58   rank = GFC_DESCRIPTOR_RANK (array) - 1;
     59   dim = (*pdim) - 1;
     60 
     61   if (unlikely (dim < 0 || dim > rank))
     62     {
     63       runtime_error ("Dim argument incorrect in u_name intrinsic: "
     64  		     "is %ld, should be between 1 and %ld",
     65 		     (long int) dim + 1, (long int) rank + 1);
     66     }
     67 
     68   len = GFC_DESCRIPTOR_EXTENT(array,dim);
     69   if (len < 0)
     70     len = 0;
     71   delta = GFC_DESCRIPTOR_STRIDE(array,dim) * string_len;
     72 
     73   for (n = 0; n < dim; n++)
     74     {
     75       sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n) * string_len;
     76       extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
     77 
     78       if (extent[n] < 0)
     79 	extent[n] = 0;
     80     }
     81   for (n = dim; n < rank; n++)
     82     {
     83       sstride[n] = GFC_DESCRIPTOR_STRIDE(array, n + 1) * string_len;
     84       extent[n] = GFC_DESCRIPTOR_EXTENT(array, n + 1);
     85 
     86       if (extent[n] < 0)
     87 	extent[n] = 0;
     88     }
     89 
     90   if (retarray->base_addr == NULL)
     91     {
     92       size_t alloc_size, str;
     93 
     94       for (n = 0; n < rank; n++)
     95 	{
     96 	  if (n == 0)
     97 	    str = 1;
     98 	  else
     99 	    str = GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1];
    100 
    101 	  GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str);
    102 
    103 	}
    104 
    105       retarray->offset = 0;
    106       retarray->dtype.rank = rank;
    107 
    108       alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1];
    109 
    110       retarray->base_addr = xmallocarray (alloc_size, sizeof (rtype_name));
    111       if (alloc_size == 0)
    112 	{
    113 	  /* Make sure we have a zero-sized array.  */
    114 	  GFC_DIMENSION_SET(retarray->dim[0], 0, -1, 1);
    115 	  return;
    116 
    117 	}
    118     }
    119   else
    120     {
    121       if (rank != GFC_DESCRIPTOR_RANK (retarray))
    122 	runtime_error ("rank of return array incorrect in"
    123 		       " u_name intrinsic: is %ld, should be %ld",
    124 		       (long int) (GFC_DESCRIPTOR_RANK (retarray)),
    125 		       (long int) rank);
    126 
    127       if (unlikely (compile_options.bounds_check))
    128 	bounds_ifunction_return ((array_t *) retarray, extent,
    129 				 "return value", "u_name");
    130     }
    131 
    132   for (n = 0; n < rank; n++)
    133     {
    134       count[n] = 0;
    135       dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n);
    136       if (extent[n] <= 0)
    137 	return;
    138     }
    139 
    140   base = array->base_addr;
    141   dest = retarray->base_addr;
    142 
    143   continue_loop = 1;
    144   while (continue_loop)
    145     {
    146       const atype_name * restrict src;
    147       rtype_name result;
    148       src = base;
    149       {
    150 ')dnl
    151 define(START_ARRAY_BLOCK,
    152 `	if (len <= 0)
    153 	  *dest = '$1`;
    154 	else
    155 	  {
    156 	    for (n = 0; n < len; n++, src += delta)
    157 	      {
    158 ')dnl
    159 define(FINISH_ARRAY_FUNCTION,
    160 `	      }
    161 	    '$1`
    162 	    *dest = result;
    163 	  }
    164       }
    165       /* Advance to the next element.  */
    166       count[0]++;
    167       base += sstride[0];
    168       dest += dstride[0];
    169       n = 0;
    170       while (count[n] == extent[n])
    171 	{
    172 	  /* When we get to the end of a dimension, reset it and increment
    173 	     the next dimension.  */
    174 	  count[n] = 0;
    175 	  /* We could precalculate these products, but this is a less
    176 	     frequently used path so probably not worth it.  */
    177 	  base -= sstride[n] * extent[n];
    178 	  dest -= dstride[n] * extent[n];
    179 	  n++;
    180 	  if (n >= rank)
    181 	    {
    182 	      /* Break out of the loop.  */
    183 	      continue_loop = 0;
    184 	      break;
    185 	    }
    186 	  else
    187 	    {
    188 	      count[n]++;
    189 	      base += sstride[n];
    190 	      dest += dstride[n];
    191 	    }
    192 	}
    193     }
    194 }')dnl
    195 define(START_MASKED_ARRAY_FUNCTION,
    196 `
    197 extern void `m'name`'rtype_qual`_'atype_code` ('rtype` * const restrict, 
    198 	'atype` * const restrict, const index_type * const restrict,
    199 	gfc_array_l1 * const restrict'back_arg`, gfc_charlen_type);
    200 export_proto(m'name`'rtype_qual`_'atype_code`);
    201 
    202 void
    203 m'name`'rtype_qual`_'atype_code` ('rtype` * const restrict retarray, 
    204 	'atype` * const restrict array, 
    205 	const index_type * const restrict pdim, 
    206 	gfc_array_l1 * const restrict mask'back_arg`,
    207 	gfc_charlen_type string_len)
    208 {
    209   index_type count[GFC_MAX_DIMENSIONS];
    210   index_type extent[GFC_MAX_DIMENSIONS];
    211   index_type sstride[GFC_MAX_DIMENSIONS];
    212   index_type dstride[GFC_MAX_DIMENSIONS];
    213   index_type mstride[GFC_MAX_DIMENSIONS];
    214   'rtype_name * restrict dest;
    215   const atype_name * restrict base;
    216   const GFC_LOGICAL_1 * restrict mbase;
    217   index_type rank;
    218   index_type dim;
    219   index_type n;
    220   index_type len;
    221   index_type delta;
    222   index_type mdelta;
    223   int mask_kind;
    224 
    225   if (mask == NULL)
    226     {
    227 #ifdef HAVE_BACK_ARG
    228       name`'rtype_qual`_'atype_code (retarray, array, pdim, back, string_len);
    229 #else
    230       name`'rtype_qual`_'atype_code (retarray, array, pdim, string_len);
    231 #endif
    232       return;
    233     }
    234 
    235   dim = (*pdim) - 1;
    236   rank = GFC_DESCRIPTOR_RANK (array) - 1;
    237 
    238 
    239   if (unlikely (dim < 0 || dim > rank))
    240     {
    241       runtime_error ("Dim argument incorrect in u_name intrinsic: "
    242  		     "is %ld, should be between 1 and %ld",
    243 		     (long int) dim + 1, (long int) rank + 1);
    244     }
    245 
    246   len = GFC_DESCRIPTOR_EXTENT(array,dim);
    247   if (len <= 0)
    248     return;
    249 
    250   mbase = mask->base_addr;
    251 
    252   mask_kind = GFC_DESCRIPTOR_SIZE (mask);
    253 
    254   if (mask_kind == 1 || mask_kind == 2 || mask_kind == 4 || mask_kind == 8
    255 #ifdef HAVE_GFC_LOGICAL_16
    256       || mask_kind == 16
    257 #endif
    258       )
    259     mbase = GFOR_POINTER_TO_L1 (mbase, mask_kind);
    260   else
    261     runtime_error ("Funny sized logical array");
    262 
    263   delta = GFC_DESCRIPTOR_STRIDE(array,dim) * string_len;
    264   mdelta = GFC_DESCRIPTOR_STRIDE_BYTES(mask,dim);
    265 
    266   for (n = 0; n < dim; n++)
    267     {
    268       sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n) * string_len;
    269       mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n);
    270       extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
    271 
    272       if (extent[n] < 0)
    273 	extent[n] = 0;
    274 
    275     }
    276   for (n = dim; n < rank; n++)
    277     {
    278       sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n + 1) * string_len;
    279       mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask, n + 1);
    280       extent[n] = GFC_DESCRIPTOR_EXTENT(array, n + 1);
    281 
    282       if (extent[n] < 0)
    283 	extent[n] = 0;
    284     }
    285 
    286   if (retarray->base_addr == NULL)
    287     {
    288       size_t alloc_size, str;
    289 
    290       for (n = 0; n < rank; n++)
    291 	{
    292 	  if (n == 0)
    293 	    str = 1;
    294 	  else
    295 	    str= GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1];
    296 
    297 	  GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str);
    298 
    299 	}
    300 
    301       alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1];
    302 
    303       retarray->offset = 0;
    304       retarray->dtype.rank = rank;
    305 
    306       if (alloc_size == 0)
    307 	{
    308 	  /* Make sure we have a zero-sized array.  */
    309 	  GFC_DIMENSION_SET(retarray->dim[0], 0, -1, 1);
    310 	  return;
    311 	}
    312       else
    313 	retarray->base_addr = xmallocarray (alloc_size, sizeof (rtype_name));
    314 
    315     }
    316   else
    317     {
    318       if (rank != GFC_DESCRIPTOR_RANK (retarray))
    319 	runtime_error ("rank of return array incorrect in u_name intrinsic");
    320 
    321       if (unlikely (compile_options.bounds_check))
    322 	{
    323 	  bounds_ifunction_return ((array_t *) retarray, extent,
    324 				   "return value", "u_name");
    325 	  bounds_equal_extents ((array_t *) mask, (array_t *) array,
    326 	  			"MASK argument", "u_name");
    327 	}
    328     }
    329 
    330   for (n = 0; n < rank; n++)
    331     {
    332       count[n] = 0;
    333       dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n);
    334       if (extent[n] <= 0)
    335 	return;
    336     }
    337 
    338   dest = retarray->base_addr;
    339   base = array->base_addr;
    340 
    341   while (base)
    342     {
    343       const atype_name * restrict src;
    344       const GFC_LOGICAL_1 * restrict msrc;
    345       rtype_name result;
    346       src = base;
    347       msrc = mbase;
    348       {
    349 ')dnl
    350 define(START_MASKED_ARRAY_BLOCK,
    351 `	for (n = 0; n < len; n++, src += delta, msrc += mdelta)
    352 	  {
    353 ')dnl
    354 define(FINISH_MASKED_ARRAY_FUNCTION,
    355 `	  }
    356 	*dest = result;
    357       }
    358       /* Advance to the next element.  */
    359       count[0]++;
    360       base += sstride[0];
    361       mbase += mstride[0];
    362       dest += dstride[0];
    363       n = 0;
    364       while (count[n] == extent[n])
    365 	{
    366 	  /* When we get to the end of a dimension, reset it and increment
    367 	     the next dimension.  */
    368 	  count[n] = 0;
    369 	  /* We could precalculate these products, but this is a less
    370 	     frequently used path so probably not worth it.  */
    371 	  base -= sstride[n] * extent[n];
    372 	  mbase -= mstride[n] * extent[n];
    373 	  dest -= dstride[n] * extent[n];
    374 	  n++;
    375 	  if (n >= rank)
    376 	    {
    377 	      /* Break out of the loop.  */
    378 	      base = NULL;
    379 	      break;
    380 	    }
    381 	  else
    382 	    {
    383 	      count[n]++;
    384 	      base += sstride[n];
    385 	      mbase += mstride[n];
    386 	      dest += dstride[n];
    387 	    }
    388 	}
    389     }
    390 }')dnl
    391 define(SCALAR_ARRAY_FUNCTION,
    392 `
    393 extern void `s'name`'rtype_qual`_'atype_code` ('rtype` * const restrict, 
    394 	'atype` * const restrict, const index_type * const restrict,
    395 	GFC_LOGICAL_4 *'back_arg`, gfc_charlen_type);
    396 export_proto(s'name`'rtype_qual`_'atype_code`);
    397 
    398 void
    399 s'name`'rtype_qual`_'atype_code` ('rtype` * const restrict retarray, 
    400 	'atype` * const restrict array, 
    401 	const index_type * const restrict pdim, 
    402 	GFC_LOGICAL_4 * mask 'back_arg`, gfc_charlen_type string_len)
    403 {
    404   index_type count[GFC_MAX_DIMENSIONS];
    405   index_type extent[GFC_MAX_DIMENSIONS];
    406   index_type dstride[GFC_MAX_DIMENSIONS];
    407   'rtype_name * restrict dest;
    408   index_type rank;
    409   index_type n;
    410   index_type dim;
    411 
    412 
    413   if (mask == NULL || *mask)
    414     {
    415 #ifdef HAVE_BACK_ARG
    416       name`'rtype_qual`_'atype_code (retarray, array, pdim, back, string_len);
    417 #else
    418       name`'rtype_qual`_'atype_code (retarray, array, pdim, string_len);
    419 #endif
    420       return;
    421     }
    422   /* Make dim zero based to avoid confusion.  */
    423   dim = (*pdim) - 1;
    424   rank = GFC_DESCRIPTOR_RANK (array) - 1;
    425 
    426   if (unlikely (dim < 0 || dim > rank))
    427     {
    428       runtime_error ("Dim argument incorrect in u_name intrinsic: "
    429  		     "is %ld, should be between 1 and %ld",
    430 		     (long int) dim + 1, (long int) rank + 1);
    431     }
    432 
    433   for (n = 0; n < dim; n++)
    434     {
    435       extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
    436 
    437       if (extent[n] <= 0)
    438 	extent[n] = 0;
    439     }
    440 
    441   for (n = dim; n < rank; n++)
    442     {
    443       extent[n] = GFC_DESCRIPTOR_EXTENT(array,n + 1);
    444 
    445       if (extent[n] <= 0)
    446 	extent[n] = 0;
    447     }
    448 
    449   if (retarray->base_addr == NULL)
    450     {
    451       size_t alloc_size, str;
    452 
    453       for (n = 0; n < rank; n++)
    454 	{
    455 	  if (n == 0)
    456 	    str = 1;
    457 	  else
    458 	    str = GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1];
    459 
    460 	  GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str);
    461 
    462 	}
    463 
    464       retarray->offset = 0;
    465       retarray->dtype.rank = rank;
    466 
    467       alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1];
    468 
    469       if (alloc_size == 0)
    470 	{
    471 	  /* Make sure we have a zero-sized array.  */
    472 	  GFC_DIMENSION_SET(retarray->dim[0], 0, -1, 1);
    473 	  return;
    474 	}
    475       else
    476 	retarray->base_addr = xmallocarray (alloc_size, sizeof (rtype_name));
    477     }
    478   else
    479     {
    480       if (rank != GFC_DESCRIPTOR_RANK (retarray))
    481 	runtime_error ("rank of return array incorrect in"
    482 		       " u_name intrinsic: is %ld, should be %ld",
    483 		       (long int) (GFC_DESCRIPTOR_RANK (retarray)),
    484 		       (long int) rank);
    485 
    486       if (unlikely (compile_options.bounds_check))
    487 	{
    488 	  for (n=0; n < rank; n++)
    489 	    {
    490 	      index_type ret_extent;
    491 
    492 	      ret_extent = GFC_DESCRIPTOR_EXTENT(retarray,n);
    493 	      if (extent[n] != ret_extent)
    494 		runtime_error ("Incorrect extent in return value of"
    495 			       " u_name intrinsic in dimension %ld:"
    496 			       " is %ld, should be %ld", (long int) n + 1,
    497 			       (long int) ret_extent, (long int) extent[n]);
    498 	    }
    499 	}
    500     }
    501 
    502   for (n = 0; n < rank; n++)
    503     {
    504       count[n] = 0;
    505       dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n);
    506     }
    507 
    508   dest = retarray->base_addr;
    509 
    510   while(1)
    511     {
    512       *dest = '$1`;
    513       count[0]++;
    514       dest += dstride[0];
    515       n = 0;
    516       while (count[n] == extent[n])
    517 	{
    518 	  /* When we get to the end of a dimension, reset it and increment
    519 	     the next dimension.  */
    520 	  count[n] = 0;
    521 	  /* We could precalculate these products, but this is a less
    522 	     frequently used path so probably not worth it.  */
    523 	  dest -= dstride[n] * extent[n];
    524 	  n++;
    525 	  if (n >= rank)
    526 	    return;
    527 	  else
    528 	    {
    529 	      count[n]++;
    530 	      dest += dstride[n];
    531 	    }
    532       	}
    533     }
    534 }')dnl
    535 define(ARRAY_FUNCTION,
    536 `START_ARRAY_FUNCTION
    537 $2
    538 START_ARRAY_BLOCK($1)
    539 $3
    540 FINISH_ARRAY_FUNCTION($4)')dnl
    541 define(MASKED_ARRAY_FUNCTION,
    542 `START_MASKED_ARRAY_FUNCTION
    543 $2
    544 START_MASKED_ARRAY_BLOCK
    545 $3
    546 FINISH_MASKED_ARRAY_FUNCTION')dnl
    547