spread.m4 revision 1.1.1.3 1 1.1 mrg `/* Special implementation of the SPREAD intrinsic
2 1.1.1.3 mrg Copyright (C) 2008-2022 Free Software Foundation, Inc.
3 1.1 mrg Contributed by Thomas Koenig <tkoenig (a] gcc.gnu.org>, based on
4 1.1 mrg spread_generic.c written by Paul Brook <paul (a] nowt.org>
5 1.1 mrg
6 1.1 mrg This file is part of the GNU Fortran runtime library (libgfortran).
7 1.1 mrg
8 1.1 mrg Libgfortran is free software; you can redistribute it and/or
9 1.1 mrg modify it under the terms of the GNU General Public
10 1.1 mrg License as published by the Free Software Foundation; either
11 1.1 mrg version 3 of the License, or (at your option) any later version.
12 1.1 mrg
13 1.1 mrg Ligbfortran is distributed in the hope that it will be useful,
14 1.1 mrg but WITHOUT ANY WARRANTY; without even the implied warranty of
15 1.1 mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 1.1 mrg GNU General Public License for more details.
17 1.1 mrg
18 1.1 mrg Under Section 7 of GPL version 3, you are granted additional
19 1.1 mrg permissions described in the GCC Runtime Library Exception, version
20 1.1 mrg 3.1, as published by the Free Software Foundation.
21 1.1 mrg
22 1.1 mrg You should have received a copy of the GNU General Public License and
23 1.1 mrg a copy of the GCC Runtime Library Exception along with this program;
24 1.1 mrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25 1.1 mrg <http://www.gnu.org/licenses/>. */
26 1.1 mrg
27 1.1 mrg #include "libgfortran.h"
28 1.1 mrg #include <string.h>'
29 1.1 mrg
30 1.1 mrg include(iparm.m4)dnl
31 1.1 mrg
32 1.1 mrg `#if defined (HAVE_'rtype_name`)
33 1.1 mrg
34 1.1 mrg void
35 1.1 mrg spread_'rtype_code` ('rtype` *ret, const 'rtype` *source,
36 1.1 mrg const index_type along, const index_type pncopies)
37 1.1 mrg {
38 1.1 mrg /* r.* indicates the return array. */
39 1.1 mrg index_type rstride[GFC_MAX_DIMENSIONS];
40 1.1 mrg index_type rstride0;
41 1.1 mrg index_type rdelta = 0;
42 1.1 mrg index_type rrank;
43 1.1 mrg index_type rs;
44 1.1 mrg 'rtype_name` *rptr;
45 1.1 mrg 'rtype_name` * restrict dest;
46 1.1 mrg /* s.* indicates the source array. */
47 1.1 mrg index_type sstride[GFC_MAX_DIMENSIONS];
48 1.1 mrg index_type sstride0;
49 1.1 mrg index_type srank;
50 1.1 mrg const 'rtype_name` *sptr;
51 1.1 mrg
52 1.1 mrg index_type count[GFC_MAX_DIMENSIONS];
53 1.1 mrg index_type extent[GFC_MAX_DIMENSIONS];
54 1.1 mrg index_type n;
55 1.1 mrg index_type dim;
56 1.1 mrg index_type ncopies;
57 1.1 mrg
58 1.1 mrg srank = GFC_DESCRIPTOR_RANK(source);
59 1.1 mrg
60 1.1 mrg rrank = srank + 1;
61 1.1 mrg if (rrank > GFC_MAX_DIMENSIONS)
62 1.1 mrg runtime_error ("return rank too large in spread()");
63 1.1 mrg
64 1.1 mrg if (along > rrank)
65 1.1 mrg runtime_error ("dim outside of rank in spread()");
66 1.1 mrg
67 1.1 mrg ncopies = pncopies;
68 1.1 mrg
69 1.1 mrg if (ret->base_addr == NULL)
70 1.1 mrg {
71 1.1 mrg
72 1.1 mrg size_t ub, stride;
73 1.1 mrg
74 1.1 mrg /* The front end has signalled that we need to populate the
75 1.1 mrg return array descriptor. */
76 1.1 mrg ret->dtype.rank = rrank;
77 1.1 mrg
78 1.1 mrg dim = 0;
79 1.1 mrg rs = 1;
80 1.1 mrg for (n = 0; n < rrank; n++)
81 1.1 mrg {
82 1.1 mrg stride = rs;
83 1.1 mrg if (n == along - 1)
84 1.1 mrg {
85 1.1 mrg ub = ncopies - 1;
86 1.1 mrg rdelta = rs;
87 1.1 mrg rs *= ncopies;
88 1.1 mrg }
89 1.1 mrg else
90 1.1 mrg {
91 1.1 mrg count[dim] = 0;
92 1.1 mrg extent[dim] = GFC_DESCRIPTOR_EXTENT(source,dim);
93 1.1 mrg sstride[dim] = GFC_DESCRIPTOR_STRIDE(source,dim);
94 1.1 mrg rstride[dim] = rs;
95 1.1 mrg
96 1.1 mrg ub = extent[dim] - 1;
97 1.1 mrg rs *= extent[dim];
98 1.1 mrg dim++;
99 1.1 mrg }
100 1.1 mrg GFC_DIMENSION_SET(ret->dim[n], 0, ub, stride);
101 1.1 mrg }
102 1.1 mrg ret->offset = 0;
103 1.1 mrg
104 1.1 mrg /* xmallocarray allocates a single byte for zero size. */
105 1.1 mrg ret->base_addr = xmallocarray (rs, sizeof('rtype_name`));
106 1.1 mrg if (rs <= 0)
107 1.1 mrg return;
108 1.1 mrg }
109 1.1 mrg else
110 1.1 mrg {
111 1.1 mrg int zero_sized;
112 1.1 mrg
113 1.1 mrg zero_sized = 0;
114 1.1 mrg
115 1.1 mrg dim = 0;
116 1.1 mrg if (GFC_DESCRIPTOR_RANK(ret) != rrank)
117 1.1 mrg runtime_error ("rank mismatch in spread()");
118 1.1 mrg
119 1.1 mrg if (unlikely (compile_options.bounds_check))
120 1.1 mrg {
121 1.1 mrg for (n = 0; n < rrank; n++)
122 1.1 mrg {
123 1.1 mrg index_type ret_extent;
124 1.1 mrg
125 1.1 mrg ret_extent = GFC_DESCRIPTOR_EXTENT(ret,n);
126 1.1 mrg if (n == along - 1)
127 1.1 mrg {
128 1.1 mrg rdelta = GFC_DESCRIPTOR_STRIDE(ret,n);
129 1.1 mrg
130 1.1 mrg if (ret_extent != ncopies)
131 1.1 mrg runtime_error("Incorrect extent in return value of SPREAD"
132 1.1 mrg " intrinsic in dimension %ld: is %ld,"
133 1.1 mrg " should be %ld", (long int) n+1,
134 1.1 mrg (long int) ret_extent, (long int) ncopies);
135 1.1 mrg }
136 1.1 mrg else
137 1.1 mrg {
138 1.1 mrg count[dim] = 0;
139 1.1 mrg extent[dim] = GFC_DESCRIPTOR_EXTENT(source,dim);
140 1.1 mrg if (ret_extent != extent[dim])
141 1.1 mrg runtime_error("Incorrect extent in return value of SPREAD"
142 1.1 mrg " intrinsic in dimension %ld: is %ld,"
143 1.1 mrg " should be %ld", (long int) n+1,
144 1.1 mrg (long int) ret_extent,
145 1.1 mrg (long int) extent[dim]);
146 1.1 mrg
147 1.1 mrg if (extent[dim] <= 0)
148 1.1 mrg zero_sized = 1;
149 1.1 mrg sstride[dim] = GFC_DESCRIPTOR_STRIDE(source,dim);
150 1.1 mrg rstride[dim] = GFC_DESCRIPTOR_STRIDE(ret,n);
151 1.1 mrg dim++;
152 1.1 mrg }
153 1.1 mrg }
154 1.1 mrg }
155 1.1 mrg else
156 1.1 mrg {
157 1.1 mrg for (n = 0; n < rrank; n++)
158 1.1 mrg {
159 1.1 mrg if (n == along - 1)
160 1.1 mrg {
161 1.1 mrg rdelta = GFC_DESCRIPTOR_STRIDE(ret,n);
162 1.1 mrg }
163 1.1 mrg else
164 1.1 mrg {
165 1.1 mrg count[dim] = 0;
166 1.1 mrg extent[dim] = GFC_DESCRIPTOR_EXTENT(source,dim);
167 1.1 mrg if (extent[dim] <= 0)
168 1.1 mrg zero_sized = 1;
169 1.1 mrg sstride[dim] = GFC_DESCRIPTOR_STRIDE(source,dim);
170 1.1 mrg rstride[dim] = GFC_DESCRIPTOR_STRIDE(ret,n);
171 1.1 mrg dim++;
172 1.1 mrg }
173 1.1 mrg }
174 1.1 mrg }
175 1.1 mrg
176 1.1 mrg if (zero_sized)
177 1.1 mrg return;
178 1.1 mrg
179 1.1 mrg if (sstride[0] == 0)
180 1.1 mrg sstride[0] = 1;
181 1.1 mrg }
182 1.1 mrg sstride0 = sstride[0];
183 1.1 mrg rstride0 = rstride[0];
184 1.1 mrg rptr = ret->base_addr;
185 1.1 mrg sptr = source->base_addr;
186 1.1 mrg
187 1.1 mrg while (sptr)
188 1.1 mrg {
189 1.1 mrg /* Spread this element. */
190 1.1 mrg dest = rptr;
191 1.1 mrg for (n = 0; n < ncopies; n++)
192 1.1 mrg {
193 1.1 mrg *dest = *sptr;
194 1.1 mrg dest += rdelta;
195 1.1 mrg }
196 1.1 mrg /* Advance to the next element. */
197 1.1 mrg sptr += sstride0;
198 1.1 mrg rptr += rstride0;
199 1.1 mrg count[0]++;
200 1.1 mrg n = 0;
201 1.1 mrg while (count[n] == extent[n])
202 1.1 mrg {
203 1.1 mrg /* When we get to the end of a dimension, reset it and increment
204 1.1 mrg the next dimension. */
205 1.1 mrg count[n] = 0;
206 1.1 mrg /* We could precalculate these products, but this is a less
207 1.1 mrg frequently used path so probably not worth it. */
208 1.1 mrg sptr -= sstride[n] * extent[n];
209 1.1 mrg rptr -= rstride[n] * extent[n];
210 1.1 mrg n++;
211 1.1 mrg if (n >= srank)
212 1.1 mrg {
213 1.1 mrg /* Break out of the loop. */
214 1.1 mrg sptr = NULL;
215 1.1 mrg break;
216 1.1 mrg }
217 1.1 mrg else
218 1.1 mrg {
219 1.1 mrg count[n]++;
220 1.1 mrg sptr += sstride[n];
221 1.1 mrg rptr += rstride[n];
222 1.1 mrg }
223 1.1 mrg }
224 1.1 mrg }
225 1.1 mrg }
226 1.1 mrg
227 1.1 mrg /* This version of spread_internal treats the special case of a scalar
228 1.1 mrg source. This is much simpler than the more general case above. */
229 1.1 mrg
230 1.1 mrg void
231 1.1 mrg spread_scalar_'rtype_code` ('rtype` *ret, const 'rtype_name` *source,
232 1.1 mrg const index_type along, const index_type ncopies)
233 1.1 mrg {
234 1.1 mrg 'rtype_name` * restrict dest;
235 1.1 mrg index_type stride;
236 1.1 mrg
237 1.1 mrg if (GFC_DESCRIPTOR_RANK (ret) != 1)
238 1.1 mrg runtime_error ("incorrect destination rank in spread()");
239 1.1 mrg
240 1.1 mrg if (along > 1)
241 1.1 mrg runtime_error ("dim outside of rank in spread()");
242 1.1 mrg
243 1.1 mrg if (ret->base_addr == NULL)
244 1.1 mrg {
245 1.1 mrg ret->base_addr = xmallocarray (ncopies, sizeof ('rtype_name`));
246 1.1 mrg ret->offset = 0;
247 1.1 mrg GFC_DIMENSION_SET(ret->dim[0], 0, ncopies - 1, 1);
248 1.1 mrg }
249 1.1 mrg else
250 1.1 mrg {
251 1.1 mrg if (ncopies - 1 > (GFC_DESCRIPTOR_EXTENT(ret,0) - 1)
252 1.1 mrg / GFC_DESCRIPTOR_STRIDE(ret,0))
253 1.1 mrg runtime_error ("dim too large in spread()");
254 1.1 mrg }
255 1.1 mrg
256 1.1 mrg dest = ret->base_addr;
257 1.1 mrg stride = GFC_DESCRIPTOR_STRIDE(ret,0);
258 1.1 mrg
259 1.1 mrg for (index_type n = 0; n < ncopies; n++)
260 1.1 mrg {
261 1.1 mrg *dest = *source;
262 1.1 mrg dest += stride;
263 1.1 mrg }
264 1.1 mrg }
265 1.1 mrg
266 1.1 mrg #endif
267 1.1 mrg '
268