xref: /netbsd-src/external/gpl3/gcc/dist/libgfortran/generated/cshift0_i2.c (revision b1e838363e3c6fc78a55519254d99869742dd33c)
1181254a7Smrg /* Helper function for cshift functions.
2*b1e83836Smrg    Copyright (C) 2008-2022 Free Software Foundation, Inc.
3181254a7Smrg    Contributed by Thomas Koenig <tkoenig@gcc.gnu.org>
4181254a7Smrg 
5181254a7Smrg This file is part of the GNU Fortran runtime library (libgfortran).
6181254a7Smrg 
7181254a7Smrg Libgfortran is free software; you can redistribute it and/or
8181254a7Smrg modify it under the terms of the GNU General Public
9181254a7Smrg License as published by the Free Software Foundation; either
10181254a7Smrg version 3 of the License, or (at your option) any later version.
11181254a7Smrg 
12181254a7Smrg Libgfortran is distributed in the hope that it will be useful,
13181254a7Smrg but WITHOUT ANY WARRANTY; without even the implied warranty of
14181254a7Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15181254a7Smrg GNU General Public License for more details.
16181254a7Smrg 
17181254a7Smrg Under Section 7 of GPL version 3, you are granted additional
18181254a7Smrg permissions described in the GCC Runtime Library Exception, version
19181254a7Smrg 3.1, as published by the Free Software Foundation.
20181254a7Smrg 
21181254a7Smrg You should have received a copy of the GNU General Public License and
22181254a7Smrg a copy of the GCC Runtime Library Exception along with this program;
23181254a7Smrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24181254a7Smrg <http://www.gnu.org/licenses/>.  */
25181254a7Smrg 
26181254a7Smrg #include "libgfortran.h"
27181254a7Smrg #include <string.h>
28181254a7Smrg 
29181254a7Smrg 
30181254a7Smrg #if defined (HAVE_GFC_INTEGER_2)
31181254a7Smrg 
32181254a7Smrg void
cshift0_i2(gfc_array_i2 * ret,const gfc_array_i2 * array,ptrdiff_t shift,int which)33181254a7Smrg cshift0_i2 (gfc_array_i2 *ret, const gfc_array_i2 *array, ptrdiff_t shift,
34181254a7Smrg 		     int which)
35181254a7Smrg {
36181254a7Smrg   /* r.* indicates the return array.  */
37181254a7Smrg   index_type rstride[GFC_MAX_DIMENSIONS];
38181254a7Smrg   index_type rstride0;
39181254a7Smrg   index_type roffset;
40181254a7Smrg   GFC_INTEGER_2 *rptr;
41181254a7Smrg 
42181254a7Smrg   /* s.* indicates the source array.  */
43181254a7Smrg   index_type sstride[GFC_MAX_DIMENSIONS];
44181254a7Smrg   index_type sstride0;
45181254a7Smrg   index_type soffset;
46181254a7Smrg   const GFC_INTEGER_2 *sptr;
47181254a7Smrg 
48181254a7Smrg   index_type count[GFC_MAX_DIMENSIONS];
49181254a7Smrg   index_type extent[GFC_MAX_DIMENSIONS];
50181254a7Smrg   index_type dim;
51181254a7Smrg   index_type len;
52181254a7Smrg   index_type n;
53181254a7Smrg 
54181254a7Smrg   bool do_blocked;
55181254a7Smrg   index_type r_ex, a_ex;
56181254a7Smrg 
57181254a7Smrg   which = which - 1;
58181254a7Smrg   sstride[0] = 0;
59181254a7Smrg   rstride[0] = 0;
60181254a7Smrg 
61181254a7Smrg   extent[0] = 1;
62181254a7Smrg   count[0] = 0;
63181254a7Smrg   n = 0;
64181254a7Smrg   /* Initialized for avoiding compiler warnings.  */
65181254a7Smrg   roffset = 1;
66181254a7Smrg   soffset = 1;
67181254a7Smrg   len = 0;
68181254a7Smrg 
69181254a7Smrg   r_ex = 1;
70181254a7Smrg   a_ex = 1;
71181254a7Smrg 
72181254a7Smrg   if (which > 0)
73181254a7Smrg     {
74181254a7Smrg       /* Test if both ret and array are contiguous.  */
75181254a7Smrg       do_blocked = true;
76181254a7Smrg       dim = GFC_DESCRIPTOR_RANK (array);
77181254a7Smrg       for (n = 0; n < dim; n ++)
78181254a7Smrg 	{
79181254a7Smrg 	  index_type rs, as;
80181254a7Smrg 	  rs = GFC_DESCRIPTOR_STRIDE (ret, n);
81181254a7Smrg 	  if (rs != r_ex)
82181254a7Smrg 	    {
83181254a7Smrg 	      do_blocked = false;
84181254a7Smrg 	      break;
85181254a7Smrg 	    }
86181254a7Smrg 	  as = GFC_DESCRIPTOR_STRIDE (array, n);
87181254a7Smrg 	  if (as != a_ex)
88181254a7Smrg 	    {
89181254a7Smrg 	      do_blocked = false;
90181254a7Smrg 	      break;
91181254a7Smrg 	    }
92181254a7Smrg 	  r_ex *= GFC_DESCRIPTOR_EXTENT (ret, n);
93181254a7Smrg 	  a_ex *= GFC_DESCRIPTOR_EXTENT (array, n);
94181254a7Smrg 	}
95181254a7Smrg     }
96181254a7Smrg   else
97181254a7Smrg     do_blocked = false;
98181254a7Smrg 
99181254a7Smrg   n = 0;
100181254a7Smrg 
101181254a7Smrg   if (do_blocked)
102181254a7Smrg     {
103181254a7Smrg       /* For contiguous arrays, use the relationship that
104181254a7Smrg 
105181254a7Smrg          dimension(n1,n2,n3) :: a, b
106181254a7Smrg 	 b = cshift(a,sh,3)
107181254a7Smrg 
108181254a7Smrg          can be dealt with as if
109181254a7Smrg 
110181254a7Smrg 	 dimension(n1*n2*n3) :: an, bn
111181254a7Smrg 	 bn = cshift(a,sh*n1*n2,1)
112181254a7Smrg 
113181254a7Smrg 	 we can used a more blocked algorithm for dim>1.  */
114181254a7Smrg       sstride[0] = 1;
115181254a7Smrg       rstride[0] = 1;
116181254a7Smrg       roffset = 1;
117181254a7Smrg       soffset = 1;
118181254a7Smrg       len = GFC_DESCRIPTOR_STRIDE(array, which)
119181254a7Smrg 	* GFC_DESCRIPTOR_EXTENT(array, which);
120181254a7Smrg       shift *= GFC_DESCRIPTOR_STRIDE(array, which);
121181254a7Smrg       for (dim = which + 1; dim < GFC_DESCRIPTOR_RANK (array); dim++)
122181254a7Smrg 	{
123181254a7Smrg 	  count[n] = 0;
124181254a7Smrg 	  extent[n] = GFC_DESCRIPTOR_EXTENT(array,dim);
125181254a7Smrg 	  rstride[n] = GFC_DESCRIPTOR_STRIDE(ret,dim);
126181254a7Smrg 	  sstride[n] = GFC_DESCRIPTOR_STRIDE(array,dim);
127181254a7Smrg 	  n++;
128181254a7Smrg 	}
129181254a7Smrg       dim = GFC_DESCRIPTOR_RANK (array) - which;
130181254a7Smrg     }
131181254a7Smrg   else
132181254a7Smrg     {
133181254a7Smrg       for (dim = 0; dim < GFC_DESCRIPTOR_RANK (array); dim++)
134181254a7Smrg 	{
135181254a7Smrg 	  if (dim == which)
136181254a7Smrg 	    {
137181254a7Smrg 	      roffset = GFC_DESCRIPTOR_STRIDE(ret,dim);
138181254a7Smrg 	      if (roffset == 0)
139181254a7Smrg 		roffset = 1;
140181254a7Smrg 	      soffset = GFC_DESCRIPTOR_STRIDE(array,dim);
141181254a7Smrg 	      if (soffset == 0)
142181254a7Smrg 		soffset = 1;
143181254a7Smrg 	      len = GFC_DESCRIPTOR_EXTENT(array,dim);
144181254a7Smrg 	    }
145181254a7Smrg 	  else
146181254a7Smrg 	    {
147181254a7Smrg 	      count[n] = 0;
148181254a7Smrg 	      extent[n] = GFC_DESCRIPTOR_EXTENT(array,dim);
149181254a7Smrg 	      rstride[n] = GFC_DESCRIPTOR_STRIDE(ret,dim);
150181254a7Smrg 	      sstride[n] = GFC_DESCRIPTOR_STRIDE(array,dim);
151181254a7Smrg 	      n++;
152181254a7Smrg 	    }
153181254a7Smrg 	}
154181254a7Smrg       if (sstride[0] == 0)
155181254a7Smrg 	sstride[0] = 1;
156181254a7Smrg       if (rstride[0] == 0)
157181254a7Smrg 	rstride[0] = 1;
158181254a7Smrg 
159181254a7Smrg       dim = GFC_DESCRIPTOR_RANK (array);
160181254a7Smrg     }
161181254a7Smrg 
162181254a7Smrg   rstride0 = rstride[0];
163181254a7Smrg   sstride0 = sstride[0];
164181254a7Smrg   rptr = ret->base_addr;
165181254a7Smrg   sptr = array->base_addr;
166181254a7Smrg 
167181254a7Smrg   /* Avoid the costly modulo for trivially in-bound shifts.  */
168181254a7Smrg   if (shift < 0 || shift >= len)
169181254a7Smrg     {
170181254a7Smrg       shift = len == 0 ? 0 : shift % (ptrdiff_t)len;
171181254a7Smrg       if (shift < 0)
172181254a7Smrg 	shift += len;
173181254a7Smrg     }
174181254a7Smrg 
175181254a7Smrg   while (rptr)
176181254a7Smrg     {
177181254a7Smrg       /* Do the shift for this dimension.  */
178181254a7Smrg 
179181254a7Smrg       /* If elements are contiguous, perform the operation
180181254a7Smrg 	 in two block moves.  */
181181254a7Smrg       if (soffset == 1 && roffset == 1)
182181254a7Smrg 	{
183181254a7Smrg 	  size_t len1 = shift * sizeof (GFC_INTEGER_2);
184181254a7Smrg 	  size_t len2 = (len - shift) * sizeof (GFC_INTEGER_2);
185181254a7Smrg 	  memcpy (rptr, sptr + shift, len2);
186181254a7Smrg 	  memcpy (rptr + (len - shift), sptr, len1);
187181254a7Smrg 	}
188181254a7Smrg       else
189181254a7Smrg 	{
190181254a7Smrg 	  /* Otherwise, we will have to perform the copy one element at
191181254a7Smrg 	     a time.  */
192181254a7Smrg 	  GFC_INTEGER_2 *dest = rptr;
193181254a7Smrg 	  const GFC_INTEGER_2 *src = &sptr[shift * soffset];
194181254a7Smrg 
195181254a7Smrg 	  for (n = 0; n < len - shift; n++)
196181254a7Smrg 	    {
197181254a7Smrg 	      *dest = *src;
198181254a7Smrg 	      dest += roffset;
199181254a7Smrg 	      src += soffset;
200181254a7Smrg 	    }
201181254a7Smrg 	  for (src = sptr, n = 0; n < shift; n++)
202181254a7Smrg 	    {
203181254a7Smrg 	      *dest = *src;
204181254a7Smrg 	      dest += roffset;
205181254a7Smrg 	      src += soffset;
206181254a7Smrg 	    }
207181254a7Smrg 	}
208181254a7Smrg 
209181254a7Smrg       /* Advance to the next section.  */
210181254a7Smrg       rptr += rstride0;
211181254a7Smrg       sptr += sstride0;
212181254a7Smrg       count[0]++;
213181254a7Smrg       n = 0;
214181254a7Smrg       while (count[n] == extent[n])
215181254a7Smrg         {
216181254a7Smrg           /* When we get to the end of a dimension, reset it and increment
217181254a7Smrg              the next dimension.  */
218181254a7Smrg           count[n] = 0;
219181254a7Smrg           /* We could precalculate these products, but this is a less
220181254a7Smrg              frequently used path so probably not worth it.  */
221181254a7Smrg           rptr -= rstride[n] * extent[n];
222181254a7Smrg           sptr -= sstride[n] * extent[n];
223181254a7Smrg           n++;
224181254a7Smrg           if (n >= dim - 1)
225181254a7Smrg             {
226181254a7Smrg               /* Break out of the loop.  */
227181254a7Smrg               rptr = NULL;
228181254a7Smrg               break;
229181254a7Smrg             }
230181254a7Smrg           else
231181254a7Smrg             {
232181254a7Smrg               count[n]++;
233181254a7Smrg               rptr += rstride[n];
234181254a7Smrg               sptr += sstride[n];
235181254a7Smrg             }
236181254a7Smrg         }
237181254a7Smrg     }
238181254a7Smrg 
239181254a7Smrg   return;
240181254a7Smrg }
241181254a7Smrg 
242181254a7Smrg #endif
243