1 `/* Implementation of the FINDLOC intrinsic
2 Copyright (C) 2018-2023 Free Software Foundation, Inc.
3 Contributed by Thomas König <tk@tkoenig.net>
5 This file is part of the GNU Fortran 95 runtime library (libgfortran).
7 Libgfortran is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public
9 License as published by the Free Software Foundation; either
10 version 3 of the License, or (at your option) any later version.
12 Libgfortran is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 Under Section 7 of GPL version 3, you are granted additional
18 permissions described in the GCC Runtime Library Exception, version
19 3.1, as published by the Free Software Foundation.
21 You should have received a copy of the GNU General Public License and
22 a copy of the GCC Runtime Library Exception along with this program;
23 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 <http://www.gnu.org/licenses/>. */
26 #include "libgfortran.h"
29 #if defined (HAVE_'atype_name`)
32 index_type count[GFC_MAX_DIMENSIONS];
33 index_type extent[GFC_MAX_DIMENSIONS];
34 index_type sstride[GFC_MAX_DIMENSIONS];
35 index_type dstride[GFC_MAX_DIMENSIONS];
36 const 'atype_name`'` * restrict base;
37 index_type * restrict dest;
45 /* Make dim zero based to avoid confusion. */
46 rank = GFC_DESCRIPTOR_RANK (array) - 1;
49 if (unlikely (dim < 0 || dim > rank))
51 runtime_error ("Dim argument incorrect in FINDLOC intrinsic: "
52 "is %ld, should be between 1 and %ld",
53 (long int) dim + 1, (long int) rank + 1);
56 len = GFC_DESCRIPTOR_EXTENT(array,dim);
59 delta = GFC_DESCRIPTOR_STRIDE(array,dim);
61 for (n = 0; n < dim; n++)
63 sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n);
64 extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
69 for (n = dim; n < rank; n++)
71 sstride[n] = GFC_DESCRIPTOR_STRIDE(array, n + 1);
72 extent[n] = GFC_DESCRIPTOR_EXTENT(array, n + 1);
78 if (retarray->base_addr == NULL)
80 size_t alloc_size, str;
82 for (n = 0; n < rank; n++)
87 str = GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1];
89 GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str);
94 retarray->dtype.rank = rank;
96 alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1];
98 retarray->base_addr = xmallocarray (alloc_size, sizeof (index_type));
104 if (rank != GFC_DESCRIPTOR_RANK (retarray))
105 runtime_error ("rank of return array incorrect in"
106 " FINDLOC intrinsic: is %ld, should be %ld",
107 (long int) (GFC_DESCRIPTOR_RANK (retarray)),
110 if (unlikely (compile_options.bounds_check))
111 bounds_ifunction_return ((array_t *) retarray, extent,
112 "return value", "FINDLOC");
115 for (n = 0; n < rank; n++)
118 dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n);
123 dest = retarray->base_addr;
126 base = array->base_addr;
127 while (continue_loop)
129 const 'atype_name`'` * restrict src;
135 src = base + (len - 1) * delta * 'base_mult`;
136 for (n = len; n > 0; n--, src -= delta * 'base_mult`)
148 for (n = 1; n <= len; n++, src += delta * 'base_mult`)
160 base += sstride[0] * 'base_mult`;
163 while (count[n] == extent[n])
166 base -= sstride[n] * extent[n] * 'base_mult`;
167 dest -= dstride[n] * extent[n];
177 base += sstride[n] * 'base_mult`;
185 index_type count[GFC_MAX_DIMENSIONS];
186 index_type extent[GFC_MAX_DIMENSIONS];
187 index_type sstride[GFC_MAX_DIMENSIONS];
188 index_type mstride[GFC_MAX_DIMENSIONS];
189 index_type dstride[GFC_MAX_DIMENSIONS];
190 const 'atype_name`'` * restrict base;
191 const GFC_LOGICAL_1 * restrict mbase;
192 index_type * restrict dest;
202 /* Make dim zero based to avoid confusion. */
203 rank = GFC_DESCRIPTOR_RANK (array) - 1;
206 if (unlikely (dim < 0 || dim > rank))
208 runtime_error ("Dim argument incorrect in FINDLOC intrinsic: "
209 "is %ld, should be between 1 and %ld",
210 (long int) dim + 1, (long int) rank + 1);
213 len = GFC_DESCRIPTOR_EXTENT(array,dim);
217 delta = GFC_DESCRIPTOR_STRIDE(array,dim);
218 mdelta = GFC_DESCRIPTOR_STRIDE_BYTES(mask,dim);
220 mbase = mask->base_addr;
222 mask_kind = GFC_DESCRIPTOR_SIZE (mask);
224 if (mask_kind == 1 || mask_kind == 2 || mask_kind == 4 || mask_kind == 8
225 #ifdef HAVE_GFC_LOGICAL_16
229 mbase = GFOR_POINTER_TO_L1 (mbase, mask_kind);
231 internal_error (NULL, "Funny sized logical array");
233 for (n = 0; n < dim; n++)
235 sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n);
236 mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n);
237 extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
242 for (n = dim; n < rank; n++)
244 sstride[n] = GFC_DESCRIPTOR_STRIDE(array, n + 1);
245 mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask, n + 1);
246 extent[n] = GFC_DESCRIPTOR_EXTENT(array, n + 1);
252 if (retarray->base_addr == NULL)
254 size_t alloc_size, str;
256 for (n = 0; n < rank; n++)
261 str = GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1];
263 GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str);
267 retarray->offset = 0;
268 retarray->dtype.rank = rank;
270 alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1];
272 retarray->base_addr = xmallocarray (alloc_size, sizeof (index_type));
278 if (rank != GFC_DESCRIPTOR_RANK (retarray))
279 runtime_error ("rank of return array incorrect in"
280 " FINDLOC intrinsic: is %ld, should be %ld",
281 (long int) (GFC_DESCRIPTOR_RANK (retarray)),
284 if (unlikely (compile_options.bounds_check))
285 bounds_ifunction_return ((array_t *) retarray, extent,
286 "return value", "FINDLOC");
289 for (n = 0; n < rank; n++)
292 dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n);
297 dest = retarray->base_addr;
300 base = array->base_addr;
301 while (continue_loop)
303 const 'atype_name`'` * restrict src;
304 const GFC_LOGICAL_1 * restrict msrc;
310 src = base + (len - 1) * delta * 'base_mult`;
311 msrc = mbase + (len - 1) * mdelta;
312 for (n = len; n > 0; n--, src -= delta * 'base_mult`, msrc -= mdelta)
314 if (*msrc && 'comparison`'`)
325 for (n = 1; n <= len; n++, src += delta * 'base_mult`, msrc += mdelta)
327 if (*msrc && 'comparison`'`)
337 base += sstride[0] * 'base_mult`;
341 while (count[n] == extent[n])
344 base -= sstride[n] * extent[n] * 'base_mult`;
345 mbase -= mstride[n] * extent[n];
346 dest -= dstride[n] * extent[n];
356 base += sstride[n] * 'base_mult`;
364 index_type count[GFC_MAX_DIMENSIONS];
365 index_type extent[GFC_MAX_DIMENSIONS];
366 index_type dstride[GFC_MAX_DIMENSIONS];
367 index_type * restrict dest;
374 if (mask == NULL || *mask)
376 findloc1_'atype_code`'` (retarray, array, value, pdim, back'len_arg`'`);
379 /* Make dim zero based to avoid confusion. */
380 rank = GFC_DESCRIPTOR_RANK (array) - 1;
383 if (unlikely (dim < 0 || dim > rank))
385 runtime_error ("Dim argument incorrect in FINDLOC intrinsic: "
386 "is %ld, should be between 1 and %ld",
387 (long int) dim + 1, (long int) rank + 1);
390 len = GFC_DESCRIPTOR_EXTENT(array,dim);
394 for (n = 0; n < dim; n++)
396 extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
402 for (n = dim; n < rank; n++)
405 GFC_DESCRIPTOR_EXTENT(array,n + 1);
412 if (retarray->base_addr == NULL)
414 size_t alloc_size, str;
416 for (n = 0; n < rank; n++)
421 str = GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1];
423 GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str);
426 retarray->offset = 0;
427 retarray->dtype.rank = rank;
429 alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1];
431 retarray->base_addr = xmallocarray (alloc_size, sizeof (index_type));
437 if (rank != GFC_DESCRIPTOR_RANK (retarray))
438 runtime_error ("rank of return array incorrect in"
439 " FINDLOC intrinsic: is %ld, should be %ld",
440 (long int) (GFC_DESCRIPTOR_RANK (retarray)),
443 if (unlikely (compile_options.bounds_check))
444 bounds_ifunction_return ((array_t *) retarray, extent,
445 "return value", "FINDLOC");
448 for (n = 0; n < rank; n++)
451 dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n);
455 dest = retarray->base_addr;
458 while (continue_loop)
465 while (count[n] == extent[n])
468 dest -= dstride[n] * extent[n];