xref: /netbsd-src/external/gpl3/gcc.old/dist/libgfortran/m4/cshift0.m4 (revision 4c3eb207d36f67d31994830c0a694161fc1ca39b)
1627f7eb2Smrg`/* Helper function for cshift functions.
2*4c3eb207Smrg   Copyright (C) 2008-2020 Free Software Foundation, Inc.
3627f7eb2Smrg   Contributed by Thomas Koenig <tkoenig@gcc.gnu.org>
4627f7eb2Smrg
5627f7eb2SmrgThis file is part of the GNU Fortran runtime library (libgfortran).
6627f7eb2Smrg
7627f7eb2SmrgLibgfortran is free software; you can redistribute it and/or
8627f7eb2Smrgmodify it under the terms of the GNU General Public
9627f7eb2SmrgLicense as published by the Free Software Foundation; either
10627f7eb2Smrgversion 3 of the License, or (at your option) any later version.
11627f7eb2Smrg
12627f7eb2SmrgLibgfortran is distributed in the hope that it will be useful,
13627f7eb2Smrgbut WITHOUT ANY WARRANTY; without even the implied warranty of
14627f7eb2SmrgMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15627f7eb2SmrgGNU General Public License for more details.
16627f7eb2Smrg
17627f7eb2SmrgUnder Section 7 of GPL version 3, you are granted additional
18627f7eb2Smrgpermissions described in the GCC Runtime Library Exception, version
19627f7eb2Smrg3.1, as published by the Free Software Foundation.
20627f7eb2Smrg
21627f7eb2SmrgYou should have received a copy of the GNU General Public License and
22627f7eb2Smrga copy of the GCC Runtime Library Exception along with this program;
23627f7eb2Smrgsee the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24627f7eb2Smrg<http://www.gnu.org/licenses/>.  */
25627f7eb2Smrg
26627f7eb2Smrg#include "libgfortran.h"
27627f7eb2Smrg#include <string.h>'
28627f7eb2Smrg
29627f7eb2Smrginclude(iparm.m4)dnl
30627f7eb2Smrg
31627f7eb2Smrg`#if defined (HAVE_'rtype_name`)
32627f7eb2Smrg
33627f7eb2Smrgvoid
34627f7eb2Smrgcshift0_'rtype_code` ('rtype` *ret, const 'rtype` *array, ptrdiff_t shift,
35627f7eb2Smrg		     int which)
36627f7eb2Smrg{
37627f7eb2Smrg  /* r.* indicates the return array.  */
38627f7eb2Smrg  index_type rstride[GFC_MAX_DIMENSIONS];
39627f7eb2Smrg  index_type rstride0;
40627f7eb2Smrg  index_type roffset;
41627f7eb2Smrg  'rtype_name` *rptr;
42627f7eb2Smrg
43627f7eb2Smrg  /* s.* indicates the source array.  */
44627f7eb2Smrg  index_type sstride[GFC_MAX_DIMENSIONS];
45627f7eb2Smrg  index_type sstride0;
46627f7eb2Smrg  index_type soffset;
47627f7eb2Smrg  const 'rtype_name` *sptr;
48627f7eb2Smrg
49627f7eb2Smrg  index_type count[GFC_MAX_DIMENSIONS];
50627f7eb2Smrg  index_type extent[GFC_MAX_DIMENSIONS];
51627f7eb2Smrg  index_type dim;
52627f7eb2Smrg  index_type len;
53627f7eb2Smrg  index_type n;
54627f7eb2Smrg
55627f7eb2Smrg  bool do_blocked;
56627f7eb2Smrg  index_type r_ex, a_ex;
57627f7eb2Smrg
58627f7eb2Smrg  which = which - 1;
59627f7eb2Smrg  sstride[0] = 0;
60627f7eb2Smrg  rstride[0] = 0;
61627f7eb2Smrg
62627f7eb2Smrg  extent[0] = 1;
63627f7eb2Smrg  count[0] = 0;
64627f7eb2Smrg  n = 0;
65627f7eb2Smrg  /* Initialized for avoiding compiler warnings.  */
66627f7eb2Smrg  roffset = 1;
67627f7eb2Smrg  soffset = 1;
68627f7eb2Smrg  len = 0;
69627f7eb2Smrg
70627f7eb2Smrg  r_ex = 1;
71627f7eb2Smrg  a_ex = 1;
72627f7eb2Smrg
73627f7eb2Smrg  if (which > 0)
74627f7eb2Smrg    {
75627f7eb2Smrg      /* Test if both ret and array are contiguous.  */
76627f7eb2Smrg      do_blocked = true;
77627f7eb2Smrg      dim = GFC_DESCRIPTOR_RANK (array);
78627f7eb2Smrg      for (n = 0; n < dim; n ++)
79627f7eb2Smrg	{
80627f7eb2Smrg	  index_type rs, as;
81627f7eb2Smrg	  rs = GFC_DESCRIPTOR_STRIDE (ret, n);
82627f7eb2Smrg	  if (rs != r_ex)
83627f7eb2Smrg	    {
84627f7eb2Smrg	      do_blocked = false;
85627f7eb2Smrg	      break;
86627f7eb2Smrg	    }
87627f7eb2Smrg	  as = GFC_DESCRIPTOR_STRIDE (array, n);
88627f7eb2Smrg	  if (as != a_ex)
89627f7eb2Smrg	    {
90627f7eb2Smrg	      do_blocked = false;
91627f7eb2Smrg	      break;
92627f7eb2Smrg	    }
93627f7eb2Smrg	  r_ex *= GFC_DESCRIPTOR_EXTENT (ret, n);
94627f7eb2Smrg	  a_ex *= GFC_DESCRIPTOR_EXTENT (array, n);
95627f7eb2Smrg	}
96627f7eb2Smrg    }
97627f7eb2Smrg  else
98627f7eb2Smrg    do_blocked = false;
99627f7eb2Smrg
100627f7eb2Smrg  n = 0;
101627f7eb2Smrg
102627f7eb2Smrg  if (do_blocked)
103627f7eb2Smrg    {
104627f7eb2Smrg      /* For contiguous arrays, use the relationship that
105627f7eb2Smrg
106627f7eb2Smrg         dimension(n1,n2,n3) :: a, b
107627f7eb2Smrg	 b = cshift(a,sh,3)
108627f7eb2Smrg
109627f7eb2Smrg         can be dealt with as if
110627f7eb2Smrg
111627f7eb2Smrg	 dimension(n1*n2*n3) :: an, bn
112627f7eb2Smrg	 bn = cshift(a,sh*n1*n2,1)
113627f7eb2Smrg
114627f7eb2Smrg	 we can used a more blocked algorithm for dim>1.  */
115627f7eb2Smrg      sstride[0] = 1;
116627f7eb2Smrg      rstride[0] = 1;
117627f7eb2Smrg      roffset = 1;
118627f7eb2Smrg      soffset = 1;
119627f7eb2Smrg      len = GFC_DESCRIPTOR_STRIDE(array, which)
120627f7eb2Smrg	* GFC_DESCRIPTOR_EXTENT(array, which);
121627f7eb2Smrg      shift *= GFC_DESCRIPTOR_STRIDE(array, which);
122627f7eb2Smrg      for (dim = which + 1; dim < GFC_DESCRIPTOR_RANK (array); dim++)
123627f7eb2Smrg	{
124627f7eb2Smrg	  count[n] = 0;
125627f7eb2Smrg	  extent[n] = GFC_DESCRIPTOR_EXTENT(array,dim);
126627f7eb2Smrg	  rstride[n] = GFC_DESCRIPTOR_STRIDE(ret,dim);
127627f7eb2Smrg	  sstride[n] = GFC_DESCRIPTOR_STRIDE(array,dim);
128627f7eb2Smrg	  n++;
129627f7eb2Smrg	}
130627f7eb2Smrg      dim = GFC_DESCRIPTOR_RANK (array) - which;
131627f7eb2Smrg    }
132627f7eb2Smrg  else
133627f7eb2Smrg    {
134627f7eb2Smrg      for (dim = 0; dim < GFC_DESCRIPTOR_RANK (array); dim++)
135627f7eb2Smrg	{
136627f7eb2Smrg	  if (dim == which)
137627f7eb2Smrg	    {
138627f7eb2Smrg	      roffset = GFC_DESCRIPTOR_STRIDE(ret,dim);
139627f7eb2Smrg	      if (roffset == 0)
140627f7eb2Smrg		roffset = 1;
141627f7eb2Smrg	      soffset = GFC_DESCRIPTOR_STRIDE(array,dim);
142627f7eb2Smrg	      if (soffset == 0)
143627f7eb2Smrg		soffset = 1;
144627f7eb2Smrg	      len = GFC_DESCRIPTOR_EXTENT(array,dim);
145627f7eb2Smrg	    }
146627f7eb2Smrg	  else
147627f7eb2Smrg	    {
148627f7eb2Smrg	      count[n] = 0;
149627f7eb2Smrg	      extent[n] = GFC_DESCRIPTOR_EXTENT(array,dim);
150627f7eb2Smrg	      rstride[n] = GFC_DESCRIPTOR_STRIDE(ret,dim);
151627f7eb2Smrg	      sstride[n] = GFC_DESCRIPTOR_STRIDE(array,dim);
152627f7eb2Smrg	      n++;
153627f7eb2Smrg	    }
154627f7eb2Smrg	}
155627f7eb2Smrg      if (sstride[0] == 0)
156627f7eb2Smrg	sstride[0] = 1;
157627f7eb2Smrg      if (rstride[0] == 0)
158627f7eb2Smrg	rstride[0] = 1;
159627f7eb2Smrg
160627f7eb2Smrg      dim = GFC_DESCRIPTOR_RANK (array);
161627f7eb2Smrg    }
162627f7eb2Smrg
163627f7eb2Smrg  rstride0 = rstride[0];
164627f7eb2Smrg  sstride0 = sstride[0];
165627f7eb2Smrg  rptr = ret->base_addr;
166627f7eb2Smrg  sptr = array->base_addr;
167627f7eb2Smrg
168627f7eb2Smrg  /* Avoid the costly modulo for trivially in-bound shifts.  */
169627f7eb2Smrg  if (shift < 0 || shift >= len)
170627f7eb2Smrg    {
171627f7eb2Smrg      shift = len == 0 ? 0 : shift % (ptrdiff_t)len;
172627f7eb2Smrg      if (shift < 0)
173627f7eb2Smrg	shift += len;
174627f7eb2Smrg    }
175627f7eb2Smrg
176627f7eb2Smrg  while (rptr)
177627f7eb2Smrg    {
178627f7eb2Smrg      /* Do the shift for this dimension.  */
179627f7eb2Smrg
180627f7eb2Smrg      /* If elements are contiguous, perform the operation
181627f7eb2Smrg	 in two block moves.  */
182627f7eb2Smrg      if (soffset == 1 && roffset == 1)
183627f7eb2Smrg	{
184627f7eb2Smrg	  size_t len1 = shift * sizeof ('rtype_name`);
185627f7eb2Smrg	  size_t len2 = (len - shift) * sizeof ('rtype_name`);
186627f7eb2Smrg	  memcpy (rptr, sptr + shift, len2);
187627f7eb2Smrg	  memcpy (rptr + (len - shift), sptr, len1);
188627f7eb2Smrg	}
189627f7eb2Smrg      else
190627f7eb2Smrg	{
191627f7eb2Smrg	  /* Otherwise, we will have to perform the copy one element at
192627f7eb2Smrg	     a time.  */
193627f7eb2Smrg	  'rtype_name` *dest = rptr;
194627f7eb2Smrg	  const 'rtype_name` *src = &sptr[shift * soffset];
195627f7eb2Smrg
196627f7eb2Smrg	  for (n = 0; n < len - shift; n++)
197627f7eb2Smrg	    {
198627f7eb2Smrg	      *dest = *src;
199627f7eb2Smrg	      dest += roffset;
200627f7eb2Smrg	      src += soffset;
201627f7eb2Smrg	    }
202627f7eb2Smrg	  for (src = sptr, n = 0; n < shift; n++)
203627f7eb2Smrg	    {
204627f7eb2Smrg	      *dest = *src;
205627f7eb2Smrg	      dest += roffset;
206627f7eb2Smrg	      src += soffset;
207627f7eb2Smrg	    }
208627f7eb2Smrg	}
209627f7eb2Smrg
210627f7eb2Smrg      /* Advance to the next section.  */
211627f7eb2Smrg      rptr += rstride0;
212627f7eb2Smrg      sptr += sstride0;
213627f7eb2Smrg      count[0]++;
214627f7eb2Smrg      n = 0;
215627f7eb2Smrg      while (count[n] == extent[n])
216627f7eb2Smrg        {
217627f7eb2Smrg          /* When we get to the end of a dimension, reset it and increment
218627f7eb2Smrg             the next dimension.  */
219627f7eb2Smrg          count[n] = 0;
220627f7eb2Smrg          /* We could precalculate these products, but this is a less
221627f7eb2Smrg             frequently used path so probably not worth it.  */
222627f7eb2Smrg          rptr -= rstride[n] * extent[n];
223627f7eb2Smrg          sptr -= sstride[n] * extent[n];
224627f7eb2Smrg          n++;
225627f7eb2Smrg          if (n >= dim - 1)
226627f7eb2Smrg            {
227627f7eb2Smrg              /* Break out of the loop.  */
228627f7eb2Smrg              rptr = NULL;
229627f7eb2Smrg              break;
230627f7eb2Smrg            }
231627f7eb2Smrg          else
232627f7eb2Smrg            {
233627f7eb2Smrg              count[n]++;
234627f7eb2Smrg              rptr += rstride[n];
235627f7eb2Smrg              sptr += sstride[n];
236627f7eb2Smrg            }
237627f7eb2Smrg        }
238627f7eb2Smrg    }
239627f7eb2Smrg
240627f7eb2Smrg  return;
241627f7eb2Smrg}
242627f7eb2Smrg
243627f7eb2Smrg#endif'
244