1181254a7Smrg /* Implementation of the RESHAPE intrinsic
2*b1e83836Smrg Copyright (C) 2002-2022 Free Software Foundation, Inc.
3181254a7Smrg Contributed by Paul Brook <paul@nowt.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
28181254a7Smrg
29181254a7Smrg #if defined (HAVE_GFC_COMPLEX_4)
30181254a7Smrg
31181254a7Smrg typedef GFC_FULL_ARRAY_DESCRIPTOR(1, index_type) shape_type;
32181254a7Smrg
33181254a7Smrg
34181254a7Smrg extern void reshape_c4 (gfc_array_c4 * const restrict,
35181254a7Smrg gfc_array_c4 * const restrict,
36181254a7Smrg shape_type * const restrict,
37181254a7Smrg gfc_array_c4 * const restrict,
38181254a7Smrg shape_type * const restrict);
39181254a7Smrg export_proto(reshape_c4);
40181254a7Smrg
41181254a7Smrg void
reshape_c4(gfc_array_c4 * const restrict ret,gfc_array_c4 * const restrict source,shape_type * const restrict shape,gfc_array_c4 * const restrict pad,shape_type * const restrict order)42181254a7Smrg reshape_c4 (gfc_array_c4 * const restrict ret,
43181254a7Smrg gfc_array_c4 * const restrict source,
44181254a7Smrg shape_type * const restrict shape,
45181254a7Smrg gfc_array_c4 * const restrict pad,
46181254a7Smrg shape_type * const restrict order)
47181254a7Smrg {
48181254a7Smrg /* r.* indicates the return array. */
49181254a7Smrg index_type rcount[GFC_MAX_DIMENSIONS];
50181254a7Smrg index_type rextent[GFC_MAX_DIMENSIONS];
51181254a7Smrg index_type rstride[GFC_MAX_DIMENSIONS];
52181254a7Smrg index_type rstride0;
53181254a7Smrg index_type rdim;
54181254a7Smrg index_type rsize;
55181254a7Smrg index_type rs;
56181254a7Smrg index_type rex;
57181254a7Smrg GFC_COMPLEX_4 *rptr;
58181254a7Smrg /* s.* indicates the source array. */
59181254a7Smrg index_type scount[GFC_MAX_DIMENSIONS];
60181254a7Smrg index_type sextent[GFC_MAX_DIMENSIONS];
61181254a7Smrg index_type sstride[GFC_MAX_DIMENSIONS];
62181254a7Smrg index_type sstride0;
63181254a7Smrg index_type sdim;
64181254a7Smrg index_type ssize;
65181254a7Smrg const GFC_COMPLEX_4 *sptr;
66181254a7Smrg /* p.* indicates the pad array. */
67181254a7Smrg index_type pcount[GFC_MAX_DIMENSIONS];
68181254a7Smrg index_type pextent[GFC_MAX_DIMENSIONS];
69181254a7Smrg index_type pstride[GFC_MAX_DIMENSIONS];
70181254a7Smrg index_type pdim;
71181254a7Smrg index_type psize;
72181254a7Smrg const GFC_COMPLEX_4 *pptr;
73181254a7Smrg
74181254a7Smrg const GFC_COMPLEX_4 *src;
75181254a7Smrg int sempty, pempty, shape_empty;
76181254a7Smrg index_type shape_data[GFC_MAX_DIMENSIONS];
77181254a7Smrg
78181254a7Smrg rdim = GFC_DESCRIPTOR_EXTENT(shape,0);
79181254a7Smrg /* rdim is always > 0; this lets the compiler optimize more and
80181254a7Smrg avoids a potential warning. */
81181254a7Smrg GFC_ASSERT(rdim>0);
82181254a7Smrg
83181254a7Smrg if (rdim != GFC_DESCRIPTOR_RANK(ret))
84181254a7Smrg runtime_error("rank of return array incorrect in RESHAPE intrinsic");
85181254a7Smrg
86181254a7Smrg shape_empty = 0;
87181254a7Smrg
88181254a7Smrg for (index_type n = 0; n < rdim; n++)
89181254a7Smrg {
90181254a7Smrg shape_data[n] = shape->base_addr[n * GFC_DESCRIPTOR_STRIDE(shape,0)];
91181254a7Smrg if (shape_data[n] <= 0)
92181254a7Smrg {
93181254a7Smrg shape_data[n] = 0;
94181254a7Smrg shape_empty = 1;
95181254a7Smrg }
96181254a7Smrg }
97181254a7Smrg
98181254a7Smrg if (ret->base_addr == NULL)
99181254a7Smrg {
100181254a7Smrg index_type alloc_size;
101181254a7Smrg
102181254a7Smrg rs = 1;
103181254a7Smrg for (index_type n = 0; n < rdim; n++)
104181254a7Smrg {
105181254a7Smrg rex = shape_data[n];
106181254a7Smrg
107181254a7Smrg GFC_DIMENSION_SET(ret->dim[n], 0, rex - 1, rs);
108181254a7Smrg
109181254a7Smrg rs *= rex;
110181254a7Smrg }
111181254a7Smrg ret->offset = 0;
112181254a7Smrg
113181254a7Smrg if (unlikely (rs < 1))
114181254a7Smrg alloc_size = 0;
115181254a7Smrg else
116181254a7Smrg alloc_size = rs;
117181254a7Smrg
118181254a7Smrg ret->base_addr = xmallocarray (alloc_size, sizeof (GFC_COMPLEX_4));
119181254a7Smrg ret->dtype.rank = rdim;
120181254a7Smrg }
121181254a7Smrg
122181254a7Smrg if (shape_empty)
123181254a7Smrg return;
124181254a7Smrg
125181254a7Smrg if (pad)
126181254a7Smrg {
127181254a7Smrg pdim = GFC_DESCRIPTOR_RANK (pad);
128181254a7Smrg psize = 1;
129181254a7Smrg pempty = 0;
130181254a7Smrg for (index_type n = 0; n < pdim; n++)
131181254a7Smrg {
132181254a7Smrg pcount[n] = 0;
133181254a7Smrg pstride[n] = GFC_DESCRIPTOR_STRIDE(pad,n);
134181254a7Smrg pextent[n] = GFC_DESCRIPTOR_EXTENT(pad,n);
135181254a7Smrg if (pextent[n] <= 0)
136181254a7Smrg {
137181254a7Smrg pempty = 1;
138181254a7Smrg pextent[n] = 0;
139181254a7Smrg }
140181254a7Smrg
141181254a7Smrg if (psize == pstride[n])
142181254a7Smrg psize *= pextent[n];
143181254a7Smrg else
144181254a7Smrg psize = 0;
145181254a7Smrg }
146181254a7Smrg pptr = pad->base_addr;
147181254a7Smrg }
148181254a7Smrg else
149181254a7Smrg {
150181254a7Smrg pdim = 0;
151181254a7Smrg psize = 1;
152181254a7Smrg pempty = 1;
153181254a7Smrg pptr = NULL;
154181254a7Smrg }
155181254a7Smrg
156181254a7Smrg if (unlikely (compile_options.bounds_check))
157181254a7Smrg {
158181254a7Smrg index_type ret_extent, source_extent;
159181254a7Smrg
160181254a7Smrg rs = 1;
161181254a7Smrg for (index_type n = 0; n < rdim; n++)
162181254a7Smrg {
163181254a7Smrg rs *= shape_data[n];
164181254a7Smrg ret_extent = GFC_DESCRIPTOR_EXTENT(ret,n);
165181254a7Smrg if (ret_extent != shape_data[n])
166181254a7Smrg runtime_error("Incorrect extent in return value of RESHAPE"
167181254a7Smrg " intrinsic in dimension %ld: is %ld,"
168181254a7Smrg " should be %ld", (long int) n+1,
169181254a7Smrg (long int) ret_extent, (long int) shape_data[n]);
170181254a7Smrg }
171181254a7Smrg
172181254a7Smrg source_extent = 1;
173181254a7Smrg sdim = GFC_DESCRIPTOR_RANK (source);
174181254a7Smrg for (index_type n = 0; n < sdim; n++)
175181254a7Smrg {
176181254a7Smrg index_type se;
177181254a7Smrg se = GFC_DESCRIPTOR_EXTENT(source,n);
178181254a7Smrg source_extent *= se > 0 ? se : 0;
179181254a7Smrg }
180181254a7Smrg
181181254a7Smrg if (rs > source_extent && (!pad || pempty))
182181254a7Smrg runtime_error("Incorrect size in SOURCE argument to RESHAPE"
183181254a7Smrg " intrinsic: is %ld, should be %ld",
184181254a7Smrg (long int) source_extent, (long int) rs);
185181254a7Smrg
186181254a7Smrg if (order)
187181254a7Smrg {
188181254a7Smrg int seen[GFC_MAX_DIMENSIONS];
189181254a7Smrg index_type v;
190181254a7Smrg
191181254a7Smrg for (index_type n = 0; n < rdim; n++)
192181254a7Smrg seen[n] = 0;
193181254a7Smrg
194181254a7Smrg for (index_type n = 0; n < rdim; n++)
195181254a7Smrg {
196181254a7Smrg v = order->base_addr[n * GFC_DESCRIPTOR_STRIDE(order,0)] - 1;
197181254a7Smrg
198181254a7Smrg if (v < 0 || v >= rdim)
199181254a7Smrg runtime_error("Value %ld out of range in ORDER argument"
200181254a7Smrg " to RESHAPE intrinsic", (long int) v + 1);
201181254a7Smrg
202181254a7Smrg if (seen[v] != 0)
203181254a7Smrg runtime_error("Duplicate value %ld in ORDER argument to"
204181254a7Smrg " RESHAPE intrinsic", (long int) v + 1);
205181254a7Smrg
206181254a7Smrg seen[v] = 1;
207181254a7Smrg }
208181254a7Smrg }
209181254a7Smrg }
210181254a7Smrg
211181254a7Smrg rsize = 1;
212181254a7Smrg for (index_type n = 0; n < rdim; n++)
213181254a7Smrg {
214181254a7Smrg index_type dim;
215181254a7Smrg if (order)
216181254a7Smrg dim = order->base_addr[n * GFC_DESCRIPTOR_STRIDE(order,0)] - 1;
217181254a7Smrg else
218181254a7Smrg dim = n;
219181254a7Smrg
220181254a7Smrg rcount[n] = 0;
221181254a7Smrg rstride[n] = GFC_DESCRIPTOR_STRIDE(ret,dim);
222181254a7Smrg rextent[n] = GFC_DESCRIPTOR_EXTENT(ret,dim);
223181254a7Smrg if (rextent[n] < 0)
224181254a7Smrg rextent[n] = 0;
225181254a7Smrg
226181254a7Smrg if (rextent[n] != shape_data[dim])
227181254a7Smrg runtime_error ("shape and target do not conform");
228181254a7Smrg
229181254a7Smrg if (rsize == rstride[n])
230181254a7Smrg rsize *= rextent[n];
231181254a7Smrg else
232181254a7Smrg rsize = 0;
233181254a7Smrg if (rextent[n] <= 0)
234181254a7Smrg return;
235181254a7Smrg }
236181254a7Smrg
237181254a7Smrg sdim = GFC_DESCRIPTOR_RANK (source);
238181254a7Smrg
239181254a7Smrg /* sdim is always > 0; this lets the compiler optimize more and
240181254a7Smrg avoids a warning. */
241181254a7Smrg GFC_ASSERT(sdim>0);
242181254a7Smrg
243181254a7Smrg ssize = 1;
244181254a7Smrg sempty = 0;
245181254a7Smrg for (index_type n = 0; n < sdim; n++)
246181254a7Smrg {
247181254a7Smrg scount[n] = 0;
248181254a7Smrg sstride[n] = GFC_DESCRIPTOR_STRIDE(source,n);
249181254a7Smrg sextent[n] = GFC_DESCRIPTOR_EXTENT(source,n);
250181254a7Smrg if (sextent[n] <= 0)
251181254a7Smrg {
252181254a7Smrg sempty = 1;
253181254a7Smrg sextent[n] = 0;
254181254a7Smrg }
255181254a7Smrg
256181254a7Smrg if (ssize == sstride[n])
257181254a7Smrg ssize *= sextent[n];
258181254a7Smrg else
259181254a7Smrg ssize = 0;
260181254a7Smrg }
261181254a7Smrg
262181254a7Smrg if (rsize != 0 && ssize != 0 && psize != 0)
263181254a7Smrg {
264181254a7Smrg rsize *= sizeof (GFC_COMPLEX_4);
265181254a7Smrg ssize *= sizeof (GFC_COMPLEX_4);
266181254a7Smrg psize *= sizeof (GFC_COMPLEX_4);
267181254a7Smrg reshape_packed ((char *)ret->base_addr, rsize, (char *)source->base_addr,
268181254a7Smrg ssize, pad ? (char *)pad->base_addr : NULL, psize);
269181254a7Smrg return;
270181254a7Smrg }
271181254a7Smrg rptr = ret->base_addr;
272181254a7Smrg src = sptr = source->base_addr;
273181254a7Smrg rstride0 = rstride[0];
274181254a7Smrg sstride0 = sstride[0];
275181254a7Smrg
276181254a7Smrg if (sempty && pempty)
277181254a7Smrg abort ();
278181254a7Smrg
279181254a7Smrg if (sempty)
280181254a7Smrg {
281181254a7Smrg /* Pretend we are using the pad array the first time around, too. */
282181254a7Smrg src = pptr;
283181254a7Smrg sptr = pptr;
284181254a7Smrg sdim = pdim;
285181254a7Smrg for (index_type dim = 0; dim < pdim; dim++)
286181254a7Smrg {
287181254a7Smrg scount[dim] = pcount[dim];
288181254a7Smrg sextent[dim] = pextent[dim];
289181254a7Smrg sstride[dim] = pstride[dim];
290181254a7Smrg sstride0 = pstride[0];
291181254a7Smrg }
292181254a7Smrg }
293181254a7Smrg
294181254a7Smrg while (rptr)
295181254a7Smrg {
296181254a7Smrg /* Select between the source and pad arrays. */
297181254a7Smrg *rptr = *src;
298181254a7Smrg /* Advance to the next element. */
299181254a7Smrg rptr += rstride0;
300181254a7Smrg src += sstride0;
301181254a7Smrg rcount[0]++;
302181254a7Smrg scount[0]++;
303181254a7Smrg
304181254a7Smrg /* Advance to the next destination element. */
305181254a7Smrg index_type n = 0;
306181254a7Smrg while (rcount[n] == rextent[n])
307181254a7Smrg {
308181254a7Smrg /* When we get to the end of a dimension, reset it and increment
309181254a7Smrg the next dimension. */
310181254a7Smrg rcount[n] = 0;
311181254a7Smrg /* We could precalculate these products, but this is a less
312181254a7Smrg frequently used path so probably not worth it. */
313181254a7Smrg rptr -= rstride[n] * rextent[n];
314181254a7Smrg n++;
315181254a7Smrg if (n == rdim)
316181254a7Smrg {
317181254a7Smrg /* Break out of the loop. */
318181254a7Smrg rptr = NULL;
319181254a7Smrg break;
320181254a7Smrg }
321181254a7Smrg else
322181254a7Smrg {
323181254a7Smrg rcount[n]++;
324181254a7Smrg rptr += rstride[n];
325181254a7Smrg }
326181254a7Smrg }
327181254a7Smrg /* Advance to the next source element. */
328181254a7Smrg n = 0;
329181254a7Smrg while (scount[n] == sextent[n])
330181254a7Smrg {
331181254a7Smrg /* When we get to the end of a dimension, reset it and increment
332181254a7Smrg the next dimension. */
333181254a7Smrg scount[n] = 0;
334181254a7Smrg /* We could precalculate these products, but this is a less
335181254a7Smrg frequently used path so probably not worth it. */
336181254a7Smrg src -= sstride[n] * sextent[n];
337181254a7Smrg n++;
338181254a7Smrg if (n == sdim)
339181254a7Smrg {
340181254a7Smrg if (sptr && pad)
341181254a7Smrg {
342181254a7Smrg /* Switch to the pad array. */
343181254a7Smrg sptr = NULL;
344181254a7Smrg sdim = pdim;
345181254a7Smrg for (index_type dim = 0; dim < pdim; dim++)
346181254a7Smrg {
347181254a7Smrg scount[dim] = pcount[dim];
348181254a7Smrg sextent[dim] = pextent[dim];
349181254a7Smrg sstride[dim] = pstride[dim];
350181254a7Smrg sstride0 = sstride[0];
351181254a7Smrg }
352181254a7Smrg }
353181254a7Smrg /* We now start again from the beginning of the pad array. */
354181254a7Smrg src = pptr;
355181254a7Smrg break;
356181254a7Smrg }
357181254a7Smrg else
358181254a7Smrg {
359181254a7Smrg scount[n]++;
360181254a7Smrg src += sstride[n];
361181254a7Smrg }
362181254a7Smrg }
363181254a7Smrg }
364181254a7Smrg }
365181254a7Smrg
366181254a7Smrg #endif
367