xref: /netbsd-src/external/gpl3/gcc.old/dist/libgfortran/m4/ifunction.m4 (revision 627f7eb200a4419d89b531d55fccd2ee3ffdcde0)
1*627f7eb2Smrgdnl Support macro file for intrinsic functions.
2*627f7eb2Smrgdnl Contains the generic sections of the array functions.
3*627f7eb2Smrgdnl This file is part of the GNU Fortran Runtime Library (libgfortran)
4*627f7eb2Smrgdnl Distributed under the GNU GPL with exception.  See COPYING for details.
5*627f7eb2Smrgdnl
6*627f7eb2Smrgdnl Pass the implementation for a single section as the parameter to
7*627f7eb2Smrgdnl {MASK_}ARRAY_FUNCTION.
8*627f7eb2Smrgdnl The variables base, delta, and len describe the input section.
9*627f7eb2Smrgdnl For masked section the mask is described by mbase and mdelta.
10*627f7eb2Smrgdnl These should not be modified. The result should be stored in *dest.
11*627f7eb2Smrgdnl The names count, extent, sstride, dstride, base, dest, rank, dim
12*627f7eb2Smrgdnl retarray, array, pdim and mstride should not be used.
13*627f7eb2Smrgdnl The variable n is declared as index_type and may be used.
14*627f7eb2Smrgdnl Other variable declarations may be placed at the start of the code,
15*627f7eb2Smrgdnl The types of the array parameter and the return value are
16*627f7eb2Smrgdnl atype_name and rtype_name respectively.
17*627f7eb2Smrgdnl Execution should be allowed to continue to the end of the block.
18*627f7eb2Smrgdnl You should not return or break from the inner loop of the implementation.
19*627f7eb2Smrgdnl Care should also be taken to avoid using the names defined in iparm.m4
20*627f7eb2Smrgdefine(START_ARRAY_FUNCTION,
21*627f7eb2Smrg`
22*627f7eb2Smrgextern void name`'rtype_qual`_'atype_code (rtype * const restrict,
23*627f7eb2Smrg	atype` * const restrict, const 'index_type` * const restrict'back_arg`);
24*627f7eb2Smrgexport_proto('name`'rtype_qual`_'atype_code);
25*627f7eb2Smrg
26*627f7eb2Smrgvoid
27*627f7eb2Smrgname`'rtype_qual`_'atype_code` ('rtype` * const restrict retarray,
28*627f7eb2Smrg	'atype` * const restrict array,
29*627f7eb2Smrg	const index_type * const restrict pdim'back_arg`)
30*627f7eb2Smrg{
31*627f7eb2Smrg  index_type count[GFC_MAX_DIMENSIONS];
32*627f7eb2Smrg  index_type extent[GFC_MAX_DIMENSIONS];
33*627f7eb2Smrg  index_type sstride[GFC_MAX_DIMENSIONS];
34*627f7eb2Smrg  index_type dstride[GFC_MAX_DIMENSIONS];
35*627f7eb2Smrg  const 'atype_name * restrict base;
36*627f7eb2Smrg  rtype_name * restrict dest;
37*627f7eb2Smrg  index_type rank;
38*627f7eb2Smrg  index_type n;
39*627f7eb2Smrg  index_type len;
40*627f7eb2Smrg  index_type delta;
41*627f7eb2Smrg  index_type dim;
42*627f7eb2Smrg  int continue_loop;
43*627f7eb2Smrg
44*627f7eb2Smrg  /* Make dim zero based to avoid confusion.  */
45*627f7eb2Smrg  rank = GFC_DESCRIPTOR_RANK (array) - 1;
46*627f7eb2Smrg  dim = (*pdim) - 1;
47*627f7eb2Smrg
48*627f7eb2Smrg  if (unlikely (dim < 0 || dim > rank))
49*627f7eb2Smrg    {
50*627f7eb2Smrg      runtime_error ("Dim argument incorrect in u_name intrinsic: "
51*627f7eb2Smrg 		     "is %ld, should be between 1 and %ld",
52*627f7eb2Smrg		     (long int) dim + 1, (long int) rank + 1);
53*627f7eb2Smrg    }
54*627f7eb2Smrg
55*627f7eb2Smrg  len = GFC_DESCRIPTOR_EXTENT(array,dim);
56*627f7eb2Smrg  if (len < 0)
57*627f7eb2Smrg    len = 0;
58*627f7eb2Smrg  delta = GFC_DESCRIPTOR_STRIDE(array,dim);
59*627f7eb2Smrg
60*627f7eb2Smrg  for (n = 0; n < dim; n++)
61*627f7eb2Smrg    {
62*627f7eb2Smrg      sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n);
63*627f7eb2Smrg      extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
64*627f7eb2Smrg
65*627f7eb2Smrg      if (extent[n] < 0)
66*627f7eb2Smrg	extent[n] = 0;
67*627f7eb2Smrg    }
68*627f7eb2Smrg  for (n = dim; n < rank; n++)
69*627f7eb2Smrg    {
70*627f7eb2Smrg      sstride[n] = GFC_DESCRIPTOR_STRIDE(array, n + 1);
71*627f7eb2Smrg      extent[n] = GFC_DESCRIPTOR_EXTENT(array, n + 1);
72*627f7eb2Smrg
73*627f7eb2Smrg      if (extent[n] < 0)
74*627f7eb2Smrg	extent[n] = 0;
75*627f7eb2Smrg    }
76*627f7eb2Smrg
77*627f7eb2Smrg  if (retarray->base_addr == NULL)
78*627f7eb2Smrg    {
79*627f7eb2Smrg      size_t alloc_size, str;
80*627f7eb2Smrg
81*627f7eb2Smrg      for (n = 0; n < rank; n++)
82*627f7eb2Smrg	{
83*627f7eb2Smrg	  if (n == 0)
84*627f7eb2Smrg	    str = 1;
85*627f7eb2Smrg	  else
86*627f7eb2Smrg	    str = GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1];
87*627f7eb2Smrg
88*627f7eb2Smrg	  GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str);
89*627f7eb2Smrg
90*627f7eb2Smrg	}
91*627f7eb2Smrg
92*627f7eb2Smrg      retarray->offset = 0;
93*627f7eb2Smrg      retarray->dtype.rank = rank;
94*627f7eb2Smrg
95*627f7eb2Smrg      alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1];
96*627f7eb2Smrg
97*627f7eb2Smrg      retarray->base_addr = xmallocarray (alloc_size, sizeof (rtype_name));
98*627f7eb2Smrg      if (alloc_size == 0)
99*627f7eb2Smrg	{
100*627f7eb2Smrg	  /* Make sure we have a zero-sized array.  */
101*627f7eb2Smrg	  GFC_DIMENSION_SET(retarray->dim[0], 0, -1, 1);
102*627f7eb2Smrg	  return;
103*627f7eb2Smrg
104*627f7eb2Smrg	}
105*627f7eb2Smrg    }
106*627f7eb2Smrg  else
107*627f7eb2Smrg    {
108*627f7eb2Smrg      if (rank != GFC_DESCRIPTOR_RANK (retarray))
109*627f7eb2Smrg	runtime_error ("rank of return array incorrect in"
110*627f7eb2Smrg		       " u_name intrinsic: is %ld, should be %ld",
111*627f7eb2Smrg		       (long int) (GFC_DESCRIPTOR_RANK (retarray)),
112*627f7eb2Smrg		       (long int) rank);
113*627f7eb2Smrg
114*627f7eb2Smrg      if (unlikely (compile_options.bounds_check))
115*627f7eb2Smrg	bounds_ifunction_return ((array_t *) retarray, extent,
116*627f7eb2Smrg				 "return value", "u_name");
117*627f7eb2Smrg    }
118*627f7eb2Smrg
119*627f7eb2Smrg  for (n = 0; n < rank; n++)
120*627f7eb2Smrg    {
121*627f7eb2Smrg      count[n] = 0;
122*627f7eb2Smrg      dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n);
123*627f7eb2Smrg      if (extent[n] <= 0)
124*627f7eb2Smrg	return;
125*627f7eb2Smrg    }
126*627f7eb2Smrg
127*627f7eb2Smrg  base = array->base_addr;
128*627f7eb2Smrg  dest = retarray->base_addr;
129*627f7eb2Smrg
130*627f7eb2Smrg  continue_loop = 1;
131*627f7eb2Smrg  while (continue_loop)
132*627f7eb2Smrg    {
133*627f7eb2Smrg      const atype_name * restrict src;
134*627f7eb2Smrg      rtype_name result;
135*627f7eb2Smrg      src = base;
136*627f7eb2Smrg      {
137*627f7eb2Smrg')dnl
138*627f7eb2Smrgdefine(START_ARRAY_BLOCK,
139*627f7eb2Smrg`	if (len <= 0)
140*627f7eb2Smrg	  *dest = '$1`;
141*627f7eb2Smrg	else
142*627f7eb2Smrg	  {
143*627f7eb2Smrg#if ! defined HAVE_BACK_ARG
144*627f7eb2Smrg	    for (n = 0; n < len; n++, src += delta)
145*627f7eb2Smrg	      {
146*627f7eb2Smrg#endif
147*627f7eb2Smrg')dnl
148*627f7eb2Smrgdefine(FINISH_ARRAY_FUNCTION,
149*627f7eb2Smrg`	      }
150*627f7eb2Smrg	    '$1`
151*627f7eb2Smrg	    *dest = result;
152*627f7eb2Smrg	  }
153*627f7eb2Smrg      }
154*627f7eb2Smrg      /* Advance to the next element.  */
155*627f7eb2Smrg      count[0]++;
156*627f7eb2Smrg      base += sstride[0];
157*627f7eb2Smrg      dest += dstride[0];
158*627f7eb2Smrg      n = 0;
159*627f7eb2Smrg      while (count[n] == extent[n])
160*627f7eb2Smrg	{
161*627f7eb2Smrg	  /* When we get to the end of a dimension, reset it and increment
162*627f7eb2Smrg	     the next dimension.  */
163*627f7eb2Smrg	  count[n] = 0;
164*627f7eb2Smrg	  /* We could precalculate these products, but this is a less
165*627f7eb2Smrg	     frequently used path so probably not worth it.  */
166*627f7eb2Smrg	  base -= sstride[n] * extent[n];
167*627f7eb2Smrg	  dest -= dstride[n] * extent[n];
168*627f7eb2Smrg	  n++;
169*627f7eb2Smrg	  if (n >= rank)
170*627f7eb2Smrg	    {
171*627f7eb2Smrg	      /* Break out of the loop.  */
172*627f7eb2Smrg	      continue_loop = 0;
173*627f7eb2Smrg	      break;
174*627f7eb2Smrg	    }
175*627f7eb2Smrg	  else
176*627f7eb2Smrg	    {
177*627f7eb2Smrg	      count[n]++;
178*627f7eb2Smrg	      base += sstride[n];
179*627f7eb2Smrg	      dest += dstride[n];
180*627f7eb2Smrg	    }
181*627f7eb2Smrg	}
182*627f7eb2Smrg    }
183*627f7eb2Smrg}')dnl
184*627f7eb2Smrgdefine(START_MASKED_ARRAY_FUNCTION,
185*627f7eb2Smrg`
186*627f7eb2Smrgextern void `m'name`'rtype_qual`_'atype_code` ('rtype` * const restrict,
187*627f7eb2Smrg	'atype` * const restrict, const 'index_type` * const restrict,
188*627f7eb2Smrg	gfc_array_l1 * const restrict'back_arg`);
189*627f7eb2Smrgexport_proto(m'name`'rtype_qual`_'atype_code`);
190*627f7eb2Smrg
191*627f7eb2Smrgvoid
192*627f7eb2Smrgm'name`'rtype_qual`_'atype_code` ('rtype` * const restrict retarray,
193*627f7eb2Smrg	'atype` * const restrict array,
194*627f7eb2Smrg	const index_type * const restrict pdim,
195*627f7eb2Smrg	gfc_array_l1 * const restrict mask'back_arg`)
196*627f7eb2Smrg{
197*627f7eb2Smrg  index_type count[GFC_MAX_DIMENSIONS];
198*627f7eb2Smrg  index_type extent[GFC_MAX_DIMENSIONS];
199*627f7eb2Smrg  index_type sstride[GFC_MAX_DIMENSIONS];
200*627f7eb2Smrg  index_type dstride[GFC_MAX_DIMENSIONS];
201*627f7eb2Smrg  index_type mstride[GFC_MAX_DIMENSIONS];
202*627f7eb2Smrg  'rtype_name * restrict dest;
203*627f7eb2Smrg  const atype_name * restrict base;
204*627f7eb2Smrg  const GFC_LOGICAL_1 * restrict mbase;
205*627f7eb2Smrg  index_type rank;
206*627f7eb2Smrg  index_type dim;
207*627f7eb2Smrg  index_type n;
208*627f7eb2Smrg  index_type len;
209*627f7eb2Smrg  index_type delta;
210*627f7eb2Smrg  index_type mdelta;
211*627f7eb2Smrg  int mask_kind;
212*627f7eb2Smrg
213*627f7eb2Smrg  if (mask == NULL)
214*627f7eb2Smrg    {
215*627f7eb2Smrg#ifdef HAVE_BACK_ARG
216*627f7eb2Smrg      name`'rtype_qual`_'atype_code (retarray, array, pdim, back);
217*627f7eb2Smrg#else
218*627f7eb2Smrg      name`'rtype_qual`_'atype_code (retarray, array, pdim);
219*627f7eb2Smrg#endif
220*627f7eb2Smrg      return;
221*627f7eb2Smrg    }
222*627f7eb2Smrg
223*627f7eb2Smrg  dim = (*pdim) - 1;
224*627f7eb2Smrg  rank = GFC_DESCRIPTOR_RANK (array) - 1;
225*627f7eb2Smrg
226*627f7eb2Smrg
227*627f7eb2Smrg  if (unlikely (dim < 0 || dim > rank))
228*627f7eb2Smrg    {
229*627f7eb2Smrg      runtime_error ("Dim argument incorrect in u_name intrinsic: "
230*627f7eb2Smrg 		     "is %ld, should be between 1 and %ld",
231*627f7eb2Smrg		     (long int) dim + 1, (long int) rank + 1);
232*627f7eb2Smrg    }
233*627f7eb2Smrg
234*627f7eb2Smrg  len = GFC_DESCRIPTOR_EXTENT(array,dim);
235*627f7eb2Smrg  if (len <= 0)
236*627f7eb2Smrg    return;
237*627f7eb2Smrg
238*627f7eb2Smrg  mbase = mask->base_addr;
239*627f7eb2Smrg
240*627f7eb2Smrg  mask_kind = GFC_DESCRIPTOR_SIZE (mask);
241*627f7eb2Smrg
242*627f7eb2Smrg  if (mask_kind == 1 || mask_kind == 2 || mask_kind == 4 || mask_kind == 8
243*627f7eb2Smrg#ifdef HAVE_GFC_LOGICAL_16
244*627f7eb2Smrg      || mask_kind == 16
245*627f7eb2Smrg#endif
246*627f7eb2Smrg      )
247*627f7eb2Smrg    mbase = GFOR_POINTER_TO_L1 (mbase, mask_kind);
248*627f7eb2Smrg  else
249*627f7eb2Smrg    runtime_error ("Funny sized logical array");
250*627f7eb2Smrg
251*627f7eb2Smrg  delta = GFC_DESCRIPTOR_STRIDE(array,dim);
252*627f7eb2Smrg  mdelta = GFC_DESCRIPTOR_STRIDE_BYTES(mask,dim);
253*627f7eb2Smrg
254*627f7eb2Smrg  for (n = 0; n < dim; n++)
255*627f7eb2Smrg    {
256*627f7eb2Smrg      sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n);
257*627f7eb2Smrg      mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n);
258*627f7eb2Smrg      extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
259*627f7eb2Smrg
260*627f7eb2Smrg      if (extent[n] < 0)
261*627f7eb2Smrg	extent[n] = 0;
262*627f7eb2Smrg
263*627f7eb2Smrg    }
264*627f7eb2Smrg  for (n = dim; n < rank; n++)
265*627f7eb2Smrg    {
266*627f7eb2Smrg      sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n + 1);
267*627f7eb2Smrg      mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask, n + 1);
268*627f7eb2Smrg      extent[n] = GFC_DESCRIPTOR_EXTENT(array, n + 1);
269*627f7eb2Smrg
270*627f7eb2Smrg      if (extent[n] < 0)
271*627f7eb2Smrg	extent[n] = 0;
272*627f7eb2Smrg    }
273*627f7eb2Smrg
274*627f7eb2Smrg  if (retarray->base_addr == NULL)
275*627f7eb2Smrg    {
276*627f7eb2Smrg      size_t alloc_size, str;
277*627f7eb2Smrg
278*627f7eb2Smrg      for (n = 0; n < rank; n++)
279*627f7eb2Smrg	{
280*627f7eb2Smrg	  if (n == 0)
281*627f7eb2Smrg	    str = 1;
282*627f7eb2Smrg	  else
283*627f7eb2Smrg	    str= GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1];
284*627f7eb2Smrg
285*627f7eb2Smrg	  GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str);
286*627f7eb2Smrg
287*627f7eb2Smrg	}
288*627f7eb2Smrg
289*627f7eb2Smrg      alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1];
290*627f7eb2Smrg
291*627f7eb2Smrg      retarray->offset = 0;
292*627f7eb2Smrg      retarray->dtype.rank = rank;
293*627f7eb2Smrg
294*627f7eb2Smrg      if (alloc_size == 0)
295*627f7eb2Smrg	{
296*627f7eb2Smrg	  /* Make sure we have a zero-sized array.  */
297*627f7eb2Smrg	  GFC_DIMENSION_SET(retarray->dim[0], 0, -1, 1);
298*627f7eb2Smrg	  return;
299*627f7eb2Smrg	}
300*627f7eb2Smrg      else
301*627f7eb2Smrg	retarray->base_addr = xmallocarray (alloc_size, sizeof (rtype_name));
302*627f7eb2Smrg
303*627f7eb2Smrg    }
304*627f7eb2Smrg  else
305*627f7eb2Smrg    {
306*627f7eb2Smrg      if (rank != GFC_DESCRIPTOR_RANK (retarray))
307*627f7eb2Smrg	runtime_error ("rank of return array incorrect in u_name intrinsic");
308*627f7eb2Smrg
309*627f7eb2Smrg      if (unlikely (compile_options.bounds_check))
310*627f7eb2Smrg	{
311*627f7eb2Smrg	  bounds_ifunction_return ((array_t *) retarray, extent,
312*627f7eb2Smrg				   "return value", "u_name");
313*627f7eb2Smrg	  bounds_equal_extents ((array_t *) mask, (array_t *) array,
314*627f7eb2Smrg	  			"MASK argument", "u_name");
315*627f7eb2Smrg	}
316*627f7eb2Smrg    }
317*627f7eb2Smrg
318*627f7eb2Smrg  for (n = 0; n < rank; n++)
319*627f7eb2Smrg    {
320*627f7eb2Smrg      count[n] = 0;
321*627f7eb2Smrg      dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n);
322*627f7eb2Smrg      if (extent[n] <= 0)
323*627f7eb2Smrg	return;
324*627f7eb2Smrg    }
325*627f7eb2Smrg
326*627f7eb2Smrg  dest = retarray->base_addr;
327*627f7eb2Smrg  base = array->base_addr;
328*627f7eb2Smrg
329*627f7eb2Smrg  while (base)
330*627f7eb2Smrg    {
331*627f7eb2Smrg      const atype_name * restrict src;
332*627f7eb2Smrg      const GFC_LOGICAL_1 * restrict msrc;
333*627f7eb2Smrg      rtype_name result;
334*627f7eb2Smrg      src = base;
335*627f7eb2Smrg      msrc = mbase;
336*627f7eb2Smrg      {
337*627f7eb2Smrg')dnl
338*627f7eb2Smrgdefine(START_MASKED_ARRAY_BLOCK,
339*627f7eb2Smrg`	for (n = 0; n < len; n++, src += delta, msrc += mdelta)
340*627f7eb2Smrg	  {
341*627f7eb2Smrg')dnl
342*627f7eb2Smrgdefine(FINISH_MASKED_ARRAY_FUNCTION,
343*627f7eb2Smrg`	  }
344*627f7eb2Smrg	*dest = result;
345*627f7eb2Smrg      }
346*627f7eb2Smrg      /* Advance to the next element.  */
347*627f7eb2Smrg      count[0]++;
348*627f7eb2Smrg      base += sstride[0];
349*627f7eb2Smrg      mbase += mstride[0];
350*627f7eb2Smrg      dest += dstride[0];
351*627f7eb2Smrg      n = 0;
352*627f7eb2Smrg      while (count[n] == extent[n])
353*627f7eb2Smrg	{
354*627f7eb2Smrg	  /* When we get to the end of a dimension, reset it and increment
355*627f7eb2Smrg	     the next dimension.  */
356*627f7eb2Smrg	  count[n] = 0;
357*627f7eb2Smrg	  /* We could precalculate these products, but this is a less
358*627f7eb2Smrg	     frequently used path so probably not worth it.  */
359*627f7eb2Smrg	  base -= sstride[n] * extent[n];
360*627f7eb2Smrg	  mbase -= mstride[n] * extent[n];
361*627f7eb2Smrg	  dest -= dstride[n] * extent[n];
362*627f7eb2Smrg	  n++;
363*627f7eb2Smrg	  if (n >= rank)
364*627f7eb2Smrg	    {
365*627f7eb2Smrg	      /* Break out of the loop.  */
366*627f7eb2Smrg	      base = NULL;
367*627f7eb2Smrg	      break;
368*627f7eb2Smrg	    }
369*627f7eb2Smrg	  else
370*627f7eb2Smrg	    {
371*627f7eb2Smrg	      count[n]++;
372*627f7eb2Smrg	      base += sstride[n];
373*627f7eb2Smrg	      mbase += mstride[n];
374*627f7eb2Smrg	      dest += dstride[n];
375*627f7eb2Smrg	    }
376*627f7eb2Smrg	}
377*627f7eb2Smrg    }
378*627f7eb2Smrg}')dnl
379*627f7eb2Smrgdefine(SCALAR_ARRAY_FUNCTION,
380*627f7eb2Smrg`
381*627f7eb2Smrgextern void `s'name`'rtype_qual`_'atype_code` ('rtype` * const restrict,
382*627f7eb2Smrg	'atype` * const restrict, const index_type * const restrict,
383*627f7eb2Smrg	GFC_LOGICAL_4 *'back_arg`);
384*627f7eb2Smrgexport_proto(s'name`'rtype_qual`_'atype_code);
385*627f7eb2Smrg
386*627f7eb2Smrgvoid
387*627f7eb2Smrg`s'name`'rtype_qual`_'atype_code` ('rtype` * const restrict retarray,
388*627f7eb2Smrg	'atype` * const restrict array,
389*627f7eb2Smrg	const index_type * const restrict pdim,
390*627f7eb2Smrg	GFC_LOGICAL_4 * mask'back_arg`)
391*627f7eb2Smrg{
392*627f7eb2Smrg  index_type count[GFC_MAX_DIMENSIONS];
393*627f7eb2Smrg  index_type extent[GFC_MAX_DIMENSIONS];
394*627f7eb2Smrg  index_type dstride[GFC_MAX_DIMENSIONS];
395*627f7eb2Smrg  'rtype_name * restrict dest;
396*627f7eb2Smrg  index_type rank;
397*627f7eb2Smrg  index_type n;
398*627f7eb2Smrg  index_type dim;
399*627f7eb2Smrg
400*627f7eb2Smrg
401*627f7eb2Smrg  if (mask == NULL || *mask)
402*627f7eb2Smrg    {
403*627f7eb2Smrg#ifdef HAVE_BACK_ARG
404*627f7eb2Smrg      name`'rtype_qual`_'atype_code (retarray, array, pdim, back);
405*627f7eb2Smrg#else
406*627f7eb2Smrg      name`'rtype_qual`_'atype_code (retarray, array, pdim);
407*627f7eb2Smrg#endif
408*627f7eb2Smrg      return;
409*627f7eb2Smrg    }
410*627f7eb2Smrg  /* Make dim zero based to avoid confusion.  */
411*627f7eb2Smrg  dim = (*pdim) - 1;
412*627f7eb2Smrg  rank = GFC_DESCRIPTOR_RANK (array) - 1;
413*627f7eb2Smrg
414*627f7eb2Smrg  if (unlikely (dim < 0 || dim > rank))
415*627f7eb2Smrg    {
416*627f7eb2Smrg      runtime_error ("Dim argument incorrect in u_name intrinsic: "
417*627f7eb2Smrg 		     "is %ld, should be between 1 and %ld",
418*627f7eb2Smrg		     (long int) dim + 1, (long int) rank + 1);
419*627f7eb2Smrg    }
420*627f7eb2Smrg
421*627f7eb2Smrg  for (n = 0; n < dim; n++)
422*627f7eb2Smrg    {
423*627f7eb2Smrg      extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
424*627f7eb2Smrg
425*627f7eb2Smrg      if (extent[n] <= 0)
426*627f7eb2Smrg	extent[n] = 0;
427*627f7eb2Smrg    }
428*627f7eb2Smrg
429*627f7eb2Smrg  for (n = dim; n < rank; n++)
430*627f7eb2Smrg    {
431*627f7eb2Smrg      extent[n] =
432*627f7eb2Smrg	GFC_DESCRIPTOR_EXTENT(array,n + 1);
433*627f7eb2Smrg
434*627f7eb2Smrg      if (extent[n] <= 0)
435*627f7eb2Smrg	extent[n] = 0;
436*627f7eb2Smrg    }
437*627f7eb2Smrg
438*627f7eb2Smrg  if (retarray->base_addr == NULL)
439*627f7eb2Smrg    {
440*627f7eb2Smrg      size_t alloc_size, str;
441*627f7eb2Smrg
442*627f7eb2Smrg      for (n = 0; n < rank; n++)
443*627f7eb2Smrg	{
444*627f7eb2Smrg	  if (n == 0)
445*627f7eb2Smrg	    str = 1;
446*627f7eb2Smrg	  else
447*627f7eb2Smrg	    str = GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1];
448*627f7eb2Smrg
449*627f7eb2Smrg	  GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str);
450*627f7eb2Smrg
451*627f7eb2Smrg	}
452*627f7eb2Smrg
453*627f7eb2Smrg      retarray->offset = 0;
454*627f7eb2Smrg      retarray->dtype.rank = rank;
455*627f7eb2Smrg
456*627f7eb2Smrg      alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1];
457*627f7eb2Smrg
458*627f7eb2Smrg      if (alloc_size == 0)
459*627f7eb2Smrg	{
460*627f7eb2Smrg	  /* Make sure we have a zero-sized array.  */
461*627f7eb2Smrg	  GFC_DIMENSION_SET(retarray->dim[0], 0, -1, 1);
462*627f7eb2Smrg	  return;
463*627f7eb2Smrg	}
464*627f7eb2Smrg      else
465*627f7eb2Smrg	retarray->base_addr = xmallocarray (alloc_size, sizeof (rtype_name));
466*627f7eb2Smrg    }
467*627f7eb2Smrg  else
468*627f7eb2Smrg    {
469*627f7eb2Smrg      if (rank != GFC_DESCRIPTOR_RANK (retarray))
470*627f7eb2Smrg	runtime_error ("rank of return array incorrect in"
471*627f7eb2Smrg		       " u_name intrinsic: is %ld, should be %ld",
472*627f7eb2Smrg		       (long int) (GFC_DESCRIPTOR_RANK (retarray)),
473*627f7eb2Smrg		       (long int) rank);
474*627f7eb2Smrg
475*627f7eb2Smrg      if (unlikely (compile_options.bounds_check))
476*627f7eb2Smrg	{
477*627f7eb2Smrg	  for (n=0; n < rank; n++)
478*627f7eb2Smrg	    {
479*627f7eb2Smrg	      index_type ret_extent;
480*627f7eb2Smrg
481*627f7eb2Smrg	      ret_extent = GFC_DESCRIPTOR_EXTENT(retarray,n);
482*627f7eb2Smrg	      if (extent[n] != ret_extent)
483*627f7eb2Smrg		runtime_error ("Incorrect extent in return value of"
484*627f7eb2Smrg			       " u_name intrinsic in dimension %ld:"
485*627f7eb2Smrg			       " is %ld, should be %ld", (long int) n + 1,
486*627f7eb2Smrg			       (long int) ret_extent, (long int) extent[n]);
487*627f7eb2Smrg	    }
488*627f7eb2Smrg	}
489*627f7eb2Smrg    }
490*627f7eb2Smrg
491*627f7eb2Smrg  for (n = 0; n < rank; n++)
492*627f7eb2Smrg    {
493*627f7eb2Smrg      count[n] = 0;
494*627f7eb2Smrg      dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n);
495*627f7eb2Smrg    }
496*627f7eb2Smrg
497*627f7eb2Smrg  dest = retarray->base_addr;
498*627f7eb2Smrg
499*627f7eb2Smrg  while(1)
500*627f7eb2Smrg    {
501*627f7eb2Smrg      *dest = '$1`;
502*627f7eb2Smrg      count[0]++;
503*627f7eb2Smrg      dest += dstride[0];
504*627f7eb2Smrg      n = 0;
505*627f7eb2Smrg      while (count[n] == extent[n])
506*627f7eb2Smrg	{
507*627f7eb2Smrg	  /* When we get to the end of a dimension, reset it and increment
508*627f7eb2Smrg	     the next dimension.  */
509*627f7eb2Smrg	  count[n] = 0;
510*627f7eb2Smrg	  /* We could precalculate these products, but this is a less
511*627f7eb2Smrg	     frequently used path so probably not worth it.  */
512*627f7eb2Smrg	  dest -= dstride[n] * extent[n];
513*627f7eb2Smrg	  n++;
514*627f7eb2Smrg	  if (n >= rank)
515*627f7eb2Smrg	    return;
516*627f7eb2Smrg	  else
517*627f7eb2Smrg	    {
518*627f7eb2Smrg	      count[n]++;
519*627f7eb2Smrg	      dest += dstride[n];
520*627f7eb2Smrg	    }
521*627f7eb2Smrg      	}
522*627f7eb2Smrg    }
523*627f7eb2Smrg}')dnl
524*627f7eb2Smrgdefine(ARRAY_FUNCTION,
525*627f7eb2Smrg`START_ARRAY_FUNCTION
526*627f7eb2Smrg$2
527*627f7eb2SmrgSTART_ARRAY_BLOCK($1)
528*627f7eb2Smrg$3
529*627f7eb2SmrgFINISH_ARRAY_FUNCTION($4)')dnl
530*627f7eb2Smrgdefine(MASKED_ARRAY_FUNCTION,
531*627f7eb2Smrg`START_MASKED_ARRAY_FUNCTION
532*627f7eb2Smrg$2
533*627f7eb2SmrgSTART_MASKED_ARRAY_BLOCK
534*627f7eb2Smrg$3
535*627f7eb2SmrgFINISH_MASKED_ARRAY_FUNCTION')dnl
536