Home | History | Annotate | Line # | Download | only in m4
      1      1.1  mrg `/* Special implementation of the SPREAD intrinsic
      2  1.1.1.3  mrg    Copyright (C) 2008-2022 Free Software Foundation, Inc.
      3      1.1  mrg    Contributed by Thomas Koenig <tkoenig (a] gcc.gnu.org>, based on
      4      1.1  mrg    spread_generic.c written by Paul Brook <paul (a] nowt.org>
      5      1.1  mrg 
      6      1.1  mrg This file is part of the GNU Fortran runtime library (libgfortran).
      7      1.1  mrg 
      8      1.1  mrg Libgfortran is free software; you can redistribute it and/or
      9      1.1  mrg modify it under the terms of the GNU General Public
     10      1.1  mrg License as published by the Free Software Foundation; either
     11      1.1  mrg version 3 of the License, or (at your option) any later version.
     12      1.1  mrg 
     13      1.1  mrg Ligbfortran is distributed in the hope that it will be useful,
     14      1.1  mrg but WITHOUT ANY WARRANTY; without even the implied warranty of
     15      1.1  mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16      1.1  mrg GNU General Public License for more details.
     17      1.1  mrg 
     18      1.1  mrg Under Section 7 of GPL version 3, you are granted additional
     19      1.1  mrg permissions described in the GCC Runtime Library Exception, version
     20      1.1  mrg 3.1, as published by the Free Software Foundation.
     21      1.1  mrg 
     22      1.1  mrg You should have received a copy of the GNU General Public License and
     23      1.1  mrg a copy of the GCC Runtime Library Exception along with this program;
     24      1.1  mrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     25      1.1  mrg <http://www.gnu.org/licenses/>.  */
     26      1.1  mrg 
     27      1.1  mrg #include "libgfortran.h"
     28      1.1  mrg #include <string.h>'
     29      1.1  mrg 
     30      1.1  mrg include(iparm.m4)dnl
     31      1.1  mrg 
     32      1.1  mrg `#if defined (HAVE_'rtype_name`)
     33      1.1  mrg 
     34      1.1  mrg void
     35      1.1  mrg spread_'rtype_code` ('rtype` *ret, const 'rtype` *source,
     36      1.1  mrg 		 const index_type along, const index_type pncopies)
     37      1.1  mrg {
     38      1.1  mrg   /* r.* indicates the return array.  */
     39      1.1  mrg   index_type rstride[GFC_MAX_DIMENSIONS];
     40      1.1  mrg   index_type rstride0;
     41      1.1  mrg   index_type rdelta = 0;
     42      1.1  mrg   index_type rrank;
     43      1.1  mrg   index_type rs;
     44      1.1  mrg   'rtype_name` *rptr;
     45      1.1  mrg   'rtype_name` * restrict dest;
     46      1.1  mrg   /* s.* indicates the source array.  */
     47      1.1  mrg   index_type sstride[GFC_MAX_DIMENSIONS];
     48      1.1  mrg   index_type sstride0;
     49      1.1  mrg   index_type srank;
     50      1.1  mrg   const 'rtype_name` *sptr;
     51      1.1  mrg 
     52      1.1  mrg   index_type count[GFC_MAX_DIMENSIONS];
     53      1.1  mrg   index_type extent[GFC_MAX_DIMENSIONS];
     54      1.1  mrg   index_type n;
     55      1.1  mrg   index_type dim;
     56      1.1  mrg   index_type ncopies;
     57      1.1  mrg 
     58      1.1  mrg   srank = GFC_DESCRIPTOR_RANK(source);
     59      1.1  mrg 
     60      1.1  mrg   rrank = srank + 1;
     61      1.1  mrg   if (rrank > GFC_MAX_DIMENSIONS)
     62      1.1  mrg     runtime_error ("return rank too large in spread()");
     63      1.1  mrg 
     64      1.1  mrg   if (along > rrank)
     65      1.1  mrg       runtime_error ("dim outside of rank in spread()");
     66      1.1  mrg 
     67      1.1  mrg   ncopies = pncopies;
     68      1.1  mrg 
     69      1.1  mrg   if (ret->base_addr == NULL)
     70      1.1  mrg     {
     71      1.1  mrg 
     72      1.1  mrg       size_t ub, stride;
     73      1.1  mrg 
     74      1.1  mrg       /* The front end has signalled that we need to populate the
     75      1.1  mrg 	 return array descriptor.  */
     76      1.1  mrg       ret->dtype.rank = rrank;
     77      1.1  mrg 
     78      1.1  mrg       dim = 0;
     79      1.1  mrg       rs = 1;
     80      1.1  mrg       for (n = 0; n < rrank; n++)
     81      1.1  mrg 	{
     82      1.1  mrg 	  stride = rs;
     83      1.1  mrg 	  if (n == along - 1)
     84      1.1  mrg 	    {
     85      1.1  mrg 	      ub = ncopies - 1;
     86      1.1  mrg 	      rdelta = rs;
     87      1.1  mrg 	      rs *= ncopies;
     88      1.1  mrg 	    }
     89      1.1  mrg 	  else
     90      1.1  mrg 	    {
     91      1.1  mrg 	      count[dim] = 0;
     92      1.1  mrg 	      extent[dim] = GFC_DESCRIPTOR_EXTENT(source,dim);
     93      1.1  mrg 	      sstride[dim] = GFC_DESCRIPTOR_STRIDE(source,dim);
     94      1.1  mrg 	      rstride[dim] = rs;
     95      1.1  mrg 
     96      1.1  mrg 	      ub = extent[dim] - 1;
     97      1.1  mrg 	      rs *= extent[dim];
     98      1.1  mrg 	      dim++;
     99      1.1  mrg 	    }
    100      1.1  mrg 	  GFC_DIMENSION_SET(ret->dim[n], 0, ub, stride);
    101      1.1  mrg 	}
    102      1.1  mrg       ret->offset = 0;
    103      1.1  mrg 
    104      1.1  mrg       /* xmallocarray allocates a single byte for zero size.  */
    105      1.1  mrg       ret->base_addr = xmallocarray (rs, sizeof('rtype_name`));
    106      1.1  mrg       if (rs <= 0)
    107      1.1  mrg         return;
    108      1.1  mrg     }
    109      1.1  mrg   else
    110      1.1  mrg     {
    111      1.1  mrg       int zero_sized;
    112      1.1  mrg 
    113      1.1  mrg       zero_sized = 0;
    114      1.1  mrg 
    115      1.1  mrg       dim = 0;
    116      1.1  mrg       if (GFC_DESCRIPTOR_RANK(ret) != rrank)
    117      1.1  mrg 	runtime_error ("rank mismatch in spread()");
    118      1.1  mrg 
    119      1.1  mrg       if (unlikely (compile_options.bounds_check))
    120      1.1  mrg 	{
    121      1.1  mrg 	  for (n = 0; n < rrank; n++)
    122      1.1  mrg 	    {
    123      1.1  mrg 	      index_type ret_extent;
    124      1.1  mrg 
    125      1.1  mrg 	      ret_extent = GFC_DESCRIPTOR_EXTENT(ret,n);
    126      1.1  mrg 	      if (n == along - 1)
    127      1.1  mrg 		{
    128      1.1  mrg 		  rdelta = GFC_DESCRIPTOR_STRIDE(ret,n);
    129      1.1  mrg 
    130      1.1  mrg 		  if (ret_extent != ncopies)
    131      1.1  mrg 		    runtime_error("Incorrect extent in return value of SPREAD"
    132      1.1  mrg 				  " intrinsic in dimension %ld: is %ld,"
    133      1.1  mrg 				  " should be %ld", (long int) n+1,
    134      1.1  mrg 				  (long int) ret_extent, (long int) ncopies);
    135      1.1  mrg 		}
    136      1.1  mrg 	      else
    137      1.1  mrg 		{
    138      1.1  mrg 		  count[dim] = 0;
    139      1.1  mrg 		  extent[dim] = GFC_DESCRIPTOR_EXTENT(source,dim);
    140      1.1  mrg 		  if (ret_extent != extent[dim])
    141      1.1  mrg 		    runtime_error("Incorrect extent in return value of SPREAD"
    142      1.1  mrg 				  " intrinsic in dimension %ld: is %ld,"
    143      1.1  mrg 				  " should be %ld", (long int) n+1,
    144      1.1  mrg 				  (long int) ret_extent,
    145      1.1  mrg 				  (long int) extent[dim]);
    146      1.1  mrg 		    
    147      1.1  mrg 		  if (extent[dim] <= 0)
    148      1.1  mrg 		    zero_sized = 1;
    149      1.1  mrg 		  sstride[dim] = GFC_DESCRIPTOR_STRIDE(source,dim);
    150      1.1  mrg 		  rstride[dim] = GFC_DESCRIPTOR_STRIDE(ret,n);
    151      1.1  mrg 		  dim++;
    152      1.1  mrg 		}
    153      1.1  mrg 	    }
    154      1.1  mrg 	}
    155      1.1  mrg       else
    156      1.1  mrg 	{
    157      1.1  mrg 	  for (n = 0; n < rrank; n++)
    158      1.1  mrg 	    {
    159      1.1  mrg 	      if (n == along - 1)
    160      1.1  mrg 		{
    161      1.1  mrg 		  rdelta = GFC_DESCRIPTOR_STRIDE(ret,n);
    162      1.1  mrg 		}
    163      1.1  mrg 	      else
    164      1.1  mrg 		{
    165      1.1  mrg 		  count[dim] = 0;
    166      1.1  mrg 		  extent[dim] = GFC_DESCRIPTOR_EXTENT(source,dim);
    167      1.1  mrg 		  if (extent[dim] <= 0)
    168      1.1  mrg 		    zero_sized = 1;
    169      1.1  mrg 		  sstride[dim] = GFC_DESCRIPTOR_STRIDE(source,dim);
    170      1.1  mrg 		  rstride[dim] = GFC_DESCRIPTOR_STRIDE(ret,n);
    171      1.1  mrg 		  dim++;
    172      1.1  mrg 		}
    173      1.1  mrg 	    }
    174      1.1  mrg 	}
    175      1.1  mrg 
    176      1.1  mrg       if (zero_sized)
    177      1.1  mrg 	return;
    178      1.1  mrg 
    179      1.1  mrg       if (sstride[0] == 0)
    180      1.1  mrg 	sstride[0] = 1;
    181      1.1  mrg     }
    182      1.1  mrg   sstride0 = sstride[0];
    183      1.1  mrg   rstride0 = rstride[0];
    184      1.1  mrg   rptr = ret->base_addr;
    185      1.1  mrg   sptr = source->base_addr;
    186      1.1  mrg 
    187      1.1  mrg   while (sptr)
    188      1.1  mrg     {
    189      1.1  mrg       /* Spread this element.  */
    190      1.1  mrg       dest = rptr;
    191      1.1  mrg       for (n = 0; n < ncopies; n++)
    192      1.1  mrg         {
    193      1.1  mrg 	  *dest = *sptr;
    194      1.1  mrg           dest += rdelta;
    195      1.1  mrg         }
    196      1.1  mrg       /* Advance to the next element.  */
    197      1.1  mrg       sptr += sstride0;
    198      1.1  mrg       rptr += rstride0;
    199      1.1  mrg       count[0]++;
    200      1.1  mrg       n = 0;
    201      1.1  mrg       while (count[n] == extent[n])
    202      1.1  mrg         {
    203      1.1  mrg           /* When we get to the end of a dimension, reset it and increment
    204      1.1  mrg              the next dimension.  */
    205      1.1  mrg           count[n] = 0;
    206      1.1  mrg           /* We could precalculate these products, but this is a less
    207      1.1  mrg              frequently used path so probably not worth it.  */
    208      1.1  mrg           sptr -= sstride[n] * extent[n];
    209      1.1  mrg           rptr -= rstride[n] * extent[n];
    210      1.1  mrg           n++;
    211      1.1  mrg           if (n >= srank)
    212      1.1  mrg             {
    213      1.1  mrg               /* Break out of the loop.  */
    214      1.1  mrg               sptr = NULL;
    215      1.1  mrg               break;
    216      1.1  mrg             }
    217      1.1  mrg           else
    218      1.1  mrg             {
    219      1.1  mrg               count[n]++;
    220      1.1  mrg               sptr += sstride[n];
    221      1.1  mrg               rptr += rstride[n];
    222      1.1  mrg             }
    223      1.1  mrg         }
    224      1.1  mrg     }
    225      1.1  mrg }
    226      1.1  mrg 
    227      1.1  mrg /* This version of spread_internal treats the special case of a scalar
    228      1.1  mrg    source.  This is much simpler than the more general case above.  */
    229      1.1  mrg 
    230      1.1  mrg void
    231      1.1  mrg spread_scalar_'rtype_code` ('rtype` *ret, const 'rtype_name` *source,
    232      1.1  mrg 			const index_type along, const index_type ncopies)
    233      1.1  mrg {
    234      1.1  mrg   'rtype_name` * restrict dest;
    235      1.1  mrg   index_type stride;
    236      1.1  mrg 
    237      1.1  mrg   if (GFC_DESCRIPTOR_RANK (ret) != 1)
    238      1.1  mrg     runtime_error ("incorrect destination rank in spread()");
    239      1.1  mrg 
    240      1.1  mrg   if (along > 1)
    241      1.1  mrg     runtime_error ("dim outside of rank in spread()");
    242      1.1  mrg 
    243      1.1  mrg   if (ret->base_addr == NULL)
    244      1.1  mrg     {
    245      1.1  mrg       ret->base_addr = xmallocarray (ncopies, sizeof ('rtype_name`));
    246      1.1  mrg       ret->offset = 0;
    247      1.1  mrg       GFC_DIMENSION_SET(ret->dim[0], 0, ncopies - 1, 1);
    248      1.1  mrg     }
    249      1.1  mrg   else
    250      1.1  mrg     {
    251      1.1  mrg       if (ncopies - 1 > (GFC_DESCRIPTOR_EXTENT(ret,0) - 1)
    252      1.1  mrg 			   / GFC_DESCRIPTOR_STRIDE(ret,0))
    253      1.1  mrg 	runtime_error ("dim too large in spread()");
    254      1.1  mrg     }
    255      1.1  mrg 
    256      1.1  mrg   dest = ret->base_addr;
    257      1.1  mrg   stride = GFC_DESCRIPTOR_STRIDE(ret,0);
    258      1.1  mrg 
    259      1.1  mrg   for (index_type n = 0; n < ncopies; n++)
    260      1.1  mrg     {
    261      1.1  mrg       *dest = *source;
    262      1.1  mrg       dest += stride;
    263      1.1  mrg     }
    264      1.1  mrg }
    265      1.1  mrg 
    266      1.1  mrg #endif
    267      1.1  mrg '
    268