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