xref: /netbsd-src/external/gpl3/gcc.old/dist/libgfortran/generated/reshape_c4.c (revision 4c3eb207d36f67d31994830c0a694161fc1ca39b)
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