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