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_REAL_16)
31181254a7Smrg
32181254a7Smrg void
cshift0_r16(gfc_array_r16 * ret,const gfc_array_r16 * array,ptrdiff_t shift,int which)33181254a7Smrg cshift0_r16 (gfc_array_r16 *ret, const gfc_array_r16 *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_REAL_16 *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_REAL_16 *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_REAL_16);
184181254a7Smrg size_t len2 = (len - shift) * sizeof (GFC_REAL_16);
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_REAL_16 *dest = rptr;
193181254a7Smrg const GFC_REAL_16 *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