1760c2415Smrg`/* Implementation of the CSHIFT intrinsic
2*0bfacb9bSmrg   Copyright (C) 2003-2020 Free Software Foundation, Inc.
3760c2415Smrg   Contributed by Feng Wang <wf_cs@yahoo.com>
4760c2415Smrg
5760c2415SmrgThis file is part of the GNU Fortran runtime library (libgfortran).
6760c2415Smrg
7760c2415SmrgLibgfortran is free software; you can redistribute it and/or
8760c2415Smrgmodify it under the terms of the GNU General Public
9760c2415SmrgLicense as published by the Free Software Foundation; either
10760c2415Smrgversion 3 of the License, or (at your option) any later version.
11760c2415Smrg
12760c2415SmrgLigbfortran is distributed in the hope that it will be useful,
13760c2415Smrgbut WITHOUT ANY WARRANTY; without even the implied warranty of
14760c2415SmrgMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15760c2415SmrgGNU General Public License for more details.
16760c2415Smrg
17760c2415SmrgUnder Section 7 of GPL version 3, you are granted additional
18760c2415Smrgpermissions described in the GCC Runtime Library Exception, version
19760c2415Smrg3.1, as published by the Free Software Foundation.
20760c2415Smrg
21760c2415SmrgYou should have received a copy of the GNU General Public License and
22760c2415Smrga copy of the GCC Runtime Library Exception along with this program;
23760c2415Smrgsee the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24760c2415Smrg<http://www.gnu.org/licenses/>.  */
25760c2415Smrg
26760c2415Smrg#include "libgfortran.h"
27760c2415Smrg#include <string.h>'
28760c2415Smrg
29760c2415Smrginclude(iparm.m4)dnl
30760c2415Smrg
31760c2415Smrg`#if defined (HAVE_'atype_name`)
32760c2415Smrg
33760c2415Smrgstatic void
34760c2415Smrgcshift1 (gfc_array_char * const restrict ret,
35760c2415Smrg	const gfc_array_char * const restrict array,
36760c2415Smrg	const 'atype` * const restrict h,
37760c2415Smrg	const 'atype_name` * const restrict pwhich)
38760c2415Smrg{
39760c2415Smrg  /* r.* indicates the return array.  */
40760c2415Smrg  index_type rstride[GFC_MAX_DIMENSIONS];
41760c2415Smrg  index_type rstride0;
42760c2415Smrg  index_type roffset;
43760c2415Smrg  char *rptr;
44760c2415Smrg  char *dest;
45760c2415Smrg  /* s.* indicates the source array.  */
46760c2415Smrg  index_type sstride[GFC_MAX_DIMENSIONS];
47760c2415Smrg  index_type sstride0;
48760c2415Smrg  index_type soffset;
49760c2415Smrg  const char *sptr;
50760c2415Smrg  const char *src;
51760c2415Smrg  /* h.* indicates the shift array.  */
52760c2415Smrg  index_type hstride[GFC_MAX_DIMENSIONS];
53760c2415Smrg  index_type hstride0;
54760c2415Smrg  const 'atype_name` *hptr;
55760c2415Smrg
56760c2415Smrg  index_type count[GFC_MAX_DIMENSIONS];
57760c2415Smrg  index_type extent[GFC_MAX_DIMENSIONS];
58760c2415Smrg  index_type dim;
59760c2415Smrg  index_type len;
60760c2415Smrg  index_type n;
61760c2415Smrg  int which;
62760c2415Smrg  'atype_name` sh;
63760c2415Smrg  index_type arraysize;
64760c2415Smrg  index_type size;
65760c2415Smrg  index_type type_size;
66760c2415Smrg
67760c2415Smrg  if (pwhich)
68760c2415Smrg    which = *pwhich - 1;
69760c2415Smrg  else
70760c2415Smrg    which = 0;
71760c2415Smrg
72760c2415Smrg  if (which < 0 || (which + 1) > GFC_DESCRIPTOR_RANK (array))
73760c2415Smrg    runtime_error ("Argument ''`DIM''` is out of range in call to ''`CSHIFT''`");
74760c2415Smrg
75760c2415Smrg  size = GFC_DESCRIPTOR_SIZE(array);
76760c2415Smrg
77760c2415Smrg  arraysize = size0 ((array_t *)array);
78760c2415Smrg
79760c2415Smrg  if (ret->base_addr == NULL)
80760c2415Smrg    {
81760c2415Smrg      ret->base_addr = xmallocarray (arraysize, size);
82760c2415Smrg      ret->offset = 0;
83760c2415Smrg      GFC_DTYPE_COPY(ret,array);
84760c2415Smrg      for (index_type i = 0; i < GFC_DESCRIPTOR_RANK (array); i++)
85760c2415Smrg        {
86760c2415Smrg	  index_type ub, str;
87760c2415Smrg
88760c2415Smrg          ub = GFC_DESCRIPTOR_EXTENT(array,i) - 1;
89760c2415Smrg
90760c2415Smrg          if (i == 0)
91760c2415Smrg            str = 1;
92760c2415Smrg          else
93760c2415Smrg	    str = GFC_DESCRIPTOR_EXTENT(ret,i-1) *
94760c2415Smrg	      GFC_DESCRIPTOR_STRIDE(ret,i-1);
95760c2415Smrg
96760c2415Smrg	  GFC_DIMENSION_SET(ret->dim[i], 0, ub, str);
97760c2415Smrg        }
98760c2415Smrg    }
99760c2415Smrg  else if (unlikely (compile_options.bounds_check))
100760c2415Smrg    {
101760c2415Smrg      bounds_equal_extents ((array_t *) ret, (array_t *) array,
102760c2415Smrg				 "return value", "CSHIFT");
103760c2415Smrg    }
104760c2415Smrg
105760c2415Smrg  if (unlikely (compile_options.bounds_check))
106760c2415Smrg    {
107760c2415Smrg      bounds_reduced_extents ((array_t *) h, (array_t *) array, which,
108760c2415Smrg      			      "SHIFT argument", "CSHIFT");
109760c2415Smrg    }
110760c2415Smrg
111760c2415Smrg  if (arraysize == 0)
112760c2415Smrg    return;
113760c2415Smrg
114760c2415Smrg  /* See if we should dispatch to a helper function.  */
115760c2415Smrg
116760c2415Smrg  type_size = GFC_DTYPE_TYPE_SIZE (array);
117760c2415Smrg
118760c2415Smrg  switch (type_size)
119760c2415Smrg  {
120760c2415Smrg    case GFC_DTYPE_LOGICAL_1:
121760c2415Smrg    case GFC_DTYPE_INTEGER_1:
122760c2415Smrg      cshift1_'atype_kind`_i1 ((gfc_array_i1 *)ret, (gfc_array_i1 *) array,
123760c2415Smrg      			h, pwhich);
124760c2415Smrg      return;
125760c2415Smrg
126760c2415Smrg    case GFC_DTYPE_LOGICAL_2:
127760c2415Smrg    case GFC_DTYPE_INTEGER_2:
128760c2415Smrg      cshift1_'atype_kind`_i2 ((gfc_array_i2 *)ret, (gfc_array_i2 *) array,
129760c2415Smrg      			h, pwhich);
130760c2415Smrg      return;
131760c2415Smrg
132760c2415Smrg    case GFC_DTYPE_LOGICAL_4:
133760c2415Smrg    case GFC_DTYPE_INTEGER_4:
134760c2415Smrg      cshift1_'atype_kind`_i4 ((gfc_array_i4 *)ret, (gfc_array_i4 *) array,
135760c2415Smrg      			h, pwhich);
136760c2415Smrg      return;
137760c2415Smrg
138760c2415Smrg    case GFC_DTYPE_LOGICAL_8:
139760c2415Smrg    case GFC_DTYPE_INTEGER_8:
140760c2415Smrg      cshift1_'atype_kind`_i8 ((gfc_array_i8 *)ret, (gfc_array_i8 *) array,
141760c2415Smrg      			h, pwhich);
142760c2415Smrg      return;
143760c2415Smrg
144760c2415Smrg#if defined (HAVE_INTEGER_16)
145760c2415Smrg    case GFC_DTYPE_LOGICAL_16:
146760c2415Smrg    case GFC_DTYPE_INTEGER_16:
147760c2415Smrg      cshift1_'atype_kind`_i16 ((gfc_array_i16 *)ret, (gfc_array_i16 *) array,
148760c2415Smrg      			h, pwhich);
149760c2415Smrg      return;
150760c2415Smrg#endif
151760c2415Smrg
152760c2415Smrg    case GFC_DTYPE_REAL_4:
153760c2415Smrg      cshift1_'atype_kind`_r4 ((gfc_array_r4 *)ret, (gfc_array_r4 *) array,
154760c2415Smrg      			h, pwhich);
155760c2415Smrg      return;
156760c2415Smrg
157760c2415Smrg    case GFC_DTYPE_REAL_8:
158760c2415Smrg      cshift1_'atype_kind`_r8 ((gfc_array_r8 *)ret, (gfc_array_r8 *) array,
159760c2415Smrg      			h, pwhich);
160760c2415Smrg      return;
161760c2415Smrg
162760c2415Smrg#if defined (HAVE_REAL_10)
163760c2415Smrg    case GFC_DTYPE_REAL_10:
164760c2415Smrg      cshift1_'atype_kind`_r10 ((gfc_array_r10 *)ret, (gfc_array_r10 *) array,
165760c2415Smrg      			h, pwhich);
166760c2415Smrg      return;
167760c2415Smrg#endif
168760c2415Smrg
169760c2415Smrg#if defined (HAVE_REAL_16)
170760c2415Smrg    case GFC_DTYPE_REAL_16:
171760c2415Smrg      cshift1_'atype_kind`_r16 ((gfc_array_r16 *)ret, (gfc_array_r16 *) array,
172760c2415Smrg      			h, pwhich);
173760c2415Smrg      return;
174760c2415Smrg#endif
175760c2415Smrg
176760c2415Smrg    case GFC_DTYPE_COMPLEX_4:
177760c2415Smrg      cshift1_'atype_kind`_c4 ((gfc_array_c4 *)ret, (gfc_array_c4 *) array,
178760c2415Smrg      			h, pwhich);
179760c2415Smrg      return;
180760c2415Smrg
181760c2415Smrg    case GFC_DTYPE_COMPLEX_8:
182760c2415Smrg      cshift1_'atype_kind`_c8 ((gfc_array_c8 *)ret, (gfc_array_c8 *) array,
183760c2415Smrg      			h, pwhich);
184760c2415Smrg      return;
185760c2415Smrg
186760c2415Smrg#if defined (HAVE_COMPLEX_10)
187760c2415Smrg    case GFC_DTYPE_COMPLEX_10:
188760c2415Smrg      cshift1_'atype_kind`_c10 ((gfc_array_c10 *)ret, (gfc_array_c10 *) array,
189760c2415Smrg      			h, pwhich);
190760c2415Smrg      return;
191760c2415Smrg#endif
192760c2415Smrg
193760c2415Smrg#if defined (HAVE_COMPLEX_16)
194760c2415Smrg    case GFC_DTYPE_COMPLEX_16:
195760c2415Smrg      cshift1_'atype_kind`_c16 ((gfc_array_c16 *)ret, (gfc_array_c16 *) array,
196760c2415Smrg      			h, pwhich);
197760c2415Smrg      return;
198760c2415Smrg#endif
199760c2415Smrg
200760c2415Smrg    default:
201760c2415Smrg      break;
202760c2415Smrg
203760c2415Smrg  }
204760c2415Smrg
205760c2415Smrg  extent[0] = 1;
206760c2415Smrg  count[0] = 0;
207760c2415Smrg  n = 0;
208760c2415Smrg
209760c2415Smrg  /* Initialized for avoiding compiler warnings.  */
210760c2415Smrg  roffset = size;
211760c2415Smrg  soffset = size;
212760c2415Smrg  len = 0;
213760c2415Smrg
214760c2415Smrg  for (dim = 0; dim < GFC_DESCRIPTOR_RANK (array); dim++)
215760c2415Smrg    {
216760c2415Smrg      if (dim == which)
217760c2415Smrg        {
218760c2415Smrg          roffset = GFC_DESCRIPTOR_STRIDE_BYTES(ret,dim);
219760c2415Smrg          if (roffset == 0)
220760c2415Smrg            roffset = size;
221760c2415Smrg          soffset = GFC_DESCRIPTOR_STRIDE_BYTES(array,dim);
222760c2415Smrg          if (soffset == 0)
223760c2415Smrg            soffset = size;
224760c2415Smrg          len = GFC_DESCRIPTOR_EXTENT(array,dim);
225760c2415Smrg        }
226760c2415Smrg      else
227760c2415Smrg        {
228760c2415Smrg          count[n] = 0;
229760c2415Smrg          extent[n] = GFC_DESCRIPTOR_EXTENT(array,dim);
230760c2415Smrg          rstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(ret,dim);
231760c2415Smrg          sstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(array,dim);
232760c2415Smrg
233760c2415Smrg          hstride[n] = GFC_DESCRIPTOR_STRIDE(h,n);
234760c2415Smrg          n++;
235760c2415Smrg        }
236760c2415Smrg    }
237760c2415Smrg  if (sstride[0] == 0)
238760c2415Smrg    sstride[0] = size;
239760c2415Smrg  if (rstride[0] == 0)
240760c2415Smrg    rstride[0] = size;
241760c2415Smrg  if (hstride[0] == 0)
242760c2415Smrg    hstride[0] = 1;
243760c2415Smrg
244760c2415Smrg  dim = GFC_DESCRIPTOR_RANK (array);
245760c2415Smrg  rstride0 = rstride[0];
246760c2415Smrg  sstride0 = sstride[0];
247760c2415Smrg  hstride0 = hstride[0];
248760c2415Smrg  rptr = ret->base_addr;
249760c2415Smrg  sptr = array->base_addr;
250760c2415Smrg  hptr = h->base_addr;
251760c2415Smrg
252760c2415Smrg  while (rptr)
253760c2415Smrg    {
254760c2415Smrg      /* Do the shift for this dimension.  */
255760c2415Smrg      sh = *hptr;
256760c2415Smrg      /* Normal case should be -len < sh < len; try to
257760c2415Smrg         avoid the expensive remainder operation if possible.  */
258760c2415Smrg      if (sh < 0)
259760c2415Smrg        sh += len;
260760c2415Smrg      if (unlikely (sh >= len || sh < 0))
261760c2415Smrg        {
262760c2415Smrg	  sh = sh % len;
263760c2415Smrg	  if (sh < 0)
264760c2415Smrg	    sh += len;
265760c2415Smrg	}
266760c2415Smrg
267760c2415Smrg      src = &sptr[sh * soffset];
268760c2415Smrg      dest = rptr;
269760c2415Smrg      if (soffset == size && roffset == size)
270760c2415Smrg      {
271760c2415Smrg        size_t len1 = sh * size;
272760c2415Smrg	size_t len2 = (len - sh) * size;
273760c2415Smrg	memcpy (rptr, sptr + len1, len2);
274760c2415Smrg	memcpy (rptr + len2, sptr, len1);
275760c2415Smrg      }
276760c2415Smrg      else
277760c2415Smrg        {
278760c2415Smrg	  for (n = 0; n < len - sh; n++)
279760c2415Smrg            {
280760c2415Smrg	      memcpy (dest, src, size);
281760c2415Smrg	      dest += roffset;
282760c2415Smrg	      src += soffset;
283760c2415Smrg	    }
284760c2415Smrg	    for (src = sptr, n = 0; n < sh; n++)
285760c2415Smrg	      {
286760c2415Smrg		memcpy (dest, src, size);
287760c2415Smrg		dest += roffset;
288760c2415Smrg		src += soffset;
289760c2415Smrg	      }
290760c2415Smrg	  }
291760c2415Smrg
292760c2415Smrg      /* Advance to the next section.  */
293760c2415Smrg      rptr += rstride0;
294760c2415Smrg      sptr += sstride0;
295760c2415Smrg      hptr += hstride0;
296760c2415Smrg      count[0]++;
297760c2415Smrg      n = 0;
298760c2415Smrg      while (count[n] == extent[n])
299760c2415Smrg        {
300760c2415Smrg          /* When we get to the end of a dimension, reset it and increment
301760c2415Smrg             the next dimension.  */
302760c2415Smrg          count[n] = 0;
303760c2415Smrg          /* We could precalculate these products, but this is a less
304760c2415Smrg             frequently used path so probably not worth it.  */
305760c2415Smrg          rptr -= rstride[n] * extent[n];
306760c2415Smrg          sptr -= sstride[n] * extent[n];
307760c2415Smrg	  hptr -= hstride[n] * extent[n];
308760c2415Smrg          n++;
309760c2415Smrg          if (n >= dim - 1)
310760c2415Smrg            {
311760c2415Smrg              /* Break out of the loop.  */
312760c2415Smrg              rptr = NULL;
313760c2415Smrg              break;
314760c2415Smrg            }
315760c2415Smrg          else
316760c2415Smrg            {
317760c2415Smrg              count[n]++;
318760c2415Smrg              rptr += rstride[n];
319760c2415Smrg              sptr += sstride[n];
320760c2415Smrg	      hptr += hstride[n];
321760c2415Smrg            }
322760c2415Smrg        }
323760c2415Smrg    }
324760c2415Smrg}
325760c2415Smrg
326760c2415Smrgvoid cshift1_'atype_kind` (gfc_array_char * const restrict,
327760c2415Smrg	const gfc_array_char * const restrict,
328760c2415Smrg	const 'atype` * const restrict,
329760c2415Smrg	const 'atype_name` * const restrict);
330760c2415Smrgexport_proto(cshift1_'atype_kind`);
331760c2415Smrg
332760c2415Smrgvoid
333760c2415Smrgcshift1_'atype_kind` (gfc_array_char * const restrict ret,
334760c2415Smrg	const gfc_array_char * const restrict array,
335760c2415Smrg	const 'atype` * const restrict h,
336760c2415Smrg	const 'atype_name` * const restrict pwhich)
337760c2415Smrg{
338760c2415Smrg  cshift1 (ret, array, h, pwhich);
339760c2415Smrg}
340760c2415Smrg
341760c2415Smrg
342760c2415Smrgvoid cshift1_'atype_kind`_char (gfc_array_char * const restrict ret,
343760c2415Smrg	GFC_INTEGER_4,
344760c2415Smrg	const gfc_array_char * const restrict array,
345760c2415Smrg	const 'atype` * const restrict h,
346760c2415Smrg	const 'atype_name` * const restrict pwhich,
347760c2415Smrg	GFC_INTEGER_4);
348760c2415Smrgexport_proto(cshift1_'atype_kind`_char);
349760c2415Smrg
350760c2415Smrgvoid
351760c2415Smrgcshift1_'atype_kind`_char (gfc_array_char * const restrict ret,
352760c2415Smrg	GFC_INTEGER_4 ret_length __attribute__((unused)),
353760c2415Smrg	const gfc_array_char * const restrict array,
354760c2415Smrg	const 'atype` * const restrict h,
355760c2415Smrg	const 'atype_name` * const restrict pwhich,
356760c2415Smrg	GFC_INTEGER_4 array_length __attribute__((unused)))
357760c2415Smrg{
358760c2415Smrg  cshift1 (ret, array, h, pwhich);
359760c2415Smrg}
360760c2415Smrg
361760c2415Smrg
362760c2415Smrgvoid cshift1_'atype_kind`_char4 (gfc_array_char * const restrict ret,
363760c2415Smrg	GFC_INTEGER_4,
364760c2415Smrg	const gfc_array_char * const restrict array,
365760c2415Smrg	const 'atype` * const restrict h,
366760c2415Smrg	const 'atype_name` * const restrict pwhich,
367760c2415Smrg	GFC_INTEGER_4);
368760c2415Smrgexport_proto(cshift1_'atype_kind`_char4);
369760c2415Smrg
370760c2415Smrgvoid
371760c2415Smrgcshift1_'atype_kind`_char4 (gfc_array_char * const restrict ret,
372760c2415Smrg	GFC_INTEGER_4 ret_length __attribute__((unused)),
373760c2415Smrg	const gfc_array_char * const restrict array,
374760c2415Smrg	const 'atype` * const restrict h,
375760c2415Smrg	const 'atype_name` * const restrict pwhich,
376760c2415Smrg	GFC_INTEGER_4 array_length __attribute__((unused)))
377760c2415Smrg{
378760c2415Smrg  cshift1 (ret, array, h, pwhich);
379760c2415Smrg}
380760c2415Smrg
381760c2415Smrg#endif'
382