Home | History | Annotate | Line # | Download | only in m4
      1 `/* Helper function for cshift functions.
      2    Copyright (C) 2008-2024 Free Software Foundation, Inc.
      3    Contributed by Thomas Koenig <tkoenig (a] gcc.gnu.org>
      4 
      5 This file is part of the GNU Fortran runtime library (libgfortran).
      6 
      7 Libgfortran is free software; you can redistribute it and/or
      8 modify it under the terms of the GNU General Public
      9 License as published by the Free Software Foundation; either
     10 version 3 of the License, or (at your option) any later version.
     11 
     12 Libgfortran is distributed in the hope that it will be useful,
     13 but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 Under Section 7 of GPL version 3, you are granted additional
     18 permissions described in the GCC Runtime Library Exception, version
     19 3.1, as published by the Free Software Foundation.
     20 
     21 You should have received a copy of the GNU General Public License and
     22 a copy of the GCC Runtime Library Exception along with this program;
     23 see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     24 <http://www.gnu.org/licenses/>.  */
     25 
     26 #include "libgfortran.h"
     27 #include <string.h>'
     28 
     29 include(iparm.m4)dnl
     30 
     31 `#if defined (HAVE_'rtype_name`)
     32 
     33 void
     34 cshift0_'rtype_code` ('rtype` *ret, const 'rtype` *array, ptrdiff_t shift,
     35 		     int which)
     36 {
     37   /* r.* indicates the return array.  */
     38   index_type rstride[GFC_MAX_DIMENSIONS];
     39   index_type rstride0;
     40   index_type roffset;
     41   'rtype_name` *rptr;
     42 
     43   /* s.* indicates the source array.  */
     44   index_type sstride[GFC_MAX_DIMENSIONS];
     45   index_type sstride0;
     46   index_type soffset;
     47   const 'rtype_name` *sptr;
     48 
     49   index_type count[GFC_MAX_DIMENSIONS];
     50   index_type extent[GFC_MAX_DIMENSIONS];
     51   index_type dim;
     52   index_type len;
     53   index_type n;
     54 
     55   bool do_blocked;
     56   index_type r_ex, a_ex;
     57 
     58   which = which - 1;
     59   sstride[0] = 0;
     60   rstride[0] = 0;
     61 
     62   extent[0] = 1;
     63   count[0] = 0;
     64   n = 0;
     65   /* Initialized for avoiding compiler warnings.  */
     66   roffset = 1;
     67   soffset = 1;
     68   len = 0;
     69 
     70   r_ex = 1;
     71   a_ex = 1;
     72 
     73   if (which > 0)
     74     {
     75       /* Test if both ret and array are contiguous.  */
     76       do_blocked = true;
     77       dim = GFC_DESCRIPTOR_RANK (array);
     78       for (n = 0; n < dim; n ++)
     79 	{
     80 	  index_type rs, as;
     81 	  rs = GFC_DESCRIPTOR_STRIDE (ret, n);
     82 	  if (rs != r_ex)
     83 	    {
     84 	      do_blocked = false;
     85 	      break;
     86 	    }
     87 	  as = GFC_DESCRIPTOR_STRIDE (array, n);
     88 	  if (as != a_ex)
     89 	    {
     90 	      do_blocked = false;
     91 	      break;
     92 	    }
     93 	  r_ex *= GFC_DESCRIPTOR_EXTENT (ret, n);
     94 	  a_ex *= GFC_DESCRIPTOR_EXTENT (array, n);
     95 	}
     96     }
     97   else
     98     do_blocked = false;
     99 
    100   n = 0;
    101 
    102   if (do_blocked)
    103     {
    104       /* For contiguous arrays, use the relationship that
    105 
    106          dimension(n1,n2,n3) :: a, b
    107 	 b = cshift(a,sh,3)
    108 
    109          can be dealt with as if
    110 
    111 	 dimension(n1*n2*n3) :: an, bn
    112 	 bn = cshift(a,sh*n1*n2,1)
    113 
    114 	 we can used a more blocked algorithm for dim>1.  */
    115       sstride[0] = 1;
    116       rstride[0] = 1;
    117       roffset = 1;
    118       soffset = 1;
    119       len = GFC_DESCRIPTOR_STRIDE(array, which)
    120 	* GFC_DESCRIPTOR_EXTENT(array, which);      
    121       shift *= GFC_DESCRIPTOR_STRIDE(array, which);
    122       for (dim = which + 1; dim < GFC_DESCRIPTOR_RANK (array); dim++)
    123 	{
    124 	  count[n] = 0;
    125 	  extent[n] = GFC_DESCRIPTOR_EXTENT(array,dim);
    126 	  rstride[n] = GFC_DESCRIPTOR_STRIDE(ret,dim);
    127 	  sstride[n] = GFC_DESCRIPTOR_STRIDE(array,dim);
    128 	  n++;
    129 	}
    130       dim = GFC_DESCRIPTOR_RANK (array) - which;
    131     }
    132   else
    133     {
    134       for (dim = 0; dim < GFC_DESCRIPTOR_RANK (array); dim++)
    135 	{
    136 	  if (dim == which)
    137 	    {
    138 	      roffset = GFC_DESCRIPTOR_STRIDE(ret,dim);
    139 	      if (roffset == 0)
    140 		roffset = 1;
    141 	      soffset = GFC_DESCRIPTOR_STRIDE(array,dim);
    142 	      if (soffset == 0)
    143 		soffset = 1;
    144 	      len = GFC_DESCRIPTOR_EXTENT(array,dim);
    145 	    }
    146 	  else
    147 	    {
    148 	      count[n] = 0;
    149 	      extent[n] = GFC_DESCRIPTOR_EXTENT(array,dim);
    150 	      rstride[n] = GFC_DESCRIPTOR_STRIDE(ret,dim);
    151 	      sstride[n] = GFC_DESCRIPTOR_STRIDE(array,dim);
    152 	      n++;
    153 	    }
    154 	}
    155       if (sstride[0] == 0)
    156 	sstride[0] = 1;
    157       if (rstride[0] == 0)
    158 	rstride[0] = 1;
    159 
    160       dim = GFC_DESCRIPTOR_RANK (array);
    161     }
    162 
    163   rstride0 = rstride[0];
    164   sstride0 = sstride[0];
    165   rptr = ret->base_addr;
    166   sptr = array->base_addr;
    167 
    168   /* Avoid the costly modulo for trivially in-bound shifts.  */
    169   if (shift < 0 || shift >= len)
    170     {
    171       shift = len == 0 ? 0 : shift % (ptrdiff_t)len;
    172       if (shift < 0)
    173 	shift += len;
    174     }
    175 
    176   while (rptr)
    177     {
    178       /* Do the shift for this dimension.  */
    179 
    180       /* If elements are contiguous, perform the operation
    181 	 in two block moves.  */
    182       if (soffset == 1 && roffset == 1)
    183 	{
    184 	  size_t len1 = shift * sizeof ('rtype_name`);
    185 	  size_t len2 = (len - shift) * sizeof ('rtype_name`);
    186 	  memcpy (rptr, sptr + shift, len2);
    187 	  memcpy (rptr + (len - shift), sptr, len1);
    188 	}
    189       else
    190 	{
    191 	  /* Otherwise, we will have to perform the copy one element at
    192 	     a time.  */
    193 	  'rtype_name` *dest = rptr;
    194 	  const 'rtype_name` *src = &sptr[shift * soffset];
    195 
    196 	  for (n = 0; n < len - shift; n++)
    197 	    {
    198 	      *dest = *src;
    199 	      dest += roffset;
    200 	      src += soffset;
    201 	    }
    202 	  for (src = sptr, n = 0; n < shift; n++)
    203 	    {
    204 	      *dest = *src;
    205 	      dest += roffset;
    206 	      src += soffset;
    207 	    }
    208 	}
    209 
    210       /* Advance to the next section.  */
    211       rptr += rstride0;
    212       sptr += sstride0;
    213       count[0]++;
    214       n = 0;
    215       while (count[n] == extent[n])
    216         {
    217           /* When we get to the end of a dimension, reset it and increment
    218              the next dimension.  */
    219           count[n] = 0;
    220           /* We could precalculate these products, but this is a less
    221              frequently used path so probably not worth it.  */
    222           rptr -= rstride[n] * extent[n];
    223           sptr -= sstride[n] * extent[n];
    224           n++;
    225           if (n >= dim - 1)
    226             {
    227               /* Break out of the loop.  */
    228               rptr = NULL;
    229               break;
    230             }
    231           else
    232             {
    233               count[n]++;
    234               rptr += rstride[n];
    235               sptr += sstride[n];
    236             }
    237         }
    238     }
    239 
    240   return;
    241 }
    242 
    243 #endif'
    244