1627f7eb2Smrg
2627f7eb2Smrg /* Implementation of the FINDLOC intrinsic
3*4c3eb207Smrg Copyright (C) 2018-2020 Free Software Foundation, Inc.
4627f7eb2Smrg Contributed by Thomas König <tk@tkoenig.net>
5627f7eb2Smrg
6627f7eb2Smrg This file is part of the GNU Fortran 95 runtime library (libgfortran).
7627f7eb2Smrg
8627f7eb2Smrg Libgfortran is free software; you can redistribute it and/or
9627f7eb2Smrg modify it under the terms of the GNU General Public
10627f7eb2Smrg License as published by the Free Software Foundation; either
11627f7eb2Smrg version 3 of the License, or (at your option) any later version.
12627f7eb2Smrg
13627f7eb2Smrg Libgfortran is distributed in the hope that it will be useful,
14627f7eb2Smrg but WITHOUT ANY WARRANTY; without even the implied warranty of
15627f7eb2Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16627f7eb2Smrg GNU General Public License for more details.
17627f7eb2Smrg
18627f7eb2Smrg Under Section 7 of GPL version 3, you are granted additional
19627f7eb2Smrg permissions described in the GCC Runtime Library Exception, version
20627f7eb2Smrg 3.1, as published by the Free Software Foundation.
21627f7eb2Smrg
22627f7eb2Smrg You should have received a copy of the GNU General Public License and
23627f7eb2Smrg a copy of the GCC Runtime Library Exception along with this program;
24627f7eb2Smrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25627f7eb2Smrg <http://www.gnu.org/licenses/>. */
26627f7eb2Smrg
27627f7eb2Smrg #include "libgfortran.h"
28627f7eb2Smrg #include <assert.h>
29627f7eb2Smrg
30627f7eb2Smrg #if defined (HAVE_GFC_REAL_16)
31627f7eb2Smrg extern void findloc0_r16 (gfc_array_index_type * const restrict retarray,
32627f7eb2Smrg gfc_array_r16 * const restrict array, GFC_REAL_16 value,
33627f7eb2Smrg GFC_LOGICAL_4);
34627f7eb2Smrg export_proto(findloc0_r16);
35627f7eb2Smrg
36627f7eb2Smrg void
findloc0_r16(gfc_array_index_type * const restrict retarray,gfc_array_r16 * const restrict array,GFC_REAL_16 value,GFC_LOGICAL_4 back)37627f7eb2Smrg findloc0_r16 (gfc_array_index_type * const restrict retarray,
38627f7eb2Smrg gfc_array_r16 * const restrict array, GFC_REAL_16 value,
39627f7eb2Smrg GFC_LOGICAL_4 back)
40627f7eb2Smrg {
41627f7eb2Smrg index_type count[GFC_MAX_DIMENSIONS];
42627f7eb2Smrg index_type extent[GFC_MAX_DIMENSIONS];
43627f7eb2Smrg index_type sstride[GFC_MAX_DIMENSIONS];
44627f7eb2Smrg index_type dstride;
45627f7eb2Smrg const GFC_REAL_16 *base;
46627f7eb2Smrg index_type * restrict dest;
47627f7eb2Smrg index_type rank;
48627f7eb2Smrg index_type n;
49627f7eb2Smrg index_type sz;
50627f7eb2Smrg
51627f7eb2Smrg rank = GFC_DESCRIPTOR_RANK (array);
52627f7eb2Smrg if (rank <= 0)
53627f7eb2Smrg runtime_error ("Rank of array needs to be > 0");
54627f7eb2Smrg
55627f7eb2Smrg if (retarray->base_addr == NULL)
56627f7eb2Smrg {
57627f7eb2Smrg GFC_DIMENSION_SET(retarray->dim[0], 0, rank-1, 1);
58627f7eb2Smrg retarray->dtype.rank = 1;
59627f7eb2Smrg retarray->offset = 0;
60627f7eb2Smrg retarray->base_addr = xmallocarray (rank, sizeof (index_type));
61627f7eb2Smrg }
62627f7eb2Smrg else
63627f7eb2Smrg {
64627f7eb2Smrg if (unlikely (compile_options.bounds_check))
65627f7eb2Smrg bounds_iforeach_return ((array_t *) retarray, (array_t *) array,
66627f7eb2Smrg "FINDLOC");
67627f7eb2Smrg }
68627f7eb2Smrg
69627f7eb2Smrg dstride = GFC_DESCRIPTOR_STRIDE(retarray,0);
70627f7eb2Smrg dest = retarray->base_addr;
71627f7eb2Smrg
72627f7eb2Smrg /* Set the return value. */
73627f7eb2Smrg for (n = 0; n < rank; n++)
74627f7eb2Smrg dest[n * dstride] = 0;
75627f7eb2Smrg
76627f7eb2Smrg sz = 1;
77627f7eb2Smrg for (n = 0; n < rank; n++)
78627f7eb2Smrg {
79627f7eb2Smrg sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n);
80627f7eb2Smrg extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
81627f7eb2Smrg sz *= extent[n];
82627f7eb2Smrg if (extent[n] <= 0)
83627f7eb2Smrg return;
84627f7eb2Smrg }
85627f7eb2Smrg
86627f7eb2Smrg for (n = 0; n < rank; n++)
87627f7eb2Smrg count[n] = 0;
88627f7eb2Smrg
89627f7eb2Smrg if (back)
90627f7eb2Smrg {
91627f7eb2Smrg base = array->base_addr + (sz - 1) * 1;
92627f7eb2Smrg
93627f7eb2Smrg while (1)
94627f7eb2Smrg {
95627f7eb2Smrg do
96627f7eb2Smrg {
97627f7eb2Smrg if (unlikely(*base == value))
98627f7eb2Smrg {
99627f7eb2Smrg for (n = 0; n < rank; n++)
100627f7eb2Smrg dest[n * dstride] = extent[n] - count[n];
101627f7eb2Smrg
102627f7eb2Smrg return;
103627f7eb2Smrg }
104627f7eb2Smrg base -= sstride[0] * 1;
105627f7eb2Smrg } while(++count[0] != extent[0]);
106627f7eb2Smrg
107627f7eb2Smrg n = 0;
108627f7eb2Smrg do
109627f7eb2Smrg {
110627f7eb2Smrg /* When we get to the end of a dimension, reset it and increment
111627f7eb2Smrg the next dimension. */
112627f7eb2Smrg count[n] = 0;
113627f7eb2Smrg /* We could precalculate these products, but this is a less
114627f7eb2Smrg frequently used path so probably not worth it. */
115627f7eb2Smrg base += sstride[n] * extent[n] * 1;
116627f7eb2Smrg n++;
117627f7eb2Smrg if (n >= rank)
118627f7eb2Smrg return;
119627f7eb2Smrg else
120627f7eb2Smrg {
121627f7eb2Smrg count[n]++;
122627f7eb2Smrg base -= sstride[n] * 1;
123627f7eb2Smrg }
124627f7eb2Smrg } while (count[n] == extent[n]);
125627f7eb2Smrg }
126627f7eb2Smrg }
127627f7eb2Smrg else
128627f7eb2Smrg {
129627f7eb2Smrg base = array->base_addr;
130627f7eb2Smrg while (1)
131627f7eb2Smrg {
132627f7eb2Smrg do
133627f7eb2Smrg {
134627f7eb2Smrg if (unlikely(*base == value))
135627f7eb2Smrg {
136627f7eb2Smrg for (n = 0; n < rank; n++)
137627f7eb2Smrg dest[n * dstride] = count[n] + 1;
138627f7eb2Smrg
139627f7eb2Smrg return;
140627f7eb2Smrg }
141627f7eb2Smrg base += sstride[0] * 1;
142627f7eb2Smrg } while(++count[0] != extent[0]);
143627f7eb2Smrg
144627f7eb2Smrg n = 0;
145627f7eb2Smrg do
146627f7eb2Smrg {
147627f7eb2Smrg /* When we get to the end of a dimension, reset it and increment
148627f7eb2Smrg the next dimension. */
149627f7eb2Smrg count[n] = 0;
150627f7eb2Smrg /* We could precalculate these products, but this is a less
151627f7eb2Smrg frequently used path so probably not worth it. */
152627f7eb2Smrg base -= sstride[n] * extent[n] * 1;
153627f7eb2Smrg n++;
154627f7eb2Smrg if (n >= rank)
155627f7eb2Smrg return;
156627f7eb2Smrg else
157627f7eb2Smrg {
158627f7eb2Smrg count[n]++;
159627f7eb2Smrg base += sstride[n] * 1;
160627f7eb2Smrg }
161627f7eb2Smrg } while (count[n] == extent[n]);
162627f7eb2Smrg }
163627f7eb2Smrg }
164627f7eb2Smrg return;
165627f7eb2Smrg }
166627f7eb2Smrg
167627f7eb2Smrg extern void mfindloc0_r16 (gfc_array_index_type * const restrict retarray,
168627f7eb2Smrg gfc_array_r16 * const restrict array, GFC_REAL_16 value,
169627f7eb2Smrg gfc_array_l1 *const restrict, GFC_LOGICAL_4);
170627f7eb2Smrg export_proto(mfindloc0_r16);
171627f7eb2Smrg
172627f7eb2Smrg void
mfindloc0_r16(gfc_array_index_type * const restrict retarray,gfc_array_r16 * const restrict array,GFC_REAL_16 value,gfc_array_l1 * const restrict mask,GFC_LOGICAL_4 back)173627f7eb2Smrg mfindloc0_r16 (gfc_array_index_type * const restrict retarray,
174627f7eb2Smrg gfc_array_r16 * const restrict array, GFC_REAL_16 value,
175627f7eb2Smrg gfc_array_l1 *const restrict mask, GFC_LOGICAL_4 back)
176627f7eb2Smrg {
177627f7eb2Smrg index_type count[GFC_MAX_DIMENSIONS];
178627f7eb2Smrg index_type extent[GFC_MAX_DIMENSIONS];
179627f7eb2Smrg index_type sstride[GFC_MAX_DIMENSIONS];
180627f7eb2Smrg index_type mstride[GFC_MAX_DIMENSIONS];
181627f7eb2Smrg index_type dstride;
182627f7eb2Smrg const GFC_REAL_16 *base;
183627f7eb2Smrg index_type * restrict dest;
184627f7eb2Smrg GFC_LOGICAL_1 *mbase;
185627f7eb2Smrg index_type rank;
186627f7eb2Smrg index_type n;
187627f7eb2Smrg int mask_kind;
188627f7eb2Smrg index_type sz;
189627f7eb2Smrg
190627f7eb2Smrg rank = GFC_DESCRIPTOR_RANK (array);
191627f7eb2Smrg if (rank <= 0)
192627f7eb2Smrg runtime_error ("Rank of array needs to be > 0");
193627f7eb2Smrg
194627f7eb2Smrg if (retarray->base_addr == NULL)
195627f7eb2Smrg {
196627f7eb2Smrg GFC_DIMENSION_SET(retarray->dim[0], 0, rank-1, 1);
197627f7eb2Smrg retarray->dtype.rank = 1;
198627f7eb2Smrg retarray->offset = 0;
199627f7eb2Smrg retarray->base_addr = xmallocarray (rank, sizeof (index_type));
200627f7eb2Smrg }
201627f7eb2Smrg else
202627f7eb2Smrg {
203627f7eb2Smrg if (unlikely (compile_options.bounds_check))
204627f7eb2Smrg {
205627f7eb2Smrg bounds_iforeach_return ((array_t *) retarray, (array_t *) array,
206627f7eb2Smrg "FINDLOC");
207627f7eb2Smrg bounds_equal_extents ((array_t *) mask, (array_t *) array,
208627f7eb2Smrg "MASK argument", "FINDLOC");
209627f7eb2Smrg }
210627f7eb2Smrg }
211627f7eb2Smrg
212627f7eb2Smrg mask_kind = GFC_DESCRIPTOR_SIZE (mask);
213627f7eb2Smrg
214627f7eb2Smrg mbase = mask->base_addr;
215627f7eb2Smrg
216627f7eb2Smrg if (mask_kind == 1 || mask_kind == 2 || mask_kind == 4 || mask_kind == 8
217627f7eb2Smrg #ifdef HAVE_GFC_LOGICAL_16
218627f7eb2Smrg || mask_kind == 16
219627f7eb2Smrg #endif
220627f7eb2Smrg )
221627f7eb2Smrg mbase = GFOR_POINTER_TO_L1 (mbase, mask_kind);
222627f7eb2Smrg else
223627f7eb2Smrg internal_error (NULL, "Funny sized logical array");
224627f7eb2Smrg
225627f7eb2Smrg dstride = GFC_DESCRIPTOR_STRIDE(retarray,0);
226627f7eb2Smrg dest = retarray->base_addr;
227627f7eb2Smrg
228627f7eb2Smrg /* Set the return value. */
229627f7eb2Smrg for (n = 0; n < rank; n++)
230627f7eb2Smrg dest[n * dstride] = 0;
231627f7eb2Smrg
232627f7eb2Smrg sz = 1;
233627f7eb2Smrg for (n = 0; n < rank; n++)
234627f7eb2Smrg {
235627f7eb2Smrg sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n);
236627f7eb2Smrg mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n);
237627f7eb2Smrg extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
238627f7eb2Smrg sz *= extent[n];
239627f7eb2Smrg if (extent[n] <= 0)
240627f7eb2Smrg return;
241627f7eb2Smrg }
242627f7eb2Smrg
243627f7eb2Smrg for (n = 0; n < rank; n++)
244627f7eb2Smrg count[n] = 0;
245627f7eb2Smrg
246627f7eb2Smrg if (back)
247627f7eb2Smrg {
248627f7eb2Smrg base = array->base_addr + (sz - 1) * 1;
249627f7eb2Smrg mbase = mbase + (sz - 1) * mask_kind;
250627f7eb2Smrg while (1)
251627f7eb2Smrg {
252627f7eb2Smrg do
253627f7eb2Smrg {
254627f7eb2Smrg if (unlikely(*mbase && *base == value))
255627f7eb2Smrg {
256627f7eb2Smrg for (n = 0; n < rank; n++)
257627f7eb2Smrg dest[n * dstride] = extent[n] - count[n];
258627f7eb2Smrg
259627f7eb2Smrg return;
260627f7eb2Smrg }
261627f7eb2Smrg base -= sstride[0] * 1;
262627f7eb2Smrg mbase -= mstride[0];
263627f7eb2Smrg } while(++count[0] != extent[0]);
264627f7eb2Smrg
265627f7eb2Smrg n = 0;
266627f7eb2Smrg do
267627f7eb2Smrg {
268627f7eb2Smrg /* When we get to the end of a dimension, reset it and increment
269627f7eb2Smrg the next dimension. */
270627f7eb2Smrg count[n] = 0;
271627f7eb2Smrg /* We could precalculate these products, but this is a less
272627f7eb2Smrg frequently used path so probably not worth it. */
273627f7eb2Smrg base += sstride[n] * extent[n] * 1;
274627f7eb2Smrg mbase -= mstride[n] * extent[n];
275627f7eb2Smrg n++;
276627f7eb2Smrg if (n >= rank)
277627f7eb2Smrg return;
278627f7eb2Smrg else
279627f7eb2Smrg {
280627f7eb2Smrg count[n]++;
281627f7eb2Smrg base -= sstride[n] * 1;
282627f7eb2Smrg mbase += mstride[n];
283627f7eb2Smrg }
284627f7eb2Smrg } while (count[n] == extent[n]);
285627f7eb2Smrg }
286627f7eb2Smrg }
287627f7eb2Smrg else
288627f7eb2Smrg {
289627f7eb2Smrg base = array->base_addr;
290627f7eb2Smrg while (1)
291627f7eb2Smrg {
292627f7eb2Smrg do
293627f7eb2Smrg {
294627f7eb2Smrg if (unlikely(*mbase && *base == value))
295627f7eb2Smrg {
296627f7eb2Smrg for (n = 0; n < rank; n++)
297627f7eb2Smrg dest[n * dstride] = count[n] + 1;
298627f7eb2Smrg
299627f7eb2Smrg return;
300627f7eb2Smrg }
301627f7eb2Smrg base += sstride[0] * 1;
302627f7eb2Smrg mbase += mstride[0];
303627f7eb2Smrg } while(++count[0] != extent[0]);
304627f7eb2Smrg
305627f7eb2Smrg n = 0;
306627f7eb2Smrg do
307627f7eb2Smrg {
308627f7eb2Smrg /* When we get to the end of a dimension, reset it and increment
309627f7eb2Smrg the next dimension. */
310627f7eb2Smrg count[n] = 0;
311627f7eb2Smrg /* We could precalculate these products, but this is a less
312627f7eb2Smrg frequently used path so probably not worth it. */
313627f7eb2Smrg base -= sstride[n] * extent[n] * 1;
314627f7eb2Smrg mbase -= mstride[n] * extent[n];
315627f7eb2Smrg n++;
316627f7eb2Smrg if (n >= rank)
317627f7eb2Smrg return;
318627f7eb2Smrg else
319627f7eb2Smrg {
320627f7eb2Smrg count[n]++;
321627f7eb2Smrg base += sstride[n]* 1;
322627f7eb2Smrg mbase += mstride[n];
323627f7eb2Smrg }
324627f7eb2Smrg } while (count[n] == extent[n]);
325627f7eb2Smrg }
326627f7eb2Smrg }
327627f7eb2Smrg return;
328627f7eb2Smrg }
329627f7eb2Smrg
330627f7eb2Smrg extern void sfindloc0_r16 (gfc_array_index_type * const restrict retarray,
331627f7eb2Smrg gfc_array_r16 * const restrict array, GFC_REAL_16 value,
332627f7eb2Smrg GFC_LOGICAL_4 *, GFC_LOGICAL_4);
333627f7eb2Smrg export_proto(sfindloc0_r16);
334627f7eb2Smrg
335627f7eb2Smrg void
sfindloc0_r16(gfc_array_index_type * const restrict retarray,gfc_array_r16 * const restrict array,GFC_REAL_16 value,GFC_LOGICAL_4 * mask,GFC_LOGICAL_4 back)336627f7eb2Smrg sfindloc0_r16 (gfc_array_index_type * const restrict retarray,
337627f7eb2Smrg gfc_array_r16 * const restrict array, GFC_REAL_16 value,
338627f7eb2Smrg GFC_LOGICAL_4 * mask, GFC_LOGICAL_4 back)
339627f7eb2Smrg {
340627f7eb2Smrg index_type rank;
341627f7eb2Smrg index_type dstride;
342627f7eb2Smrg index_type * restrict dest;
343627f7eb2Smrg index_type n;
344627f7eb2Smrg
345627f7eb2Smrg if (mask == NULL || *mask)
346627f7eb2Smrg {
347627f7eb2Smrg findloc0_r16 (retarray, array, value, back);
348627f7eb2Smrg return;
349627f7eb2Smrg }
350627f7eb2Smrg
351627f7eb2Smrg rank = GFC_DESCRIPTOR_RANK (array);
352627f7eb2Smrg
353627f7eb2Smrg if (rank <= 0)
354627f7eb2Smrg internal_error (NULL, "Rank of array needs to be > 0");
355627f7eb2Smrg
356627f7eb2Smrg if (retarray->base_addr == NULL)
357627f7eb2Smrg {
358627f7eb2Smrg GFC_DIMENSION_SET(retarray->dim[0], 0, rank-1, 1);
359627f7eb2Smrg retarray->dtype.rank = 1;
360627f7eb2Smrg retarray->offset = 0;
361627f7eb2Smrg retarray->base_addr = xmallocarray (rank, sizeof (index_type));
362627f7eb2Smrg }
363627f7eb2Smrg else if (unlikely (compile_options.bounds_check))
364627f7eb2Smrg {
365627f7eb2Smrg bounds_iforeach_return ((array_t *) retarray, (array_t *) array,
366627f7eb2Smrg "FINDLOC");
367627f7eb2Smrg }
368627f7eb2Smrg
369627f7eb2Smrg dstride = GFC_DESCRIPTOR_STRIDE(retarray,0);
370627f7eb2Smrg dest = retarray->base_addr;
371627f7eb2Smrg for (n = 0; n<rank; n++)
372627f7eb2Smrg dest[n * dstride] = 0 ;
373627f7eb2Smrg }
374627f7eb2Smrg
375627f7eb2Smrg #endif
376