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