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