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