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