cshift0.m4 revision 1.1.1.4 1 1.1 mrg `/* Helper function for cshift functions.
2 1.1.1.4 mrg Copyright (C) 2008-2024 Free Software Foundation, Inc.
3 1.1 mrg Contributed by Thomas Koenig <tkoenig (a] gcc.gnu.org>
4 1.1 mrg
5 1.1 mrg This file is part of the GNU Fortran runtime library (libgfortran).
6 1.1 mrg
7 1.1 mrg Libgfortran is free software; you can redistribute it and/or
8 1.1 mrg modify it under the terms of the GNU General Public
9 1.1 mrg License as published by the Free Software Foundation; either
10 1.1 mrg version 3 of the License, or (at your option) any later version.
11 1.1 mrg
12 1.1 mrg Libgfortran is distributed in the hope that it will be useful,
13 1.1 mrg but WITHOUT ANY WARRANTY; without even the implied warranty of
14 1.1 mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 1.1 mrg GNU General Public License for more details.
16 1.1 mrg
17 1.1 mrg Under Section 7 of GPL version 3, you are granted additional
18 1.1 mrg permissions described in the GCC Runtime Library Exception, version
19 1.1 mrg 3.1, as published by the Free Software Foundation.
20 1.1 mrg
21 1.1 mrg You should have received a copy of the GNU General Public License and
22 1.1 mrg a copy of the GCC Runtime Library Exception along with this program;
23 1.1 mrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 1.1 mrg <http://www.gnu.org/licenses/>. */
25 1.1 mrg
26 1.1 mrg #include "libgfortran.h"
27 1.1 mrg #include <string.h>'
28 1.1 mrg
29 1.1 mrg include(iparm.m4)dnl
30 1.1 mrg
31 1.1 mrg `#if defined (HAVE_'rtype_name`)
32 1.1 mrg
33 1.1 mrg void
34 1.1 mrg cshift0_'rtype_code` ('rtype` *ret, const 'rtype` *array, ptrdiff_t shift,
35 1.1 mrg int which)
36 1.1 mrg {
37 1.1 mrg /* r.* indicates the return array. */
38 1.1 mrg index_type rstride[GFC_MAX_DIMENSIONS];
39 1.1 mrg index_type rstride0;
40 1.1 mrg index_type roffset;
41 1.1 mrg 'rtype_name` *rptr;
42 1.1 mrg
43 1.1 mrg /* s.* indicates the source array. */
44 1.1 mrg index_type sstride[GFC_MAX_DIMENSIONS];
45 1.1 mrg index_type sstride0;
46 1.1 mrg index_type soffset;
47 1.1 mrg const 'rtype_name` *sptr;
48 1.1 mrg
49 1.1 mrg index_type count[GFC_MAX_DIMENSIONS];
50 1.1 mrg index_type extent[GFC_MAX_DIMENSIONS];
51 1.1 mrg index_type dim;
52 1.1 mrg index_type len;
53 1.1 mrg index_type n;
54 1.1 mrg
55 1.1 mrg bool do_blocked;
56 1.1 mrg index_type r_ex, a_ex;
57 1.1 mrg
58 1.1 mrg which = which - 1;
59 1.1 mrg sstride[0] = 0;
60 1.1 mrg rstride[0] = 0;
61 1.1 mrg
62 1.1 mrg extent[0] = 1;
63 1.1 mrg count[0] = 0;
64 1.1 mrg n = 0;
65 1.1 mrg /* Initialized for avoiding compiler warnings. */
66 1.1 mrg roffset = 1;
67 1.1 mrg soffset = 1;
68 1.1 mrg len = 0;
69 1.1 mrg
70 1.1 mrg r_ex = 1;
71 1.1 mrg a_ex = 1;
72 1.1 mrg
73 1.1 mrg if (which > 0)
74 1.1 mrg {
75 1.1 mrg /* Test if both ret and array are contiguous. */
76 1.1 mrg do_blocked = true;
77 1.1 mrg dim = GFC_DESCRIPTOR_RANK (array);
78 1.1 mrg for (n = 0; n < dim; n ++)
79 1.1 mrg {
80 1.1 mrg index_type rs, as;
81 1.1 mrg rs = GFC_DESCRIPTOR_STRIDE (ret, n);
82 1.1 mrg if (rs != r_ex)
83 1.1 mrg {
84 1.1 mrg do_blocked = false;
85 1.1 mrg break;
86 1.1 mrg }
87 1.1 mrg as = GFC_DESCRIPTOR_STRIDE (array, n);
88 1.1 mrg if (as != a_ex)
89 1.1 mrg {
90 1.1 mrg do_blocked = false;
91 1.1 mrg break;
92 1.1 mrg }
93 1.1 mrg r_ex *= GFC_DESCRIPTOR_EXTENT (ret, n);
94 1.1 mrg a_ex *= GFC_DESCRIPTOR_EXTENT (array, n);
95 1.1 mrg }
96 1.1 mrg }
97 1.1 mrg else
98 1.1 mrg do_blocked = false;
99 1.1 mrg
100 1.1 mrg n = 0;
101 1.1 mrg
102 1.1 mrg if (do_blocked)
103 1.1 mrg {
104 1.1 mrg /* For contiguous arrays, use the relationship that
105 1.1 mrg
106 1.1 mrg dimension(n1,n2,n3) :: a, b
107 1.1 mrg b = cshift(a,sh,3)
108 1.1 mrg
109 1.1 mrg can be dealt with as if
110 1.1 mrg
111 1.1 mrg dimension(n1*n2*n3) :: an, bn
112 1.1 mrg bn = cshift(a,sh*n1*n2,1)
113 1.1 mrg
114 1.1 mrg we can used a more blocked algorithm for dim>1. */
115 1.1 mrg sstride[0] = 1;
116 1.1 mrg rstride[0] = 1;
117 1.1 mrg roffset = 1;
118 1.1 mrg soffset = 1;
119 1.1 mrg len = GFC_DESCRIPTOR_STRIDE(array, which)
120 1.1 mrg * GFC_DESCRIPTOR_EXTENT(array, which);
121 1.1 mrg shift *= GFC_DESCRIPTOR_STRIDE(array, which);
122 1.1 mrg for (dim = which + 1; dim < GFC_DESCRIPTOR_RANK (array); dim++)
123 1.1 mrg {
124 1.1 mrg count[n] = 0;
125 1.1 mrg extent[n] = GFC_DESCRIPTOR_EXTENT(array,dim);
126 1.1 mrg rstride[n] = GFC_DESCRIPTOR_STRIDE(ret,dim);
127 1.1 mrg sstride[n] = GFC_DESCRIPTOR_STRIDE(array,dim);
128 1.1 mrg n++;
129 1.1 mrg }
130 1.1 mrg dim = GFC_DESCRIPTOR_RANK (array) - which;
131 1.1 mrg }
132 1.1 mrg else
133 1.1 mrg {
134 1.1 mrg for (dim = 0; dim < GFC_DESCRIPTOR_RANK (array); dim++)
135 1.1 mrg {
136 1.1 mrg if (dim == which)
137 1.1 mrg {
138 1.1 mrg roffset = GFC_DESCRIPTOR_STRIDE(ret,dim);
139 1.1 mrg if (roffset == 0)
140 1.1 mrg roffset = 1;
141 1.1 mrg soffset = GFC_DESCRIPTOR_STRIDE(array,dim);
142 1.1 mrg if (soffset == 0)
143 1.1 mrg soffset = 1;
144 1.1 mrg len = GFC_DESCRIPTOR_EXTENT(array,dim);
145 1.1 mrg }
146 1.1 mrg else
147 1.1 mrg {
148 1.1 mrg count[n] = 0;
149 1.1 mrg extent[n] = GFC_DESCRIPTOR_EXTENT(array,dim);
150 1.1 mrg rstride[n] = GFC_DESCRIPTOR_STRIDE(ret,dim);
151 1.1 mrg sstride[n] = GFC_DESCRIPTOR_STRIDE(array,dim);
152 1.1 mrg n++;
153 1.1 mrg }
154 1.1 mrg }
155 1.1 mrg if (sstride[0] == 0)
156 1.1 mrg sstride[0] = 1;
157 1.1 mrg if (rstride[0] == 0)
158 1.1 mrg rstride[0] = 1;
159 1.1 mrg
160 1.1 mrg dim = GFC_DESCRIPTOR_RANK (array);
161 1.1 mrg }
162 1.1 mrg
163 1.1 mrg rstride0 = rstride[0];
164 1.1 mrg sstride0 = sstride[0];
165 1.1 mrg rptr = ret->base_addr;
166 1.1 mrg sptr = array->base_addr;
167 1.1 mrg
168 1.1 mrg /* Avoid the costly modulo for trivially in-bound shifts. */
169 1.1 mrg if (shift < 0 || shift >= len)
170 1.1 mrg {
171 1.1 mrg shift = len == 0 ? 0 : shift % (ptrdiff_t)len;
172 1.1 mrg if (shift < 0)
173 1.1 mrg shift += len;
174 1.1 mrg }
175 1.1 mrg
176 1.1 mrg while (rptr)
177 1.1 mrg {
178 1.1 mrg /* Do the shift for this dimension. */
179 1.1 mrg
180 1.1 mrg /* If elements are contiguous, perform the operation
181 1.1 mrg in two block moves. */
182 1.1 mrg if (soffset == 1 && roffset == 1)
183 1.1 mrg {
184 1.1 mrg size_t len1 = shift * sizeof ('rtype_name`);
185 1.1 mrg size_t len2 = (len - shift) * sizeof ('rtype_name`);
186 1.1 mrg memcpy (rptr, sptr + shift, len2);
187 1.1 mrg memcpy (rptr + (len - shift), sptr, len1);
188 1.1 mrg }
189 1.1 mrg else
190 1.1 mrg {
191 1.1 mrg /* Otherwise, we will have to perform the copy one element at
192 1.1 mrg a time. */
193 1.1 mrg 'rtype_name` *dest = rptr;
194 1.1 mrg const 'rtype_name` *src = &sptr[shift * soffset];
195 1.1 mrg
196 1.1 mrg for (n = 0; n < len - shift; n++)
197 1.1 mrg {
198 1.1 mrg *dest = *src;
199 1.1 mrg dest += roffset;
200 1.1 mrg src += soffset;
201 1.1 mrg }
202 1.1 mrg for (src = sptr, n = 0; n < shift; n++)
203 1.1 mrg {
204 1.1 mrg *dest = *src;
205 1.1 mrg dest += roffset;
206 1.1 mrg src += soffset;
207 1.1 mrg }
208 1.1 mrg }
209 1.1 mrg
210 1.1 mrg /* Advance to the next section. */
211 1.1 mrg rptr += rstride0;
212 1.1 mrg sptr += sstride0;
213 1.1 mrg count[0]++;
214 1.1 mrg n = 0;
215 1.1 mrg while (count[n] == extent[n])
216 1.1 mrg {
217 1.1 mrg /* When we get to the end of a dimension, reset it and increment
218 1.1 mrg the next dimension. */
219 1.1 mrg count[n] = 0;
220 1.1 mrg /* We could precalculate these products, but this is a less
221 1.1 mrg frequently used path so probably not worth it. */
222 1.1 mrg rptr -= rstride[n] * extent[n];
223 1.1 mrg sptr -= sstride[n] * extent[n];
224 1.1 mrg n++;
225 1.1 mrg if (n >= dim - 1)
226 1.1 mrg {
227 1.1 mrg /* Break out of the loop. */
228 1.1 mrg rptr = NULL;
229 1.1 mrg break;
230 1.1 mrg }
231 1.1 mrg else
232 1.1 mrg {
233 1.1 mrg count[n]++;
234 1.1 mrg rptr += rstride[n];
235 1.1 mrg sptr += sstride[n];
236 1.1 mrg }
237 1.1 mrg }
238 1.1 mrg }
239 1.1 mrg
240 1.1 mrg return;
241 1.1 mrg }
242 1.1 mrg
243 1.1 mrg #endif'
244