xref: /netbsd-src/external/gpl3/gcc.old/dist/libgfortran/m4/cshift1.m4 (revision 4c3eb207d36f67d31994830c0a694161fc1ca39b)
1627f7eb2Smrg`/* Implementation of the CSHIFT intrinsic
2*4c3eb207Smrg   Copyright (C) 2003-2020 Free Software Foundation, Inc.
3627f7eb2Smrg   Contributed by Feng Wang <wf_cs@yahoo.com>
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
12627f7eb2SmrgLigbfortran 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_'atype_name`)
32627f7eb2Smrg
33627f7eb2Smrgstatic void
34627f7eb2Smrgcshift1 (gfc_array_char * const restrict ret,
35627f7eb2Smrg	const gfc_array_char * const restrict array,
36627f7eb2Smrg	const 'atype` * const restrict h,
37627f7eb2Smrg	const 'atype_name` * const restrict pwhich)
38627f7eb2Smrg{
39627f7eb2Smrg  /* r.* indicates the return array.  */
40627f7eb2Smrg  index_type rstride[GFC_MAX_DIMENSIONS];
41627f7eb2Smrg  index_type rstride0;
42627f7eb2Smrg  index_type roffset;
43627f7eb2Smrg  char *rptr;
44627f7eb2Smrg  char *dest;
45627f7eb2Smrg  /* s.* indicates the source array.  */
46627f7eb2Smrg  index_type sstride[GFC_MAX_DIMENSIONS];
47627f7eb2Smrg  index_type sstride0;
48627f7eb2Smrg  index_type soffset;
49627f7eb2Smrg  const char *sptr;
50627f7eb2Smrg  const char *src;
51627f7eb2Smrg  /* h.* indicates the shift array.  */
52627f7eb2Smrg  index_type hstride[GFC_MAX_DIMENSIONS];
53627f7eb2Smrg  index_type hstride0;
54627f7eb2Smrg  const 'atype_name` *hptr;
55627f7eb2Smrg
56627f7eb2Smrg  index_type count[GFC_MAX_DIMENSIONS];
57627f7eb2Smrg  index_type extent[GFC_MAX_DIMENSIONS];
58627f7eb2Smrg  index_type dim;
59627f7eb2Smrg  index_type len;
60627f7eb2Smrg  index_type n;
61627f7eb2Smrg  int which;
62627f7eb2Smrg  'atype_name` sh;
63627f7eb2Smrg  index_type arraysize;
64627f7eb2Smrg  index_type size;
65627f7eb2Smrg  index_type type_size;
66627f7eb2Smrg
67627f7eb2Smrg  if (pwhich)
68627f7eb2Smrg    which = *pwhich - 1;
69627f7eb2Smrg  else
70627f7eb2Smrg    which = 0;
71627f7eb2Smrg
72627f7eb2Smrg  if (which < 0 || (which + 1) > GFC_DESCRIPTOR_RANK (array))
73627f7eb2Smrg    runtime_error ("Argument ''`DIM''` is out of range in call to ''`CSHIFT''`");
74627f7eb2Smrg
75627f7eb2Smrg  size = GFC_DESCRIPTOR_SIZE(array);
76627f7eb2Smrg
77627f7eb2Smrg  arraysize = size0 ((array_t *)array);
78627f7eb2Smrg
79627f7eb2Smrg  if (ret->base_addr == NULL)
80627f7eb2Smrg    {
81627f7eb2Smrg      ret->base_addr = xmallocarray (arraysize, size);
82627f7eb2Smrg      ret->offset = 0;
83627f7eb2Smrg      GFC_DTYPE_COPY(ret,array);
84627f7eb2Smrg      for (index_type i = 0; i < GFC_DESCRIPTOR_RANK (array); i++)
85627f7eb2Smrg        {
86627f7eb2Smrg	  index_type ub, str;
87627f7eb2Smrg
88627f7eb2Smrg          ub = GFC_DESCRIPTOR_EXTENT(array,i) - 1;
89627f7eb2Smrg
90627f7eb2Smrg          if (i == 0)
91627f7eb2Smrg            str = 1;
92627f7eb2Smrg          else
93627f7eb2Smrg	    str = GFC_DESCRIPTOR_EXTENT(ret,i-1) *
94627f7eb2Smrg	      GFC_DESCRIPTOR_STRIDE(ret,i-1);
95627f7eb2Smrg
96627f7eb2Smrg	  GFC_DIMENSION_SET(ret->dim[i], 0, ub, str);
97627f7eb2Smrg        }
98627f7eb2Smrg    }
99627f7eb2Smrg  else if (unlikely (compile_options.bounds_check))
100627f7eb2Smrg    {
101627f7eb2Smrg      bounds_equal_extents ((array_t *) ret, (array_t *) array,
102627f7eb2Smrg				 "return value", "CSHIFT");
103627f7eb2Smrg    }
104627f7eb2Smrg
105627f7eb2Smrg  if (unlikely (compile_options.bounds_check))
106627f7eb2Smrg    {
107627f7eb2Smrg      bounds_reduced_extents ((array_t *) h, (array_t *) array, which,
108627f7eb2Smrg      			      "SHIFT argument", "CSHIFT");
109627f7eb2Smrg    }
110627f7eb2Smrg
111627f7eb2Smrg  if (arraysize == 0)
112627f7eb2Smrg    return;
113627f7eb2Smrg
114627f7eb2Smrg  /* See if we should dispatch to a helper function.  */
115627f7eb2Smrg
116627f7eb2Smrg  type_size = GFC_DTYPE_TYPE_SIZE (array);
117627f7eb2Smrg
118627f7eb2Smrg  switch (type_size)
119627f7eb2Smrg  {
120627f7eb2Smrg    case GFC_DTYPE_LOGICAL_1:
121627f7eb2Smrg    case GFC_DTYPE_INTEGER_1:
122627f7eb2Smrg      cshift1_'atype_kind`_i1 ((gfc_array_i1 *)ret, (gfc_array_i1 *) array,
123627f7eb2Smrg      			h, pwhich);
124627f7eb2Smrg      return;
125627f7eb2Smrg
126627f7eb2Smrg    case GFC_DTYPE_LOGICAL_2:
127627f7eb2Smrg    case GFC_DTYPE_INTEGER_2:
128627f7eb2Smrg      cshift1_'atype_kind`_i2 ((gfc_array_i2 *)ret, (gfc_array_i2 *) array,
129627f7eb2Smrg      			h, pwhich);
130627f7eb2Smrg      return;
131627f7eb2Smrg
132627f7eb2Smrg    case GFC_DTYPE_LOGICAL_4:
133627f7eb2Smrg    case GFC_DTYPE_INTEGER_4:
134627f7eb2Smrg      cshift1_'atype_kind`_i4 ((gfc_array_i4 *)ret, (gfc_array_i4 *) array,
135627f7eb2Smrg      			h, pwhich);
136627f7eb2Smrg      return;
137627f7eb2Smrg
138627f7eb2Smrg    case GFC_DTYPE_LOGICAL_8:
139627f7eb2Smrg    case GFC_DTYPE_INTEGER_8:
140627f7eb2Smrg      cshift1_'atype_kind`_i8 ((gfc_array_i8 *)ret, (gfc_array_i8 *) array,
141627f7eb2Smrg      			h, pwhich);
142627f7eb2Smrg      return;
143627f7eb2Smrg
144627f7eb2Smrg#if defined (HAVE_INTEGER_16)
145627f7eb2Smrg    case GFC_DTYPE_LOGICAL_16:
146627f7eb2Smrg    case GFC_DTYPE_INTEGER_16:
147627f7eb2Smrg      cshift1_'atype_kind`_i16 ((gfc_array_i16 *)ret, (gfc_array_i16 *) array,
148627f7eb2Smrg      			h, pwhich);
149627f7eb2Smrg      return;
150627f7eb2Smrg#endif
151627f7eb2Smrg
152627f7eb2Smrg    case GFC_DTYPE_REAL_4:
153627f7eb2Smrg      cshift1_'atype_kind`_r4 ((gfc_array_r4 *)ret, (gfc_array_r4 *) array,
154627f7eb2Smrg      			h, pwhich);
155627f7eb2Smrg      return;
156627f7eb2Smrg
157627f7eb2Smrg    case GFC_DTYPE_REAL_8:
158627f7eb2Smrg      cshift1_'atype_kind`_r8 ((gfc_array_r8 *)ret, (gfc_array_r8 *) array,
159627f7eb2Smrg      			h, pwhich);
160627f7eb2Smrg      return;
161627f7eb2Smrg
162627f7eb2Smrg#if defined (HAVE_REAL_10)
163627f7eb2Smrg    case GFC_DTYPE_REAL_10:
164627f7eb2Smrg      cshift1_'atype_kind`_r10 ((gfc_array_r10 *)ret, (gfc_array_r10 *) array,
165627f7eb2Smrg      			h, pwhich);
166627f7eb2Smrg      return;
167627f7eb2Smrg#endif
168627f7eb2Smrg
169627f7eb2Smrg#if defined (HAVE_REAL_16)
170627f7eb2Smrg    case GFC_DTYPE_REAL_16:
171627f7eb2Smrg      cshift1_'atype_kind`_r16 ((gfc_array_r16 *)ret, (gfc_array_r16 *) array,
172627f7eb2Smrg      			h, pwhich);
173627f7eb2Smrg      return;
174627f7eb2Smrg#endif
175627f7eb2Smrg
176627f7eb2Smrg    case GFC_DTYPE_COMPLEX_4:
177627f7eb2Smrg      cshift1_'atype_kind`_c4 ((gfc_array_c4 *)ret, (gfc_array_c4 *) array,
178627f7eb2Smrg      			h, pwhich);
179627f7eb2Smrg      return;
180627f7eb2Smrg
181627f7eb2Smrg    case GFC_DTYPE_COMPLEX_8:
182627f7eb2Smrg      cshift1_'atype_kind`_c8 ((gfc_array_c8 *)ret, (gfc_array_c8 *) array,
183627f7eb2Smrg      			h, pwhich);
184627f7eb2Smrg      return;
185627f7eb2Smrg
186627f7eb2Smrg#if defined (HAVE_COMPLEX_10)
187627f7eb2Smrg    case GFC_DTYPE_COMPLEX_10:
188627f7eb2Smrg      cshift1_'atype_kind`_c10 ((gfc_array_c10 *)ret, (gfc_array_c10 *) array,
189627f7eb2Smrg      			h, pwhich);
190627f7eb2Smrg      return;
191627f7eb2Smrg#endif
192627f7eb2Smrg
193627f7eb2Smrg#if defined (HAVE_COMPLEX_16)
194627f7eb2Smrg    case GFC_DTYPE_COMPLEX_16:
195627f7eb2Smrg      cshift1_'atype_kind`_c16 ((gfc_array_c16 *)ret, (gfc_array_c16 *) array,
196627f7eb2Smrg      			h, pwhich);
197627f7eb2Smrg      return;
198627f7eb2Smrg#endif
199627f7eb2Smrg
200627f7eb2Smrg    default:
201627f7eb2Smrg      break;
202627f7eb2Smrg
203627f7eb2Smrg  }
204627f7eb2Smrg
205627f7eb2Smrg  extent[0] = 1;
206627f7eb2Smrg  count[0] = 0;
207627f7eb2Smrg  n = 0;
208627f7eb2Smrg
209627f7eb2Smrg  /* Initialized for avoiding compiler warnings.  */
210627f7eb2Smrg  roffset = size;
211627f7eb2Smrg  soffset = size;
212627f7eb2Smrg  len = 0;
213627f7eb2Smrg
214627f7eb2Smrg  for (dim = 0; dim < GFC_DESCRIPTOR_RANK (array); dim++)
215627f7eb2Smrg    {
216627f7eb2Smrg      if (dim == which)
217627f7eb2Smrg        {
218627f7eb2Smrg          roffset = GFC_DESCRIPTOR_STRIDE_BYTES(ret,dim);
219627f7eb2Smrg          if (roffset == 0)
220627f7eb2Smrg            roffset = size;
221627f7eb2Smrg          soffset = GFC_DESCRIPTOR_STRIDE_BYTES(array,dim);
222627f7eb2Smrg          if (soffset == 0)
223627f7eb2Smrg            soffset = size;
224627f7eb2Smrg          len = GFC_DESCRIPTOR_EXTENT(array,dim);
225627f7eb2Smrg        }
226627f7eb2Smrg      else
227627f7eb2Smrg        {
228627f7eb2Smrg          count[n] = 0;
229627f7eb2Smrg          extent[n] = GFC_DESCRIPTOR_EXTENT(array,dim);
230627f7eb2Smrg          rstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(ret,dim);
231627f7eb2Smrg          sstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(array,dim);
232627f7eb2Smrg
233627f7eb2Smrg          hstride[n] = GFC_DESCRIPTOR_STRIDE(h,n);
234627f7eb2Smrg          n++;
235627f7eb2Smrg        }
236627f7eb2Smrg    }
237627f7eb2Smrg  if (sstride[0] == 0)
238627f7eb2Smrg    sstride[0] = size;
239627f7eb2Smrg  if (rstride[0] == 0)
240627f7eb2Smrg    rstride[0] = size;
241627f7eb2Smrg  if (hstride[0] == 0)
242627f7eb2Smrg    hstride[0] = 1;
243627f7eb2Smrg
244627f7eb2Smrg  dim = GFC_DESCRIPTOR_RANK (array);
245627f7eb2Smrg  rstride0 = rstride[0];
246627f7eb2Smrg  sstride0 = sstride[0];
247627f7eb2Smrg  hstride0 = hstride[0];
248627f7eb2Smrg  rptr = ret->base_addr;
249627f7eb2Smrg  sptr = array->base_addr;
250627f7eb2Smrg  hptr = h->base_addr;
251627f7eb2Smrg
252627f7eb2Smrg  while (rptr)
253627f7eb2Smrg    {
254627f7eb2Smrg      /* Do the shift for this dimension.  */
255627f7eb2Smrg      sh = *hptr;
256627f7eb2Smrg      /* Normal case should be -len < sh < len; try to
257627f7eb2Smrg         avoid the expensive remainder operation if possible.  */
258627f7eb2Smrg      if (sh < 0)
259627f7eb2Smrg        sh += len;
260627f7eb2Smrg      if (unlikely (sh >= len || sh < 0))
261627f7eb2Smrg        {
262627f7eb2Smrg	  sh = sh % len;
263627f7eb2Smrg	  if (sh < 0)
264627f7eb2Smrg	    sh += len;
265627f7eb2Smrg	}
266627f7eb2Smrg
267627f7eb2Smrg      src = &sptr[sh * soffset];
268627f7eb2Smrg      dest = rptr;
269627f7eb2Smrg      if (soffset == size && roffset == size)
270627f7eb2Smrg      {
271627f7eb2Smrg        size_t len1 = sh * size;
272627f7eb2Smrg	size_t len2 = (len - sh) * size;
273627f7eb2Smrg	memcpy (rptr, sptr + len1, len2);
274627f7eb2Smrg	memcpy (rptr + len2, sptr, len1);
275627f7eb2Smrg      }
276627f7eb2Smrg      else
277627f7eb2Smrg        {
278627f7eb2Smrg	  for (n = 0; n < len - sh; n++)
279627f7eb2Smrg            {
280627f7eb2Smrg	      memcpy (dest, src, size);
281627f7eb2Smrg	      dest += roffset;
282627f7eb2Smrg	      src += soffset;
283627f7eb2Smrg	    }
284627f7eb2Smrg	    for (src = sptr, n = 0; n < sh; n++)
285627f7eb2Smrg	      {
286627f7eb2Smrg		memcpy (dest, src, size);
287627f7eb2Smrg		dest += roffset;
288627f7eb2Smrg		src += soffset;
289627f7eb2Smrg	      }
290627f7eb2Smrg	  }
291627f7eb2Smrg
292627f7eb2Smrg      /* Advance to the next section.  */
293627f7eb2Smrg      rptr += rstride0;
294627f7eb2Smrg      sptr += sstride0;
295627f7eb2Smrg      hptr += hstride0;
296627f7eb2Smrg      count[0]++;
297627f7eb2Smrg      n = 0;
298627f7eb2Smrg      while (count[n] == extent[n])
299627f7eb2Smrg        {
300627f7eb2Smrg          /* When we get to the end of a dimension, reset it and increment
301627f7eb2Smrg             the next dimension.  */
302627f7eb2Smrg          count[n] = 0;
303627f7eb2Smrg          /* We could precalculate these products, but this is a less
304627f7eb2Smrg             frequently used path so probably not worth it.  */
305627f7eb2Smrg          rptr -= rstride[n] * extent[n];
306627f7eb2Smrg          sptr -= sstride[n] * extent[n];
307627f7eb2Smrg	  hptr -= hstride[n] * extent[n];
308627f7eb2Smrg          n++;
309627f7eb2Smrg          if (n >= dim - 1)
310627f7eb2Smrg            {
311627f7eb2Smrg              /* Break out of the loop.  */
312627f7eb2Smrg              rptr = NULL;
313627f7eb2Smrg              break;
314627f7eb2Smrg            }
315627f7eb2Smrg          else
316627f7eb2Smrg            {
317627f7eb2Smrg              count[n]++;
318627f7eb2Smrg              rptr += rstride[n];
319627f7eb2Smrg              sptr += sstride[n];
320627f7eb2Smrg	      hptr += hstride[n];
321627f7eb2Smrg            }
322627f7eb2Smrg        }
323627f7eb2Smrg    }
324627f7eb2Smrg}
325627f7eb2Smrg
326627f7eb2Smrgvoid cshift1_'atype_kind` (gfc_array_char * const restrict,
327627f7eb2Smrg	const gfc_array_char * const restrict,
328627f7eb2Smrg	const 'atype` * const restrict,
329627f7eb2Smrg	const 'atype_name` * const restrict);
330627f7eb2Smrgexport_proto(cshift1_'atype_kind`);
331627f7eb2Smrg
332627f7eb2Smrgvoid
333627f7eb2Smrgcshift1_'atype_kind` (gfc_array_char * const restrict ret,
334627f7eb2Smrg	const gfc_array_char * const restrict array,
335627f7eb2Smrg	const 'atype` * const restrict h,
336627f7eb2Smrg	const 'atype_name` * const restrict pwhich)
337627f7eb2Smrg{
338627f7eb2Smrg  cshift1 (ret, array, h, pwhich);
339627f7eb2Smrg}
340627f7eb2Smrg
341627f7eb2Smrg
342627f7eb2Smrgvoid cshift1_'atype_kind`_char (gfc_array_char * const restrict ret,
343627f7eb2Smrg	GFC_INTEGER_4,
344627f7eb2Smrg	const gfc_array_char * const restrict array,
345627f7eb2Smrg	const 'atype` * const restrict h,
346627f7eb2Smrg	const 'atype_name` * const restrict pwhich,
347627f7eb2Smrg	GFC_INTEGER_4);
348627f7eb2Smrgexport_proto(cshift1_'atype_kind`_char);
349627f7eb2Smrg
350627f7eb2Smrgvoid
351627f7eb2Smrgcshift1_'atype_kind`_char (gfc_array_char * const restrict ret,
352627f7eb2Smrg	GFC_INTEGER_4 ret_length __attribute__((unused)),
353627f7eb2Smrg	const gfc_array_char * const restrict array,
354627f7eb2Smrg	const 'atype` * const restrict h,
355627f7eb2Smrg	const 'atype_name` * const restrict pwhich,
356627f7eb2Smrg	GFC_INTEGER_4 array_length __attribute__((unused)))
357627f7eb2Smrg{
358627f7eb2Smrg  cshift1 (ret, array, h, pwhich);
359627f7eb2Smrg}
360627f7eb2Smrg
361627f7eb2Smrg
362627f7eb2Smrgvoid cshift1_'atype_kind`_char4 (gfc_array_char * const restrict ret,
363627f7eb2Smrg	GFC_INTEGER_4,
364627f7eb2Smrg	const gfc_array_char * const restrict array,
365627f7eb2Smrg	const 'atype` * const restrict h,
366627f7eb2Smrg	const 'atype_name` * const restrict pwhich,
367627f7eb2Smrg	GFC_INTEGER_4);
368627f7eb2Smrgexport_proto(cshift1_'atype_kind`_char4);
369627f7eb2Smrg
370627f7eb2Smrgvoid
371627f7eb2Smrgcshift1_'atype_kind`_char4 (gfc_array_char * const restrict ret,
372627f7eb2Smrg	GFC_INTEGER_4 ret_length __attribute__((unused)),
373627f7eb2Smrg	const gfc_array_char * const restrict array,
374627f7eb2Smrg	const 'atype` * const restrict h,
375627f7eb2Smrg	const 'atype_name` * const restrict pwhich,
376627f7eb2Smrg	GFC_INTEGER_4 array_length __attribute__((unused)))
377627f7eb2Smrg{
378627f7eb2Smrg  cshift1 (ret, array, h, pwhich);
379627f7eb2Smrg}
380627f7eb2Smrg
381627f7eb2Smrg#endif'
382