1181254a7Smrg /* Implementation of the CSHIFT intrinsic.
2*b1e83836Smrg Copyright (C) 2017-2022 Free Software Foundation, Inc.
3181254a7Smrg Contributed by Thomas Koenig <tkoenig@gcc.gnu.org>
4181254a7Smrg
5181254a7Smrg This file is part of the GNU Fortran 95 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 #if defined (HAVE_GFC_COMPLEX_10) && defined (HAVE_GFC_INTEGER_8)
30181254a7Smrg
31181254a7Smrg void
cshift1_8_c10(gfc_array_c10 * const restrict ret,const gfc_array_c10 * const restrict array,const gfc_array_i8 * const restrict h,const GFC_INTEGER_8 * const restrict pwhich)32181254a7Smrg cshift1_8_c10 (gfc_array_c10 * const restrict ret,
33181254a7Smrg const gfc_array_c10 * const restrict array,
34181254a7Smrg const gfc_array_i8 * const restrict h,
35181254a7Smrg const GFC_INTEGER_8 * const restrict pwhich)
36181254a7Smrg {
37181254a7Smrg /* r.* indicates the return array. */
38181254a7Smrg index_type rstride[GFC_MAX_DIMENSIONS];
39181254a7Smrg index_type rstride0;
40181254a7Smrg index_type roffset;
41181254a7Smrg GFC_COMPLEX_10 *rptr;
42181254a7Smrg GFC_COMPLEX_10 *dest;
43181254a7Smrg /* s.* indicates the source array. */
44181254a7Smrg index_type sstride[GFC_MAX_DIMENSIONS];
45181254a7Smrg index_type sstride0;
46181254a7Smrg index_type soffset;
47181254a7Smrg const GFC_COMPLEX_10 *sptr;
48181254a7Smrg const GFC_COMPLEX_10 *src;
49181254a7Smrg /* h.* indicates the shift array. */
50181254a7Smrg index_type hstride[GFC_MAX_DIMENSIONS];
51181254a7Smrg index_type hstride0;
52181254a7Smrg const GFC_INTEGER_8 *hptr;
53181254a7Smrg
54181254a7Smrg index_type count[GFC_MAX_DIMENSIONS];
55181254a7Smrg index_type extent[GFC_MAX_DIMENSIONS];
56181254a7Smrg index_type rs_ex[GFC_MAX_DIMENSIONS];
57181254a7Smrg index_type ss_ex[GFC_MAX_DIMENSIONS];
58181254a7Smrg index_type hs_ex[GFC_MAX_DIMENSIONS];
59181254a7Smrg
60181254a7Smrg index_type dim;
61181254a7Smrg index_type len;
62181254a7Smrg index_type n;
63181254a7Smrg int which;
64181254a7Smrg GFC_INTEGER_8 sh;
65181254a7Smrg
66181254a7Smrg /* Bounds checking etc is already done by the caller. */
67181254a7Smrg
68181254a7Smrg if (pwhich)
69181254a7Smrg which = *pwhich - 1;
70181254a7Smrg else
71181254a7Smrg which = 0;
72181254a7Smrg
73181254a7Smrg extent[0] = 1;
74181254a7Smrg count[0] = 0;
75181254a7Smrg n = 0;
76181254a7Smrg
77181254a7Smrg /* Initialized for avoiding compiler warnings. */
78181254a7Smrg roffset = 1;
79181254a7Smrg soffset = 1;
80181254a7Smrg len = 0;
81181254a7Smrg
82181254a7Smrg for (dim = 0; dim < GFC_DESCRIPTOR_RANK (array); dim++)
83181254a7Smrg {
84181254a7Smrg if (dim == which)
85181254a7Smrg {
86181254a7Smrg roffset = GFC_DESCRIPTOR_STRIDE(ret,dim);
87181254a7Smrg if (roffset == 0)
88181254a7Smrg roffset = 1;
89181254a7Smrg soffset = GFC_DESCRIPTOR_STRIDE(array,dim);
90181254a7Smrg if (soffset == 0)
91181254a7Smrg soffset = 1;
92181254a7Smrg len = GFC_DESCRIPTOR_EXTENT(array,dim);
93181254a7Smrg }
94181254a7Smrg else
95181254a7Smrg {
96181254a7Smrg count[n] = 0;
97181254a7Smrg extent[n] = GFC_DESCRIPTOR_EXTENT(array,dim);
98181254a7Smrg rstride[n] = GFC_DESCRIPTOR_STRIDE(ret,dim);
99181254a7Smrg sstride[n] = GFC_DESCRIPTOR_STRIDE(array,dim);
100181254a7Smrg hstride[n] = GFC_DESCRIPTOR_STRIDE(h,n);
101181254a7Smrg rs_ex[n] = rstride[n] * extent[n];
102181254a7Smrg ss_ex[n] = sstride[n] * extent[n];
103181254a7Smrg hs_ex[n] = hstride[n] * extent[n];
104181254a7Smrg n++;
105181254a7Smrg }
106181254a7Smrg }
107181254a7Smrg if (sstride[0] == 0)
108181254a7Smrg sstride[0] = 1;
109181254a7Smrg if (rstride[0] == 0)
110181254a7Smrg rstride[0] = 1;
111181254a7Smrg if (hstride[0] == 0)
112181254a7Smrg hstride[0] = 1;
113181254a7Smrg
114181254a7Smrg dim = GFC_DESCRIPTOR_RANK (array);
115181254a7Smrg rstride0 = rstride[0];
116181254a7Smrg sstride0 = sstride[0];
117181254a7Smrg hstride0 = hstride[0];
118181254a7Smrg rptr = ret->base_addr;
119181254a7Smrg sptr = array->base_addr;
120181254a7Smrg hptr = h->base_addr;
121181254a7Smrg
122181254a7Smrg while (rptr)
123181254a7Smrg {
124181254a7Smrg /* Do the shift for this dimension. */
125181254a7Smrg sh = *hptr;
126181254a7Smrg /* Normal case should be -len < sh < len; try to
127181254a7Smrg avoid the expensive remainder operation if possible. */
128181254a7Smrg if (sh < 0)
129181254a7Smrg sh += len;
130181254a7Smrg if (unlikely(sh >= len || sh < 0))
131181254a7Smrg {
132181254a7Smrg sh = sh % len;
133181254a7Smrg if (sh < 0)
134181254a7Smrg sh += len;
135181254a7Smrg }
136181254a7Smrg src = &sptr[sh * soffset];
137181254a7Smrg dest = rptr;
138181254a7Smrg if (soffset == 1 && roffset == 1)
139181254a7Smrg {
140181254a7Smrg size_t len1 = sh * sizeof (GFC_COMPLEX_10);
141181254a7Smrg size_t len2 = (len - sh) * sizeof (GFC_COMPLEX_10);
142181254a7Smrg memcpy (rptr, sptr + sh, len2);
143181254a7Smrg memcpy (rptr + (len - sh), sptr, len1);
144181254a7Smrg }
145181254a7Smrg else
146181254a7Smrg {
147181254a7Smrg for (n = 0; n < len - sh; n++)
148181254a7Smrg {
149181254a7Smrg *dest = *src;
150181254a7Smrg dest += roffset;
151181254a7Smrg src += soffset;
152181254a7Smrg }
153181254a7Smrg for (src = sptr, n = 0; n < sh; n++)
154181254a7Smrg {
155181254a7Smrg *dest = *src;
156181254a7Smrg dest += roffset;
157181254a7Smrg src += soffset;
158181254a7Smrg }
159181254a7Smrg }
160181254a7Smrg
161181254a7Smrg /* Advance to the next section. */
162181254a7Smrg rptr += rstride0;
163181254a7Smrg sptr += sstride0;
164181254a7Smrg hptr += hstride0;
165181254a7Smrg count[0]++;
166181254a7Smrg n = 0;
167181254a7Smrg while (count[n] == extent[n])
168181254a7Smrg {
169181254a7Smrg /* When we get to the end of a dimension, reset it and increment
170181254a7Smrg the next dimension. */
171181254a7Smrg count[n] = 0;
172181254a7Smrg rptr -= rs_ex[n];
173181254a7Smrg sptr -= ss_ex[n];
174181254a7Smrg hptr -= hs_ex[n];
175181254a7Smrg n++;
176181254a7Smrg if (n >= dim - 1)
177181254a7Smrg {
178181254a7Smrg /* Break out of the loop. */
179181254a7Smrg rptr = NULL;
180181254a7Smrg break;
181181254a7Smrg }
182181254a7Smrg else
183181254a7Smrg {
184181254a7Smrg count[n]++;
185181254a7Smrg rptr += rstride[n];
186181254a7Smrg sptr += sstride[n];
187181254a7Smrg hptr += hstride[n];
188181254a7Smrg }
189181254a7Smrg }
190181254a7Smrg }
191181254a7Smrg }
192181254a7Smrg
193181254a7Smrg #endif
194