1*b1e83836Smrg
2*b1e83836Smrg /* Implementation of the FINDLOC intrinsic
3*b1e83836Smrg Copyright (C) 2018-2022 Free Software Foundation, Inc.
4*b1e83836Smrg Contributed by Thomas König <tk@tkoenig.net>
5*b1e83836Smrg
6*b1e83836Smrg This file is part of the GNU Fortran 95 runtime library (libgfortran).
7*b1e83836Smrg
8*b1e83836Smrg Libgfortran is free software; you can redistribute it and/or
9*b1e83836Smrg modify it under the terms of the GNU General Public
10*b1e83836Smrg License as published by the Free Software Foundation; either
11*b1e83836Smrg version 3 of the License, or (at your option) any later version.
12*b1e83836Smrg
13*b1e83836Smrg Libgfortran is distributed in the hope that it will be useful,
14*b1e83836Smrg but WITHOUT ANY WARRANTY; without even the implied warranty of
15*b1e83836Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16*b1e83836Smrg GNU General Public License for more details.
17*b1e83836Smrg
18*b1e83836Smrg Under Section 7 of GPL version 3, you are granted additional
19*b1e83836Smrg permissions described in the GCC Runtime Library Exception, version
20*b1e83836Smrg 3.1, as published by the Free Software Foundation.
21*b1e83836Smrg
22*b1e83836Smrg You should have received a copy of the GNU General Public License and
23*b1e83836Smrg a copy of the GCC Runtime Library Exception along with this program;
24*b1e83836Smrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25*b1e83836Smrg <http://www.gnu.org/licenses/>. */
26*b1e83836Smrg
27*b1e83836Smrg #include "libgfortran.h"
28*b1e83836Smrg #include <assert.h>
29*b1e83836Smrg
30*b1e83836Smrg #if defined (HAVE_GFC_REAL_17)
31*b1e83836Smrg extern void findloc0_r17 (gfc_array_index_type * const restrict retarray,
32*b1e83836Smrg gfc_array_r17 * const restrict array, GFC_REAL_17 value,
33*b1e83836Smrg GFC_LOGICAL_4);
34*b1e83836Smrg export_proto(findloc0_r17);
35*b1e83836Smrg
36*b1e83836Smrg void
findloc0_r17(gfc_array_index_type * const restrict retarray,gfc_array_r17 * const restrict array,GFC_REAL_17 value,GFC_LOGICAL_4 back)37*b1e83836Smrg findloc0_r17 (gfc_array_index_type * const restrict retarray,
38*b1e83836Smrg gfc_array_r17 * const restrict array, GFC_REAL_17 value,
39*b1e83836Smrg GFC_LOGICAL_4 back)
40*b1e83836Smrg {
41*b1e83836Smrg index_type count[GFC_MAX_DIMENSIONS];
42*b1e83836Smrg index_type extent[GFC_MAX_DIMENSIONS];
43*b1e83836Smrg index_type sstride[GFC_MAX_DIMENSIONS];
44*b1e83836Smrg index_type dstride;
45*b1e83836Smrg const GFC_REAL_17 *base;
46*b1e83836Smrg index_type * restrict dest;
47*b1e83836Smrg index_type rank;
48*b1e83836Smrg index_type n;
49*b1e83836Smrg index_type sz;
50*b1e83836Smrg
51*b1e83836Smrg rank = GFC_DESCRIPTOR_RANK (array);
52*b1e83836Smrg if (rank <= 0)
53*b1e83836Smrg runtime_error ("Rank of array needs to be > 0");
54*b1e83836Smrg
55*b1e83836Smrg if (retarray->base_addr == NULL)
56*b1e83836Smrg {
57*b1e83836Smrg GFC_DIMENSION_SET(retarray->dim[0], 0, rank-1, 1);
58*b1e83836Smrg retarray->dtype.rank = 1;
59*b1e83836Smrg retarray->offset = 0;
60*b1e83836Smrg retarray->base_addr = xmallocarray (rank, sizeof (index_type));
61*b1e83836Smrg }
62*b1e83836Smrg else
63*b1e83836Smrg {
64*b1e83836Smrg if (unlikely (compile_options.bounds_check))
65*b1e83836Smrg bounds_iforeach_return ((array_t *) retarray, (array_t *) array,
66*b1e83836Smrg "FINDLOC");
67*b1e83836Smrg }
68*b1e83836Smrg
69*b1e83836Smrg dstride = GFC_DESCRIPTOR_STRIDE(retarray,0);
70*b1e83836Smrg dest = retarray->base_addr;
71*b1e83836Smrg
72*b1e83836Smrg /* Set the return value. */
73*b1e83836Smrg for (n = 0; n < rank; n++)
74*b1e83836Smrg dest[n * dstride] = 0;
75*b1e83836Smrg
76*b1e83836Smrg sz = 1;
77*b1e83836Smrg for (n = 0; n < rank; n++)
78*b1e83836Smrg {
79*b1e83836Smrg sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n);
80*b1e83836Smrg extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
81*b1e83836Smrg sz *= extent[n];
82*b1e83836Smrg if (extent[n] <= 0)
83*b1e83836Smrg return;
84*b1e83836Smrg }
85*b1e83836Smrg
86*b1e83836Smrg for (n = 0; n < rank; n++)
87*b1e83836Smrg count[n] = 0;
88*b1e83836Smrg
89*b1e83836Smrg if (back)
90*b1e83836Smrg {
91*b1e83836Smrg base = array->base_addr + (sz - 1) * 1;
92*b1e83836Smrg
93*b1e83836Smrg while (1)
94*b1e83836Smrg {
95*b1e83836Smrg do
96*b1e83836Smrg {
97*b1e83836Smrg if (unlikely(*base == value))
98*b1e83836Smrg {
99*b1e83836Smrg for (n = 0; n < rank; n++)
100*b1e83836Smrg dest[n * dstride] = extent[n] - count[n];
101*b1e83836Smrg
102*b1e83836Smrg return;
103*b1e83836Smrg }
104*b1e83836Smrg base -= sstride[0] * 1;
105*b1e83836Smrg } while(++count[0] != extent[0]);
106*b1e83836Smrg
107*b1e83836Smrg n = 0;
108*b1e83836Smrg do
109*b1e83836Smrg {
110*b1e83836Smrg /* When we get to the end of a dimension, reset it and increment
111*b1e83836Smrg the next dimension. */
112*b1e83836Smrg count[n] = 0;
113*b1e83836Smrg /* We could precalculate these products, but this is a less
114*b1e83836Smrg frequently used path so probably not worth it. */
115*b1e83836Smrg base += sstride[n] * extent[n] * 1;
116*b1e83836Smrg n++;
117*b1e83836Smrg if (n >= rank)
118*b1e83836Smrg return;
119*b1e83836Smrg else
120*b1e83836Smrg {
121*b1e83836Smrg count[n]++;
122*b1e83836Smrg base -= sstride[n] * 1;
123*b1e83836Smrg }
124*b1e83836Smrg } while (count[n] == extent[n]);
125*b1e83836Smrg }
126*b1e83836Smrg }
127*b1e83836Smrg else
128*b1e83836Smrg {
129*b1e83836Smrg base = array->base_addr;
130*b1e83836Smrg while (1)
131*b1e83836Smrg {
132*b1e83836Smrg do
133*b1e83836Smrg {
134*b1e83836Smrg if (unlikely(*base == value))
135*b1e83836Smrg {
136*b1e83836Smrg for (n = 0; n < rank; n++)
137*b1e83836Smrg dest[n * dstride] = count[n] + 1;
138*b1e83836Smrg
139*b1e83836Smrg return;
140*b1e83836Smrg }
141*b1e83836Smrg base += sstride[0] * 1;
142*b1e83836Smrg } while(++count[0] != extent[0]);
143*b1e83836Smrg
144*b1e83836Smrg n = 0;
145*b1e83836Smrg do
146*b1e83836Smrg {
147*b1e83836Smrg /* When we get to the end of a dimension, reset it and increment
148*b1e83836Smrg the next dimension. */
149*b1e83836Smrg count[n] = 0;
150*b1e83836Smrg /* We could precalculate these products, but this is a less
151*b1e83836Smrg frequently used path so probably not worth it. */
152*b1e83836Smrg base -= sstride[n] * extent[n] * 1;
153*b1e83836Smrg n++;
154*b1e83836Smrg if (n >= rank)
155*b1e83836Smrg return;
156*b1e83836Smrg else
157*b1e83836Smrg {
158*b1e83836Smrg count[n]++;
159*b1e83836Smrg base += sstride[n] * 1;
160*b1e83836Smrg }
161*b1e83836Smrg } while (count[n] == extent[n]);
162*b1e83836Smrg }
163*b1e83836Smrg }
164*b1e83836Smrg return;
165*b1e83836Smrg }
166*b1e83836Smrg
167*b1e83836Smrg extern void mfindloc0_r17 (gfc_array_index_type * const restrict retarray,
168*b1e83836Smrg gfc_array_r17 * const restrict array, GFC_REAL_17 value,
169*b1e83836Smrg gfc_array_l1 *const restrict, GFC_LOGICAL_4);
170*b1e83836Smrg export_proto(mfindloc0_r17);
171*b1e83836Smrg
172*b1e83836Smrg void
mfindloc0_r17(gfc_array_index_type * const restrict retarray,gfc_array_r17 * const restrict array,GFC_REAL_17 value,gfc_array_l1 * const restrict mask,GFC_LOGICAL_4 back)173*b1e83836Smrg mfindloc0_r17 (gfc_array_index_type * const restrict retarray,
174*b1e83836Smrg gfc_array_r17 * const restrict array, GFC_REAL_17 value,
175*b1e83836Smrg gfc_array_l1 *const restrict mask, GFC_LOGICAL_4 back)
176*b1e83836Smrg {
177*b1e83836Smrg index_type count[GFC_MAX_DIMENSIONS];
178*b1e83836Smrg index_type extent[GFC_MAX_DIMENSIONS];
179*b1e83836Smrg index_type sstride[GFC_MAX_DIMENSIONS];
180*b1e83836Smrg index_type mstride[GFC_MAX_DIMENSIONS];
181*b1e83836Smrg index_type dstride;
182*b1e83836Smrg const GFC_REAL_17 *base;
183*b1e83836Smrg index_type * restrict dest;
184*b1e83836Smrg GFC_LOGICAL_1 *mbase;
185*b1e83836Smrg index_type rank;
186*b1e83836Smrg index_type n;
187*b1e83836Smrg int mask_kind;
188*b1e83836Smrg index_type sz;
189*b1e83836Smrg
190*b1e83836Smrg rank = GFC_DESCRIPTOR_RANK (array);
191*b1e83836Smrg if (rank <= 0)
192*b1e83836Smrg runtime_error ("Rank of array needs to be > 0");
193*b1e83836Smrg
194*b1e83836Smrg if (retarray->base_addr == NULL)
195*b1e83836Smrg {
196*b1e83836Smrg GFC_DIMENSION_SET(retarray->dim[0], 0, rank-1, 1);
197*b1e83836Smrg retarray->dtype.rank = 1;
198*b1e83836Smrg retarray->offset = 0;
199*b1e83836Smrg retarray->base_addr = xmallocarray (rank, sizeof (index_type));
200*b1e83836Smrg }
201*b1e83836Smrg else
202*b1e83836Smrg {
203*b1e83836Smrg if (unlikely (compile_options.bounds_check))
204*b1e83836Smrg {
205*b1e83836Smrg bounds_iforeach_return ((array_t *) retarray, (array_t *) array,
206*b1e83836Smrg "FINDLOC");
207*b1e83836Smrg bounds_equal_extents ((array_t *) mask, (array_t *) array,
208*b1e83836Smrg "MASK argument", "FINDLOC");
209*b1e83836Smrg }
210*b1e83836Smrg }
211*b1e83836Smrg
212*b1e83836Smrg mask_kind = GFC_DESCRIPTOR_SIZE (mask);
213*b1e83836Smrg
214*b1e83836Smrg mbase = mask->base_addr;
215*b1e83836Smrg
216*b1e83836Smrg if (mask_kind == 1 || mask_kind == 2 || mask_kind == 4 || mask_kind == 8
217*b1e83836Smrg #ifdef HAVE_GFC_LOGICAL_16
218*b1e83836Smrg || mask_kind == 16
219*b1e83836Smrg #endif
220*b1e83836Smrg )
221*b1e83836Smrg mbase = GFOR_POINTER_TO_L1 (mbase, mask_kind);
222*b1e83836Smrg else
223*b1e83836Smrg internal_error (NULL, "Funny sized logical array");
224*b1e83836Smrg
225*b1e83836Smrg dstride = GFC_DESCRIPTOR_STRIDE(retarray,0);
226*b1e83836Smrg dest = retarray->base_addr;
227*b1e83836Smrg
228*b1e83836Smrg /* Set the return value. */
229*b1e83836Smrg for (n = 0; n < rank; n++)
230*b1e83836Smrg dest[n * dstride] = 0;
231*b1e83836Smrg
232*b1e83836Smrg sz = 1;
233*b1e83836Smrg for (n = 0; n < rank; n++)
234*b1e83836Smrg {
235*b1e83836Smrg sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n);
236*b1e83836Smrg mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n);
237*b1e83836Smrg extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
238*b1e83836Smrg sz *= extent[n];
239*b1e83836Smrg if (extent[n] <= 0)
240*b1e83836Smrg return;
241*b1e83836Smrg }
242*b1e83836Smrg
243*b1e83836Smrg for (n = 0; n < rank; n++)
244*b1e83836Smrg count[n] = 0;
245*b1e83836Smrg
246*b1e83836Smrg if (back)
247*b1e83836Smrg {
248*b1e83836Smrg base = array->base_addr + (sz - 1) * 1;
249*b1e83836Smrg mbase = mbase + (sz - 1) * mask_kind;
250*b1e83836Smrg while (1)
251*b1e83836Smrg {
252*b1e83836Smrg do
253*b1e83836Smrg {
254*b1e83836Smrg if (unlikely(*mbase && *base == value))
255*b1e83836Smrg {
256*b1e83836Smrg for (n = 0; n < rank; n++)
257*b1e83836Smrg dest[n * dstride] = extent[n] - count[n];
258*b1e83836Smrg
259*b1e83836Smrg return;
260*b1e83836Smrg }
261*b1e83836Smrg base -= sstride[0] * 1;
262*b1e83836Smrg mbase -= mstride[0];
263*b1e83836Smrg } while(++count[0] != extent[0]);
264*b1e83836Smrg
265*b1e83836Smrg n = 0;
266*b1e83836Smrg do
267*b1e83836Smrg {
268*b1e83836Smrg /* When we get to the end of a dimension, reset it and increment
269*b1e83836Smrg the next dimension. */
270*b1e83836Smrg count[n] = 0;
271*b1e83836Smrg /* We could precalculate these products, but this is a less
272*b1e83836Smrg frequently used path so probably not worth it. */
273*b1e83836Smrg base += sstride[n] * extent[n] * 1;
274*b1e83836Smrg mbase -= mstride[n] * extent[n];
275*b1e83836Smrg n++;
276*b1e83836Smrg if (n >= rank)
277*b1e83836Smrg return;
278*b1e83836Smrg else
279*b1e83836Smrg {
280*b1e83836Smrg count[n]++;
281*b1e83836Smrg base -= sstride[n] * 1;
282*b1e83836Smrg mbase += mstride[n];
283*b1e83836Smrg }
284*b1e83836Smrg } while (count[n] == extent[n]);
285*b1e83836Smrg }
286*b1e83836Smrg }
287*b1e83836Smrg else
288*b1e83836Smrg {
289*b1e83836Smrg base = array->base_addr;
290*b1e83836Smrg while (1)
291*b1e83836Smrg {
292*b1e83836Smrg do
293*b1e83836Smrg {
294*b1e83836Smrg if (unlikely(*mbase && *base == value))
295*b1e83836Smrg {
296*b1e83836Smrg for (n = 0; n < rank; n++)
297*b1e83836Smrg dest[n * dstride] = count[n] + 1;
298*b1e83836Smrg
299*b1e83836Smrg return;
300*b1e83836Smrg }
301*b1e83836Smrg base += sstride[0] * 1;
302*b1e83836Smrg mbase += mstride[0];
303*b1e83836Smrg } while(++count[0] != extent[0]);
304*b1e83836Smrg
305*b1e83836Smrg n = 0;
306*b1e83836Smrg do
307*b1e83836Smrg {
308*b1e83836Smrg /* When we get to the end of a dimension, reset it and increment
309*b1e83836Smrg the next dimension. */
310*b1e83836Smrg count[n] = 0;
311*b1e83836Smrg /* We could precalculate these products, but this is a less
312*b1e83836Smrg frequently used path so probably not worth it. */
313*b1e83836Smrg base -= sstride[n] * extent[n] * 1;
314*b1e83836Smrg mbase -= mstride[n] * extent[n];
315*b1e83836Smrg n++;
316*b1e83836Smrg if (n >= rank)
317*b1e83836Smrg return;
318*b1e83836Smrg else
319*b1e83836Smrg {
320*b1e83836Smrg count[n]++;
321*b1e83836Smrg base += sstride[n]* 1;
322*b1e83836Smrg mbase += mstride[n];
323*b1e83836Smrg }
324*b1e83836Smrg } while (count[n] == extent[n]);
325*b1e83836Smrg }
326*b1e83836Smrg }
327*b1e83836Smrg return;
328*b1e83836Smrg }
329*b1e83836Smrg
330*b1e83836Smrg extern void sfindloc0_r17 (gfc_array_index_type * const restrict retarray,
331*b1e83836Smrg gfc_array_r17 * const restrict array, GFC_REAL_17 value,
332*b1e83836Smrg GFC_LOGICAL_4 *, GFC_LOGICAL_4);
333*b1e83836Smrg export_proto(sfindloc0_r17);
334*b1e83836Smrg
335*b1e83836Smrg void
sfindloc0_r17(gfc_array_index_type * const restrict retarray,gfc_array_r17 * const restrict array,GFC_REAL_17 value,GFC_LOGICAL_4 * mask,GFC_LOGICAL_4 back)336*b1e83836Smrg sfindloc0_r17 (gfc_array_index_type * const restrict retarray,
337*b1e83836Smrg gfc_array_r17 * const restrict array, GFC_REAL_17 value,
338*b1e83836Smrg GFC_LOGICAL_4 * mask, GFC_LOGICAL_4 back)
339*b1e83836Smrg {
340*b1e83836Smrg index_type rank;
341*b1e83836Smrg index_type dstride;
342*b1e83836Smrg index_type * restrict dest;
343*b1e83836Smrg index_type n;
344*b1e83836Smrg
345*b1e83836Smrg if (mask == NULL || *mask)
346*b1e83836Smrg {
347*b1e83836Smrg findloc0_r17 (retarray, array, value, back);
348*b1e83836Smrg return;
349*b1e83836Smrg }
350*b1e83836Smrg
351*b1e83836Smrg rank = GFC_DESCRIPTOR_RANK (array);
352*b1e83836Smrg
353*b1e83836Smrg if (rank <= 0)
354*b1e83836Smrg internal_error (NULL, "Rank of array needs to be > 0");
355*b1e83836Smrg
356*b1e83836Smrg if (retarray->base_addr == NULL)
357*b1e83836Smrg {
358*b1e83836Smrg GFC_DIMENSION_SET(retarray->dim[0], 0, rank-1, 1);
359*b1e83836Smrg retarray->dtype.rank = 1;
360*b1e83836Smrg retarray->offset = 0;
361*b1e83836Smrg retarray->base_addr = xmallocarray (rank, sizeof (index_type));
362*b1e83836Smrg }
363*b1e83836Smrg else if (unlikely (compile_options.bounds_check))
364*b1e83836Smrg {
365*b1e83836Smrg bounds_iforeach_return ((array_t *) retarray, (array_t *) array,
366*b1e83836Smrg "FINDLOC");
367*b1e83836Smrg }
368*b1e83836Smrg
369*b1e83836Smrg dstride = GFC_DESCRIPTOR_STRIDE(retarray,0);
370*b1e83836Smrg dest = retarray->base_addr;
371*b1e83836Smrg for (n = 0; n<rank; n++)
372*b1e83836Smrg dest[n * dstride] = 0 ;
373*b1e83836Smrg }
374*b1e83836Smrg
375*b1e83836Smrg #endif
376