]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgfortran/m4/ifunction.m4
2019-06-13 Richard Biener <rguenther@suse.de>
[thirdparty/gcc.git] / libgfortran / m4 / ifunction.m4
CommitLineData
4ee9c684 1dnl Support macro file for intrinsic functions.
2dnl Contains the generic sections of the array functions.
b4ba8232 3dnl This file is part of the GNU Fortran Runtime Library (libgfortran)
b417ea8c 4dnl Distributed under the GNU GPL with exception. See COPYING for details.
4ee9c684 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
cdafa1f6 16dnl atype_name and rtype_name respectively.
4ee9c684 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,
7b6cb5bd 21`
b4cafd67 22extern void name`'rtype_qual`_'atype_code (rtype * const restrict,
cb458068 23 atype` * const restrict, const 'index_type` * const restrict'back_arg`);
24export_proto('name`'rtype_qual`_'atype_code);
7b6cb5bd 25
26void
cb458068 27name`'rtype_qual`_'atype_code` ('rtype` * const restrict retarray,
28 'atype` * const restrict array,
29 const index_type * const restrict pdim'back_arg`)
4ee9c684 30{
9130521e 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];
cb458068 35 const 'atype_name * restrict base;
b4cafd67 36 rtype_name * restrict dest;
4ee9c684 37 index_type rank;
38 index_type n;
39 index_type len;
40 index_type delta;
41 index_type dim;
393a1b6c 42 int continue_loop;
4ee9c684 43
44 /* Make dim zero based to avoid confusion. */
4ee9c684 45 rank = GFC_DESCRIPTOR_RANK (array) - 1;
eab3d206 46 dim = (*pdim) - 1;
73654594 47
3a33b9df 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
827aef63 55 len = GFC_DESCRIPTOR_EXTENT(array,dim);
393a1b6c 56 if (len < 0)
57 len = 0;
827aef63 58 delta = GFC_DESCRIPTOR_STRIDE(array,dim);
4ee9c684 59
60 for (n = 0; n < dim; n++)
61 {
827aef63 62 sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n);
63 extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
a14c06e9 64
65 if (extent[n] < 0)
66 extent[n] = 0;
4ee9c684 67 }
68 for (n = dim; n < rank; n++)
69 {
827aef63 70 sstride[n] = GFC_DESCRIPTOR_STRIDE(array, n + 1);
71 extent[n] = GFC_DESCRIPTOR_EXTENT(array, n + 1);
a14c06e9 72
73 if (extent[n] < 0)
74 extent[n] = 0;
4ee9c684 75 }
76
553877d9 77 if (retarray->base_addr == NULL)
5fcc57ce 78 {
827aef63 79 size_t alloc_size, str;
a14c06e9 80
5fcc57ce 81 for (n = 0; n < rank; n++)
7ebee933 82 {
83 if (n == 0)
827aef63 84 str = 1;
7ebee933 85 else
86 str = GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1];
827aef63 87
88 GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str);
89
7ebee933 90 }
5fcc57ce 91
93830de1 92 retarray->offset = 0;
0bb0be20 93 retarray->dtype.rank = rank;
a14c06e9 94
af1e9051 95 alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1];
a14c06e9 96
af1e9051 97 retarray->base_addr = xmallocarray (alloc_size, sizeof (rtype_name));
a14c06e9 98 if (alloc_size == 0)
99 {
100 /* Make sure we have a zero-sized array. */
827aef63 101 GFC_DIMENSION_SET(retarray->dim[0], 0, -1, 1);
a14c06e9 102 return;
827aef63 103
a14c06e9 104 }
5fcc57ce 105 }
07ea8faa 106 else
107 {
07ea8faa 108 if (rank != GFC_DESCRIPTOR_RANK (retarray))
8dec97a0 109 runtime_error ("rank of return array incorrect in"
ae66f8f3 110 " u_name intrinsic: is %ld, should be %ld",
111 (long int) (GFC_DESCRIPTOR_RANK (retarray)),
112 (long int) rank);
8dec97a0 113
c7fb575f 114 if (unlikely (compile_options.bounds_check))
5d04d450 115 bounds_ifunction_return ((array_t *) retarray, extent,
116 "return value", "u_name");
07ea8faa 117 }
118
4ee9c684 119 for (n = 0; n < rank; n++)
120 {
121 count[n] = 0;
827aef63 122 dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n);
4ee9c684 123 if (extent[n] <= 0)
7cbf86e5 124 return;
4ee9c684 125 }
126
553877d9 127 base = array->base_addr;
128 dest = retarray->base_addr;
4ee9c684 129
393a1b6c 130 continue_loop = 1;
131 while (continue_loop)
4ee9c684 132 {
b4cafd67 133 const atype_name * restrict src;
4ee9c684 134 rtype_name result;
135 src = base;
136 {
137')dnl
138define(START_ARRAY_BLOCK,
7ebee933 139` if (len <= 0)
4ee9c684 140 *dest = '$1`;
141 else
142 {
ca96069a 143#if ! defined HAVE_BACK_ARG
4ee9c684 144 for (n = 0; n < len; n++, src += delta)
145 {
ca96069a 146#endif
4ee9c684 147')dnl
148define(FINISH_ARRAY_FUNCTION,
7ebee933 149` }
b4ba8232 150 '$1`
4ee9c684 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])
7ebee933 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++;
bacde0a1 169 if (n >= rank)
7ebee933 170 {
bacde0a1 171 /* Break out of the loop. */
393a1b6c 172 continue_loop = 0;
173 break;
7ebee933 174 }
175 else
176 {
177 count[n]++;
178 base += sstride[n];
179 dest += dstride[n];
180 }
181 }
4ee9c684 182 }
183}')dnl
184define(START_MASKED_ARRAY_FUNCTION,
7b6cb5bd 185`
cb458068 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`);
7b6cb5bd 190
191void
cb458068 192m'name`'rtype_qual`_'atype_code` ('rtype` * const restrict retarray,
193 'atype` * const restrict array,
b4cafd67 194 const index_type * const restrict pdim,
cb458068 195 gfc_array_l1 * const restrict mask'back_arg`)
4ee9c684 196{
9130521e 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];
cb458068 202 'rtype_name * restrict dest;
b4cafd67 203 const atype_name * restrict base;
7ed8f627 204 const GFC_LOGICAL_1 * restrict mbase;
3a33b9df 205 index_type rank;
206 index_type dim;
4ee9c684 207 index_type n;
208 index_type len;
209 index_type delta;
210 index_type mdelta;
7ed8f627 211 int mask_kind;
4ee9c684 212
538bdcdc 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
4ee9c684 223 dim = (*pdim) - 1;
224 rank = GFC_DESCRIPTOR_RANK (array) - 1;
73654594 225
3a33b9df 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
827aef63 234 len = GFC_DESCRIPTOR_EXTENT(array,dim);
4ee9c684 235 if (len <= 0)
236 return;
7ed8f627 237
553877d9 238 mbase = mask->base_addr;
7ed8f627 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
827aef63 251 delta = GFC_DESCRIPTOR_STRIDE(array,dim);
252 mdelta = GFC_DESCRIPTOR_STRIDE_BYTES(mask,dim);
4ee9c684 253
254 for (n = 0; n < dim; n++)
255 {
827aef63 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);
a14c06e9 259
260 if (extent[n] < 0)
261 extent[n] = 0;
262
4ee9c684 263 }
264 for (n = dim; n < rank; n++)
265 {
827aef63 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);
a14c06e9 269
270 if (extent[n] < 0)
271 extent[n] = 0;
4ee9c684 272 }
273
553877d9 274 if (retarray->base_addr == NULL)
07ea8faa 275 {
827aef63 276 size_t alloc_size, str;
a14c06e9 277
07ea8faa 278 for (n = 0; n < rank; n++)
7ebee933 279 {
280 if (n == 0)
281 str = 1;
282 else
283 str= GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1];
827aef63 284
285 GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str);
286
7ebee933 287 }
07ea8faa 288
af1e9051 289 alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1];
a14c06e9 290
93830de1 291 retarray->offset = 0;
0bb0be20 292 retarray->dtype.rank = rank;
a14c06e9 293
294 if (alloc_size == 0)
295 {
296 /* Make sure we have a zero-sized array. */
827aef63 297 GFC_DIMENSION_SET(retarray->dim[0], 0, -1, 1);
a14c06e9 298 return;
299 }
300 else
af1e9051 301 retarray->base_addr = xmallocarray (alloc_size, sizeof (rtype_name));
a14c06e9 302
07ea8faa 303 }
304 else
305 {
07ea8faa 306 if (rank != GFC_DESCRIPTOR_RANK (retarray))
8dec97a0 307 runtime_error ("rank of return array incorrect in u_name intrinsic");
308
c7fb575f 309 if (unlikely (compile_options.bounds_check))
8dec97a0 310 {
5d04d450 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");
8dec97a0 315 }
07ea8faa 316 }
317
4ee9c684 318 for (n = 0; n < rank; n++)
319 {
320 count[n] = 0;
827aef63 321 dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n);
4ee9c684 322 if (extent[n] <= 0)
7ebee933 323 return;
4ee9c684 324 }
325
553877d9 326 dest = retarray->base_addr;
327 base = array->base_addr;
4ee9c684 328
329 while (base)
330 {
b4cafd67 331 const atype_name * restrict src;
7ed8f627 332 const GFC_LOGICAL_1 * restrict msrc;
4ee9c684 333 rtype_name result;
334 src = base;
335 msrc = mbase;
336 {
337')dnl
338define(START_MASKED_ARRAY_BLOCK,
08e1eb56 339` for (n = 0; n < len; n++, src += delta, msrc += mdelta)
4ee9c684 340 {
4ee9c684 341')dnl
342define(FINISH_MASKED_ARRAY_FUNCTION,
08e1eb56 343` }
344 *dest = result;
4ee9c684 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])
7ebee933 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++;
bacde0a1 363 if (n >= rank)
7ebee933 364 {
bacde0a1 365 /* Break out of the loop. */
7ebee933 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 }
4ee9c684 377 }
378}')dnl
4292b27d 379define(SCALAR_ARRAY_FUNCTION,
380`
cb458068 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);
4292b27d 385
386void
cb458068 387`s'name`'rtype_qual`_'atype_code` ('rtype` * const restrict retarray,
388 'atype` * const restrict array,
4292b27d 389 const index_type * const restrict pdim,
cb458068 390 GFC_LOGICAL_4 * mask'back_arg`)
4292b27d 391{
f955bfc4 392 index_type count[GFC_MAX_DIMENSIONS];
393 index_type extent[GFC_MAX_DIMENSIONS];
f955bfc4 394 index_type dstride[GFC_MAX_DIMENSIONS];
cb458068 395 'rtype_name * restrict dest;
4292b27d 396 index_type rank;
397 index_type n;
f955bfc4 398 index_type dim;
399
4292b27d 400
538bdcdc 401 if (mask == NULL || *mask)
4292b27d 402 {
cb458068 403#ifdef HAVE_BACK_ARG
404 name`'rtype_qual`_'atype_code (retarray, array, pdim, back);
405#else
4292b27d 406 name`'rtype_qual`_'atype_code (retarray, array, pdim);
cb458068 407#endif
4292b27d 408 return;
409 }
f955bfc4 410 /* Make dim zero based to avoid confusion. */
411 dim = (*pdim) - 1;
412 rank = GFC_DESCRIPTOR_RANK (array) - 1;
413
3a33b9df 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
f955bfc4 421 for (n = 0; n < dim; n++)
422 {
827aef63 423 extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
f955bfc4 424
425 if (extent[n] <= 0)
426 extent[n] = 0;
427 }
428
429 for (n = dim; n < rank; n++)
430 {
f955bfc4 431 extent[n] =
7ebee933 432 GFC_DESCRIPTOR_EXTENT(array,n + 1);
f955bfc4 433
434 if (extent[n] <= 0)
7ebee933 435 extent[n] = 0;
f955bfc4 436 }
4292b27d 437
553877d9 438 if (retarray->base_addr == NULL)
4292b27d 439 {
827aef63 440 size_t alloc_size, str;
f955bfc4 441
442 for (n = 0; n < rank; n++)
7ebee933 443 {
444 if (n == 0)
445 str = 1;
446 else
447 str = GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1];
827aef63 448
449 GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str);
450
7ebee933 451 }
f955bfc4 452
4292b27d 453 retarray->offset = 0;
0bb0be20 454 retarray->dtype.rank = rank;
f955bfc4 455
af1e9051 456 alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1];
f955bfc4 457
458 if (alloc_size == 0)
459 {
460 /* Make sure we have a zero-sized array. */
827aef63 461 GFC_DIMENSION_SET(retarray->dim[0], 0, -1, 1);
f955bfc4 462 return;
463 }
464 else
af1e9051 465 retarray->base_addr = xmallocarray (alloc_size, sizeof (rtype_name));
4292b27d 466 }
467 else
468 {
f955bfc4 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
c7fb575f 475 if (unlikely (compile_options.bounds_check))
8dec97a0 476 {
f955bfc4 477 for (n=0; n < rank; n++)
478 {
479 index_type ret_extent;
4292b27d 480
827aef63 481 ret_extent = GFC_DESCRIPTOR_EXTENT(retarray,n);
f955bfc4 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 }
8dec97a0 488 }
489 }
4292b27d 490
f955bfc4 491 for (n = 0; n < rank; n++)
492 {
493 count[n] = 0;
827aef63 494 dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n);
f955bfc4 495 }
496
553877d9 497 dest = retarray->base_addr;
f955bfc4 498
499 while(1)
500 {
501 *dest = '$1`;
502 count[0]++;
503 dest += dstride[0];
504 n = 0;
505 while (count[n] == extent[n])
7ebee933 506 {
f955bfc4 507 /* When we get to the end of a dimension, reset it and increment
7ebee933 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++;
bacde0a1 514 if (n >= rank)
f955bfc4 515 return;
7ebee933 516 else
517 {
518 count[n]++;
519 dest += dstride[n];
520 }
f955bfc4 521 }
522 }
4292b27d 523}')dnl
4ee9c684 524define(ARRAY_FUNCTION,
525`START_ARRAY_FUNCTION
526$2
527START_ARRAY_BLOCK($1)
528$3
b4ba8232 529FINISH_ARRAY_FUNCTION($4)')dnl
4ee9c684 530define(MASKED_ARRAY_FUNCTION,
531`START_MASKED_ARRAY_FUNCTION
532$2
08e1eb56 533START_MASKED_ARRAY_BLOCK
4ee9c684 534$3
535FINISH_MASKED_ARRAY_FUNCTION')dnl