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