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