1627f7eb2Smrg /* Implementation of the RESHAPE intrinsic
2*4c3eb207Smrg Copyright (C) 2002-2020 Free Software Foundation, Inc.
3627f7eb2Smrg Contributed by Paul Brook <paul@nowt.org>
4627f7eb2Smrg
5627f7eb2Smrg This file is part of the GNU Fortran runtime library (libgfortran).
6627f7eb2Smrg
7627f7eb2Smrg Libgfortran is free software; you can redistribute it and/or
8627f7eb2Smrg modify it under the terms of the GNU General Public
9627f7eb2Smrg License as published by the Free Software Foundation; either
10627f7eb2Smrg version 3 of the License, or (at your option) any later version.
11627f7eb2Smrg
12627f7eb2Smrg Libgfortran is distributed in the hope that it will be useful,
13627f7eb2Smrg but WITHOUT ANY WARRANTY; without even the implied warranty of
14627f7eb2Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15627f7eb2Smrg GNU General Public License for more details.
16627f7eb2Smrg
17627f7eb2Smrg Under Section 7 of GPL version 3, you are granted additional
18627f7eb2Smrg permissions described in the GCC Runtime Library Exception, version
19627f7eb2Smrg 3.1, as published by the Free Software Foundation.
20627f7eb2Smrg
21627f7eb2Smrg You should have received a copy of the GNU General Public License and
22627f7eb2Smrg a copy of the GCC Runtime Library Exception along with this program;
23627f7eb2Smrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24627f7eb2Smrg <http://www.gnu.org/licenses/>. */
25627f7eb2Smrg
26627f7eb2Smrg #include "libgfortran.h"
27627f7eb2Smrg
28627f7eb2Smrg
29627f7eb2Smrg #if defined (HAVE_GFC_COMPLEX_4)
30627f7eb2Smrg
31627f7eb2Smrg typedef GFC_FULL_ARRAY_DESCRIPTOR(1, index_type) shape_type;
32627f7eb2Smrg
33627f7eb2Smrg
34627f7eb2Smrg extern void reshape_c4 (gfc_array_c4 * const restrict,
35627f7eb2Smrg gfc_array_c4 * const restrict,
36627f7eb2Smrg shape_type * const restrict,
37627f7eb2Smrg gfc_array_c4 * const restrict,
38627f7eb2Smrg shape_type * const restrict);
39627f7eb2Smrg export_proto(reshape_c4);
40627f7eb2Smrg
41627f7eb2Smrg 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)42627f7eb2Smrg reshape_c4 (gfc_array_c4 * const restrict ret,
43627f7eb2Smrg gfc_array_c4 * const restrict source,
44627f7eb2Smrg shape_type * const restrict shape,
45627f7eb2Smrg gfc_array_c4 * const restrict pad,
46627f7eb2Smrg shape_type * const restrict order)
47627f7eb2Smrg {
48627f7eb2Smrg /* r.* indicates the return array. */
49627f7eb2Smrg index_type rcount[GFC_MAX_DIMENSIONS];
50627f7eb2Smrg index_type rextent[GFC_MAX_DIMENSIONS];
51627f7eb2Smrg index_type rstride[GFC_MAX_DIMENSIONS];
52627f7eb2Smrg index_type rstride0;
53627f7eb2Smrg index_type rdim;
54627f7eb2Smrg index_type rsize;
55627f7eb2Smrg index_type rs;
56627f7eb2Smrg index_type rex;
57627f7eb2Smrg GFC_COMPLEX_4 *rptr;
58627f7eb2Smrg /* s.* indicates the source array. */
59627f7eb2Smrg index_type scount[GFC_MAX_DIMENSIONS];
60627f7eb2Smrg index_type sextent[GFC_MAX_DIMENSIONS];
61627f7eb2Smrg index_type sstride[GFC_MAX_DIMENSIONS];
62627f7eb2Smrg index_type sstride0;
63627f7eb2Smrg index_type sdim;
64627f7eb2Smrg index_type ssize;
65627f7eb2Smrg const GFC_COMPLEX_4 *sptr;
66627f7eb2Smrg /* p.* indicates the pad array. */
67627f7eb2Smrg index_type pcount[GFC_MAX_DIMENSIONS];
68627f7eb2Smrg index_type pextent[GFC_MAX_DIMENSIONS];
69627f7eb2Smrg index_type pstride[GFC_MAX_DIMENSIONS];
70627f7eb2Smrg index_type pdim;
71627f7eb2Smrg index_type psize;
72627f7eb2Smrg const GFC_COMPLEX_4 *pptr;
73627f7eb2Smrg
74627f7eb2Smrg const GFC_COMPLEX_4 *src;
75627f7eb2Smrg int sempty, pempty, shape_empty;
76627f7eb2Smrg index_type shape_data[GFC_MAX_DIMENSIONS];
77627f7eb2Smrg
78627f7eb2Smrg rdim = GFC_DESCRIPTOR_EXTENT(shape,0);
79627f7eb2Smrg /* rdim is always > 0; this lets the compiler optimize more and
80627f7eb2Smrg avoids a potential warning. */
81627f7eb2Smrg GFC_ASSERT(rdim>0);
82627f7eb2Smrg
83627f7eb2Smrg if (rdim != GFC_DESCRIPTOR_RANK(ret))
84627f7eb2Smrg runtime_error("rank of return array incorrect in RESHAPE intrinsic");
85627f7eb2Smrg
86627f7eb2Smrg shape_empty = 0;
87627f7eb2Smrg
88627f7eb2Smrg for (index_type n = 0; n < rdim; n++)
89627f7eb2Smrg {
90627f7eb2Smrg shape_data[n] = shape->base_addr[n * GFC_DESCRIPTOR_STRIDE(shape,0)];
91627f7eb2Smrg if (shape_data[n] <= 0)
92627f7eb2Smrg {
93627f7eb2Smrg shape_data[n] = 0;
94627f7eb2Smrg shape_empty = 1;
95627f7eb2Smrg }
96627f7eb2Smrg }
97627f7eb2Smrg
98627f7eb2Smrg if (ret->base_addr == NULL)
99627f7eb2Smrg {
100627f7eb2Smrg index_type alloc_size;
101627f7eb2Smrg
102627f7eb2Smrg rs = 1;
103627f7eb2Smrg for (index_type n = 0; n < rdim; n++)
104627f7eb2Smrg {
105627f7eb2Smrg rex = shape_data[n];
106627f7eb2Smrg
107627f7eb2Smrg GFC_DIMENSION_SET(ret->dim[n], 0, rex - 1, rs);
108627f7eb2Smrg
109627f7eb2Smrg rs *= rex;
110627f7eb2Smrg }
111627f7eb2Smrg ret->offset = 0;
112627f7eb2Smrg
113627f7eb2Smrg if (unlikely (rs < 1))
114627f7eb2Smrg alloc_size = 0;
115627f7eb2Smrg else
116627f7eb2Smrg alloc_size = rs;
117627f7eb2Smrg
118627f7eb2Smrg ret->base_addr = xmallocarray (alloc_size, sizeof (GFC_COMPLEX_4));
119627f7eb2Smrg ret->dtype.rank = rdim;
120627f7eb2Smrg }
121627f7eb2Smrg
122627f7eb2Smrg if (shape_empty)
123627f7eb2Smrg return;
124627f7eb2Smrg
125627f7eb2Smrg if (pad)
126627f7eb2Smrg {
127627f7eb2Smrg pdim = GFC_DESCRIPTOR_RANK (pad);
128627f7eb2Smrg psize = 1;
129627f7eb2Smrg pempty = 0;
130627f7eb2Smrg for (index_type n = 0; n < pdim; n++)
131627f7eb2Smrg {
132627f7eb2Smrg pcount[n] = 0;
133627f7eb2Smrg pstride[n] = GFC_DESCRIPTOR_STRIDE(pad,n);
134627f7eb2Smrg pextent[n] = GFC_DESCRIPTOR_EXTENT(pad,n);
135627f7eb2Smrg if (pextent[n] <= 0)
136627f7eb2Smrg {
137627f7eb2Smrg pempty = 1;
138627f7eb2Smrg pextent[n] = 0;
139627f7eb2Smrg }
140627f7eb2Smrg
141627f7eb2Smrg if (psize == pstride[n])
142627f7eb2Smrg psize *= pextent[n];
143627f7eb2Smrg else
144627f7eb2Smrg psize = 0;
145627f7eb2Smrg }
146627f7eb2Smrg pptr = pad->base_addr;
147627f7eb2Smrg }
148627f7eb2Smrg else
149627f7eb2Smrg {
150627f7eb2Smrg pdim = 0;
151627f7eb2Smrg psize = 1;
152627f7eb2Smrg pempty = 1;
153627f7eb2Smrg pptr = NULL;
154627f7eb2Smrg }
155627f7eb2Smrg
156627f7eb2Smrg if (unlikely (compile_options.bounds_check))
157627f7eb2Smrg {
158627f7eb2Smrg index_type ret_extent, source_extent;
159627f7eb2Smrg
160627f7eb2Smrg rs = 1;
161627f7eb2Smrg for (index_type n = 0; n < rdim; n++)
162627f7eb2Smrg {
163627f7eb2Smrg rs *= shape_data[n];
164627f7eb2Smrg ret_extent = GFC_DESCRIPTOR_EXTENT(ret,n);
165627f7eb2Smrg if (ret_extent != shape_data[n])
166627f7eb2Smrg runtime_error("Incorrect extent in return value of RESHAPE"
167627f7eb2Smrg " intrinsic in dimension %ld: is %ld,"
168627f7eb2Smrg " should be %ld", (long int) n+1,
169627f7eb2Smrg (long int) ret_extent, (long int) shape_data[n]);
170627f7eb2Smrg }
171627f7eb2Smrg
172627f7eb2Smrg source_extent = 1;
173627f7eb2Smrg sdim = GFC_DESCRIPTOR_RANK (source);
174627f7eb2Smrg for (index_type n = 0; n < sdim; n++)
175627f7eb2Smrg {
176627f7eb2Smrg index_type se;
177627f7eb2Smrg se = GFC_DESCRIPTOR_EXTENT(source,n);
178627f7eb2Smrg source_extent *= se > 0 ? se : 0;
179627f7eb2Smrg }
180627f7eb2Smrg
181627f7eb2Smrg if (rs > source_extent && (!pad || pempty))
182627f7eb2Smrg runtime_error("Incorrect size in SOURCE argument to RESHAPE"
183627f7eb2Smrg " intrinsic: is %ld, should be %ld",
184627f7eb2Smrg (long int) source_extent, (long int) rs);
185627f7eb2Smrg
186627f7eb2Smrg if (order)
187627f7eb2Smrg {
188627f7eb2Smrg int seen[GFC_MAX_DIMENSIONS];
189627f7eb2Smrg index_type v;
190627f7eb2Smrg
191627f7eb2Smrg for (index_type n = 0; n < rdim; n++)
192627f7eb2Smrg seen[n] = 0;
193627f7eb2Smrg
194627f7eb2Smrg for (index_type n = 0; n < rdim; n++)
195627f7eb2Smrg {
196627f7eb2Smrg v = order->base_addr[n * GFC_DESCRIPTOR_STRIDE(order,0)] - 1;
197627f7eb2Smrg
198627f7eb2Smrg if (v < 0 || v >= rdim)
199627f7eb2Smrg runtime_error("Value %ld out of range in ORDER argument"
200627f7eb2Smrg " to RESHAPE intrinsic", (long int) v + 1);
201627f7eb2Smrg
202627f7eb2Smrg if (seen[v] != 0)
203627f7eb2Smrg runtime_error("Duplicate value %ld in ORDER argument to"
204627f7eb2Smrg " RESHAPE intrinsic", (long int) v + 1);
205627f7eb2Smrg
206627f7eb2Smrg seen[v] = 1;
207627f7eb2Smrg }
208627f7eb2Smrg }
209627f7eb2Smrg }
210627f7eb2Smrg
211627f7eb2Smrg rsize = 1;
212627f7eb2Smrg for (index_type n = 0; n < rdim; n++)
213627f7eb2Smrg {
214627f7eb2Smrg index_type dim;
215627f7eb2Smrg if (order)
216627f7eb2Smrg dim = order->base_addr[n * GFC_DESCRIPTOR_STRIDE(order,0)] - 1;
217627f7eb2Smrg else
218627f7eb2Smrg dim = n;
219627f7eb2Smrg
220627f7eb2Smrg rcount[n] = 0;
221627f7eb2Smrg rstride[n] = GFC_DESCRIPTOR_STRIDE(ret,dim);
222627f7eb2Smrg rextent[n] = GFC_DESCRIPTOR_EXTENT(ret,dim);
223627f7eb2Smrg if (rextent[n] < 0)
224627f7eb2Smrg rextent[n] = 0;
225627f7eb2Smrg
226627f7eb2Smrg if (rextent[n] != shape_data[dim])
227627f7eb2Smrg runtime_error ("shape and target do not conform");
228627f7eb2Smrg
229627f7eb2Smrg if (rsize == rstride[n])
230627f7eb2Smrg rsize *= rextent[n];
231627f7eb2Smrg else
232627f7eb2Smrg rsize = 0;
233627f7eb2Smrg if (rextent[n] <= 0)
234627f7eb2Smrg return;
235627f7eb2Smrg }
236627f7eb2Smrg
237627f7eb2Smrg sdim = GFC_DESCRIPTOR_RANK (source);
238627f7eb2Smrg
239627f7eb2Smrg /* sdim is always > 0; this lets the compiler optimize more and
240627f7eb2Smrg avoids a warning. */
241627f7eb2Smrg GFC_ASSERT(sdim>0);
242627f7eb2Smrg
243627f7eb2Smrg ssize = 1;
244627f7eb2Smrg sempty = 0;
245627f7eb2Smrg for (index_type n = 0; n < sdim; n++)
246627f7eb2Smrg {
247627f7eb2Smrg scount[n] = 0;
248627f7eb2Smrg sstride[n] = GFC_DESCRIPTOR_STRIDE(source,n);
249627f7eb2Smrg sextent[n] = GFC_DESCRIPTOR_EXTENT(source,n);
250627f7eb2Smrg if (sextent[n] <= 0)
251627f7eb2Smrg {
252627f7eb2Smrg sempty = 1;
253627f7eb2Smrg sextent[n] = 0;
254627f7eb2Smrg }
255627f7eb2Smrg
256627f7eb2Smrg if (ssize == sstride[n])
257627f7eb2Smrg ssize *= sextent[n];
258627f7eb2Smrg else
259627f7eb2Smrg ssize = 0;
260627f7eb2Smrg }
261627f7eb2Smrg
262627f7eb2Smrg if (rsize != 0 && ssize != 0 && psize != 0)
263627f7eb2Smrg {
264627f7eb2Smrg rsize *= sizeof (GFC_COMPLEX_4);
265627f7eb2Smrg ssize *= sizeof (GFC_COMPLEX_4);
266627f7eb2Smrg psize *= sizeof (GFC_COMPLEX_4);
267627f7eb2Smrg reshape_packed ((char *)ret->base_addr, rsize, (char *)source->base_addr,
268627f7eb2Smrg ssize, pad ? (char *)pad->base_addr : NULL, psize);
269627f7eb2Smrg return;
270627f7eb2Smrg }
271627f7eb2Smrg rptr = ret->base_addr;
272627f7eb2Smrg src = sptr = source->base_addr;
273627f7eb2Smrg rstride0 = rstride[0];
274627f7eb2Smrg sstride0 = sstride[0];
275627f7eb2Smrg
276627f7eb2Smrg if (sempty && pempty)
277627f7eb2Smrg abort ();
278627f7eb2Smrg
279627f7eb2Smrg if (sempty)
280627f7eb2Smrg {
281627f7eb2Smrg /* Pretend we are using the pad array the first time around, too. */
282627f7eb2Smrg src = pptr;
283627f7eb2Smrg sptr = pptr;
284627f7eb2Smrg sdim = pdim;
285627f7eb2Smrg for (index_type dim = 0; dim < pdim; dim++)
286627f7eb2Smrg {
287627f7eb2Smrg scount[dim] = pcount[dim];
288627f7eb2Smrg sextent[dim] = pextent[dim];
289627f7eb2Smrg sstride[dim] = pstride[dim];
290627f7eb2Smrg sstride0 = pstride[0];
291627f7eb2Smrg }
292627f7eb2Smrg }
293627f7eb2Smrg
294627f7eb2Smrg while (rptr)
295627f7eb2Smrg {
296627f7eb2Smrg /* Select between the source and pad arrays. */
297627f7eb2Smrg *rptr = *src;
298627f7eb2Smrg /* Advance to the next element. */
299627f7eb2Smrg rptr += rstride0;
300627f7eb2Smrg src += sstride0;
301627f7eb2Smrg rcount[0]++;
302627f7eb2Smrg scount[0]++;
303627f7eb2Smrg
304627f7eb2Smrg /* Advance to the next destination element. */
305627f7eb2Smrg index_type n = 0;
306627f7eb2Smrg while (rcount[n] == rextent[n])
307627f7eb2Smrg {
308627f7eb2Smrg /* When we get to the end of a dimension, reset it and increment
309627f7eb2Smrg the next dimension. */
310627f7eb2Smrg rcount[n] = 0;
311627f7eb2Smrg /* We could precalculate these products, but this is a less
312627f7eb2Smrg frequently used path so probably not worth it. */
313627f7eb2Smrg rptr -= rstride[n] * rextent[n];
314627f7eb2Smrg n++;
315627f7eb2Smrg if (n == rdim)
316627f7eb2Smrg {
317627f7eb2Smrg /* Break out of the loop. */
318627f7eb2Smrg rptr = NULL;
319627f7eb2Smrg break;
320627f7eb2Smrg }
321627f7eb2Smrg else
322627f7eb2Smrg {
323627f7eb2Smrg rcount[n]++;
324627f7eb2Smrg rptr += rstride[n];
325627f7eb2Smrg }
326627f7eb2Smrg }
327627f7eb2Smrg /* Advance to the next source element. */
328627f7eb2Smrg n = 0;
329627f7eb2Smrg while (scount[n] == sextent[n])
330627f7eb2Smrg {
331627f7eb2Smrg /* When we get to the end of a dimension, reset it and increment
332627f7eb2Smrg the next dimension. */
333627f7eb2Smrg scount[n] = 0;
334627f7eb2Smrg /* We could precalculate these products, but this is a less
335627f7eb2Smrg frequently used path so probably not worth it. */
336627f7eb2Smrg src -= sstride[n] * sextent[n];
337627f7eb2Smrg n++;
338627f7eb2Smrg if (n == sdim)
339627f7eb2Smrg {
340627f7eb2Smrg if (sptr && pad)
341627f7eb2Smrg {
342627f7eb2Smrg /* Switch to the pad array. */
343627f7eb2Smrg sptr = NULL;
344627f7eb2Smrg sdim = pdim;
345627f7eb2Smrg for (index_type dim = 0; dim < pdim; dim++)
346627f7eb2Smrg {
347627f7eb2Smrg scount[dim] = pcount[dim];
348627f7eb2Smrg sextent[dim] = pextent[dim];
349627f7eb2Smrg sstride[dim] = pstride[dim];
350627f7eb2Smrg sstride0 = sstride[0];
351627f7eb2Smrg }
352627f7eb2Smrg }
353627f7eb2Smrg /* We now start again from the beginning of the pad array. */
354627f7eb2Smrg src = pptr;
355627f7eb2Smrg break;
356627f7eb2Smrg }
357627f7eb2Smrg else
358627f7eb2Smrg {
359627f7eb2Smrg scount[n]++;
360627f7eb2Smrg src += sstride[n];
361627f7eb2Smrg }
362627f7eb2Smrg }
363627f7eb2Smrg }
364627f7eb2Smrg }
365627f7eb2Smrg
366627f7eb2Smrg #endif
367