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_UINTEGER_1)
31627f7eb2Smrg extern void findloc0_s1 (gfc_array_index_type * const restrict retarray,
32627f7eb2Smrg gfc_array_s1 * const restrict array, GFC_UINTEGER_1 *value,
33627f7eb2Smrg GFC_LOGICAL_4 back, gfc_charlen_type len_array, gfc_charlen_type len_value);
34627f7eb2Smrg
35627f7eb2Smrg export_proto(findloc0_s1);
36627f7eb2Smrg
37627f7eb2Smrg void
findloc0_s1(gfc_array_index_type * const restrict retarray,gfc_array_s1 * const restrict array,GFC_UINTEGER_1 * value,GFC_LOGICAL_4 back,gfc_charlen_type len_array,gfc_charlen_type len_value)38627f7eb2Smrg findloc0_s1 (gfc_array_index_type * const restrict retarray,
39627f7eb2Smrg gfc_array_s1 * const restrict array, GFC_UINTEGER_1 *value,
40627f7eb2Smrg GFC_LOGICAL_4 back, gfc_charlen_type len_array, gfc_charlen_type len_value)
41627f7eb2Smrg {
42627f7eb2Smrg index_type count[GFC_MAX_DIMENSIONS];
43627f7eb2Smrg index_type extent[GFC_MAX_DIMENSIONS];
44627f7eb2Smrg index_type sstride[GFC_MAX_DIMENSIONS];
45627f7eb2Smrg index_type dstride;
46627f7eb2Smrg const GFC_UINTEGER_1 *base;
47627f7eb2Smrg index_type * restrict dest;
48627f7eb2Smrg index_type rank;
49627f7eb2Smrg index_type n;
50627f7eb2Smrg index_type sz;
51627f7eb2Smrg
52627f7eb2Smrg rank = GFC_DESCRIPTOR_RANK (array);
53627f7eb2Smrg if (rank <= 0)
54627f7eb2Smrg runtime_error ("Rank of array needs to be > 0");
55627f7eb2Smrg
56627f7eb2Smrg if (retarray->base_addr == NULL)
57627f7eb2Smrg {
58627f7eb2Smrg GFC_DIMENSION_SET(retarray->dim[0], 0, rank-1, 1);
59627f7eb2Smrg retarray->dtype.rank = 1;
60627f7eb2Smrg retarray->offset = 0;
61627f7eb2Smrg retarray->base_addr = xmallocarray (rank, sizeof (index_type));
62627f7eb2Smrg }
63627f7eb2Smrg else
64627f7eb2Smrg {
65627f7eb2Smrg if (unlikely (compile_options.bounds_check))
66627f7eb2Smrg bounds_iforeach_return ((array_t *) retarray, (array_t *) array,
67627f7eb2Smrg "FINDLOC");
68627f7eb2Smrg }
69627f7eb2Smrg
70627f7eb2Smrg dstride = GFC_DESCRIPTOR_STRIDE(retarray,0);
71627f7eb2Smrg dest = retarray->base_addr;
72627f7eb2Smrg
73627f7eb2Smrg /* Set the return value. */
74627f7eb2Smrg for (n = 0; n < rank; n++)
75627f7eb2Smrg dest[n * dstride] = 0;
76627f7eb2Smrg
77627f7eb2Smrg sz = 1;
78627f7eb2Smrg for (n = 0; n < rank; n++)
79627f7eb2Smrg {
80627f7eb2Smrg sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n);
81627f7eb2Smrg extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
82627f7eb2Smrg sz *= extent[n];
83627f7eb2Smrg if (extent[n] <= 0)
84627f7eb2Smrg return;
85627f7eb2Smrg }
86627f7eb2Smrg
87627f7eb2Smrg for (n = 0; n < rank; n++)
88627f7eb2Smrg count[n] = 0;
89627f7eb2Smrg
90627f7eb2Smrg if (back)
91627f7eb2Smrg {
92627f7eb2Smrg base = array->base_addr + (sz - 1) * len_array;
93627f7eb2Smrg
94627f7eb2Smrg while (1)
95627f7eb2Smrg {
96627f7eb2Smrg do
97627f7eb2Smrg {
98627f7eb2Smrg if (unlikely(compare_string (len_array, (char *) base, len_value, (char *) value) == 0))
99627f7eb2Smrg {
100627f7eb2Smrg for (n = 0; n < rank; n++)
101627f7eb2Smrg dest[n * dstride] = extent[n] - count[n];
102627f7eb2Smrg
103627f7eb2Smrg return;
104627f7eb2Smrg }
105627f7eb2Smrg base -= sstride[0] * len_array;
106627f7eb2Smrg } while(++count[0] != extent[0]);
107627f7eb2Smrg
108627f7eb2Smrg n = 0;
109627f7eb2Smrg do
110627f7eb2Smrg {
111627f7eb2Smrg /* When we get to the end of a dimension, reset it and increment
112627f7eb2Smrg the next dimension. */
113627f7eb2Smrg count[n] = 0;
114627f7eb2Smrg /* We could precalculate these products, but this is a less
115627f7eb2Smrg frequently used path so probably not worth it. */
116627f7eb2Smrg base += sstride[n] * extent[n] * len_array;
117627f7eb2Smrg n++;
118627f7eb2Smrg if (n >= rank)
119627f7eb2Smrg return;
120627f7eb2Smrg else
121627f7eb2Smrg {
122627f7eb2Smrg count[n]++;
123627f7eb2Smrg base -= sstride[n] * len_array;
124627f7eb2Smrg }
125627f7eb2Smrg } while (count[n] == extent[n]);
126627f7eb2Smrg }
127627f7eb2Smrg }
128627f7eb2Smrg else
129627f7eb2Smrg {
130627f7eb2Smrg base = array->base_addr;
131627f7eb2Smrg while (1)
132627f7eb2Smrg {
133627f7eb2Smrg do
134627f7eb2Smrg {
135627f7eb2Smrg if (unlikely(compare_string (len_array, (char *) base, len_value, (char *) value) == 0))
136627f7eb2Smrg {
137627f7eb2Smrg for (n = 0; n < rank; n++)
138627f7eb2Smrg dest[n * dstride] = count[n] + 1;
139627f7eb2Smrg
140627f7eb2Smrg return;
141627f7eb2Smrg }
142627f7eb2Smrg base += sstride[0] * len_array;
143627f7eb2Smrg } while(++count[0] != extent[0]);
144627f7eb2Smrg
145627f7eb2Smrg n = 0;
146627f7eb2Smrg do
147627f7eb2Smrg {
148627f7eb2Smrg /* When we get to the end of a dimension, reset it and increment
149627f7eb2Smrg the next dimension. */
150627f7eb2Smrg count[n] = 0;
151627f7eb2Smrg /* We could precalculate these products, but this is a less
152627f7eb2Smrg frequently used path so probably not worth it. */
153627f7eb2Smrg base -= sstride[n] * extent[n] * len_array;
154627f7eb2Smrg n++;
155627f7eb2Smrg if (n >= rank)
156627f7eb2Smrg return;
157627f7eb2Smrg else
158627f7eb2Smrg {
159627f7eb2Smrg count[n]++;
160627f7eb2Smrg base += sstride[n] * len_array;
161627f7eb2Smrg }
162627f7eb2Smrg } while (count[n] == extent[n]);
163627f7eb2Smrg }
164627f7eb2Smrg }
165627f7eb2Smrg return;
166627f7eb2Smrg }
167627f7eb2Smrg
168627f7eb2Smrg extern void mfindloc0_s1 (gfc_array_index_type * const restrict retarray,
169627f7eb2Smrg gfc_array_s1 * const restrict array, GFC_UINTEGER_1 *value,
170627f7eb2Smrg gfc_array_l1 *const restrict, GFC_LOGICAL_4 back, gfc_charlen_type len_array,
171627f7eb2Smrg gfc_charlen_type len_value);
172627f7eb2Smrg export_proto(mfindloc0_s1);
173627f7eb2Smrg
174627f7eb2Smrg void
mfindloc0_s1(gfc_array_index_type * const restrict retarray,gfc_array_s1 * const restrict array,GFC_UINTEGER_1 * value,gfc_array_l1 * const restrict mask,GFC_LOGICAL_4 back,gfc_charlen_type len_array,gfc_charlen_type len_value)175627f7eb2Smrg mfindloc0_s1 (gfc_array_index_type * const restrict retarray,
176627f7eb2Smrg gfc_array_s1 * const restrict array, GFC_UINTEGER_1 *value,
177627f7eb2Smrg gfc_array_l1 *const restrict mask, GFC_LOGICAL_4 back,
178627f7eb2Smrg gfc_charlen_type len_array, gfc_charlen_type len_value)
179627f7eb2Smrg {
180627f7eb2Smrg index_type count[GFC_MAX_DIMENSIONS];
181627f7eb2Smrg index_type extent[GFC_MAX_DIMENSIONS];
182627f7eb2Smrg index_type sstride[GFC_MAX_DIMENSIONS];
183627f7eb2Smrg index_type mstride[GFC_MAX_DIMENSIONS];
184627f7eb2Smrg index_type dstride;
185627f7eb2Smrg const GFC_UINTEGER_1 *base;
186627f7eb2Smrg index_type * restrict dest;
187627f7eb2Smrg GFC_LOGICAL_1 *mbase;
188627f7eb2Smrg index_type rank;
189627f7eb2Smrg index_type n;
190627f7eb2Smrg int mask_kind;
191627f7eb2Smrg index_type sz;
192627f7eb2Smrg
193627f7eb2Smrg rank = GFC_DESCRIPTOR_RANK (array);
194627f7eb2Smrg if (rank <= 0)
195627f7eb2Smrg runtime_error ("Rank of array needs to be > 0");
196627f7eb2Smrg
197627f7eb2Smrg if (retarray->base_addr == NULL)
198627f7eb2Smrg {
199627f7eb2Smrg GFC_DIMENSION_SET(retarray->dim[0], 0, rank-1, 1);
200627f7eb2Smrg retarray->dtype.rank = 1;
201627f7eb2Smrg retarray->offset = 0;
202627f7eb2Smrg retarray->base_addr = xmallocarray (rank, sizeof (index_type));
203627f7eb2Smrg }
204627f7eb2Smrg else
205627f7eb2Smrg {
206627f7eb2Smrg if (unlikely (compile_options.bounds_check))
207627f7eb2Smrg {
208627f7eb2Smrg bounds_iforeach_return ((array_t *) retarray, (array_t *) array,
209627f7eb2Smrg "FINDLOC");
210627f7eb2Smrg bounds_equal_extents ((array_t *) mask, (array_t *) array,
211627f7eb2Smrg "MASK argument", "FINDLOC");
212627f7eb2Smrg }
213627f7eb2Smrg }
214627f7eb2Smrg
215627f7eb2Smrg mask_kind = GFC_DESCRIPTOR_SIZE (mask);
216627f7eb2Smrg
217627f7eb2Smrg mbase = mask->base_addr;
218627f7eb2Smrg
219627f7eb2Smrg if (mask_kind == 1 || mask_kind == 2 || mask_kind == 4 || mask_kind == 8
220627f7eb2Smrg #ifdef HAVE_GFC_LOGICAL_16
221627f7eb2Smrg || mask_kind == 16
222627f7eb2Smrg #endif
223627f7eb2Smrg )
224627f7eb2Smrg mbase = GFOR_POINTER_TO_L1 (mbase, mask_kind);
225627f7eb2Smrg else
226627f7eb2Smrg internal_error (NULL, "Funny sized logical array");
227627f7eb2Smrg
228627f7eb2Smrg dstride = GFC_DESCRIPTOR_STRIDE(retarray,0);
229627f7eb2Smrg dest = retarray->base_addr;
230627f7eb2Smrg
231627f7eb2Smrg /* Set the return value. */
232627f7eb2Smrg for (n = 0; n < rank; n++)
233627f7eb2Smrg dest[n * dstride] = 0;
234627f7eb2Smrg
235627f7eb2Smrg sz = 1;
236627f7eb2Smrg for (n = 0; n < rank; n++)
237627f7eb2Smrg {
238627f7eb2Smrg sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n);
239627f7eb2Smrg mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n);
240627f7eb2Smrg extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
241627f7eb2Smrg sz *= extent[n];
242627f7eb2Smrg if (extent[n] <= 0)
243627f7eb2Smrg return;
244627f7eb2Smrg }
245627f7eb2Smrg
246627f7eb2Smrg for (n = 0; n < rank; n++)
247627f7eb2Smrg count[n] = 0;
248627f7eb2Smrg
249627f7eb2Smrg if (back)
250627f7eb2Smrg {
251627f7eb2Smrg base = array->base_addr + (sz - 1) * len_array;
252627f7eb2Smrg mbase = mbase + (sz - 1) * mask_kind;
253627f7eb2Smrg while (1)
254627f7eb2Smrg {
255627f7eb2Smrg do
256627f7eb2Smrg {
257627f7eb2Smrg if (unlikely(*mbase && compare_string (len_array, (char *) base, len_value, (char *) value) == 0))
258627f7eb2Smrg {
259627f7eb2Smrg for (n = 0; n < rank; n++)
260627f7eb2Smrg dest[n * dstride] = extent[n] - count[n];
261627f7eb2Smrg
262627f7eb2Smrg return;
263627f7eb2Smrg }
264627f7eb2Smrg base -= sstride[0] * len_array;
265627f7eb2Smrg mbase -= mstride[0];
266627f7eb2Smrg } while(++count[0] != extent[0]);
267627f7eb2Smrg
268627f7eb2Smrg n = 0;
269627f7eb2Smrg do
270627f7eb2Smrg {
271627f7eb2Smrg /* When we get to the end of a dimension, reset it and increment
272627f7eb2Smrg the next dimension. */
273627f7eb2Smrg count[n] = 0;
274627f7eb2Smrg /* We could precalculate these products, but this is a less
275627f7eb2Smrg frequently used path so probably not worth it. */
276627f7eb2Smrg base += sstride[n] * extent[n] * len_array;
277627f7eb2Smrg mbase -= mstride[n] * extent[n];
278627f7eb2Smrg n++;
279627f7eb2Smrg if (n >= rank)
280627f7eb2Smrg return;
281627f7eb2Smrg else
282627f7eb2Smrg {
283627f7eb2Smrg count[n]++;
284627f7eb2Smrg base -= sstride[n] * len_array;
285627f7eb2Smrg mbase += mstride[n];
286627f7eb2Smrg }
287627f7eb2Smrg } while (count[n] == extent[n]);
288627f7eb2Smrg }
289627f7eb2Smrg }
290627f7eb2Smrg else
291627f7eb2Smrg {
292627f7eb2Smrg base = array->base_addr;
293627f7eb2Smrg while (1)
294627f7eb2Smrg {
295627f7eb2Smrg do
296627f7eb2Smrg {
297627f7eb2Smrg if (unlikely(*mbase && compare_string (len_array, (char *) base, len_value, (char *) value) == 0))
298627f7eb2Smrg {
299627f7eb2Smrg for (n = 0; n < rank; n++)
300627f7eb2Smrg dest[n * dstride] = count[n] + 1;
301627f7eb2Smrg
302627f7eb2Smrg return;
303627f7eb2Smrg }
304627f7eb2Smrg base += sstride[0] * len_array;
305627f7eb2Smrg mbase += mstride[0];
306627f7eb2Smrg } while(++count[0] != extent[0]);
307627f7eb2Smrg
308627f7eb2Smrg n = 0;
309627f7eb2Smrg do
310627f7eb2Smrg {
311627f7eb2Smrg /* When we get to the end of a dimension, reset it and increment
312627f7eb2Smrg the next dimension. */
313627f7eb2Smrg count[n] = 0;
314627f7eb2Smrg /* We could precalculate these products, but this is a less
315627f7eb2Smrg frequently used path so probably not worth it. */
316627f7eb2Smrg base -= sstride[n] * extent[n] * len_array;
317627f7eb2Smrg mbase -= mstride[n] * extent[n];
318627f7eb2Smrg n++;
319627f7eb2Smrg if (n >= rank)
320627f7eb2Smrg return;
321627f7eb2Smrg else
322627f7eb2Smrg {
323627f7eb2Smrg count[n]++;
324627f7eb2Smrg base += sstride[n]* len_array;
325627f7eb2Smrg mbase += mstride[n];
326627f7eb2Smrg }
327627f7eb2Smrg } while (count[n] == extent[n]);
328627f7eb2Smrg }
329627f7eb2Smrg }
330627f7eb2Smrg return;
331627f7eb2Smrg }
332627f7eb2Smrg
333627f7eb2Smrg extern void sfindloc0_s1 (gfc_array_index_type * const restrict retarray,
334627f7eb2Smrg gfc_array_s1 * const restrict array, GFC_UINTEGER_1 *value,
335627f7eb2Smrg GFC_LOGICAL_4 *, GFC_LOGICAL_4 back, gfc_charlen_type len_array,
336627f7eb2Smrg gfc_charlen_type len_value);
337627f7eb2Smrg export_proto(sfindloc0_s1);
338627f7eb2Smrg
339627f7eb2Smrg void
sfindloc0_s1(gfc_array_index_type * const restrict retarray,gfc_array_s1 * const restrict array,GFC_UINTEGER_1 * value,GFC_LOGICAL_4 * mask,GFC_LOGICAL_4 back,gfc_charlen_type len_array,gfc_charlen_type len_value)340627f7eb2Smrg sfindloc0_s1 (gfc_array_index_type * const restrict retarray,
341627f7eb2Smrg gfc_array_s1 * const restrict array, GFC_UINTEGER_1 *value,
342627f7eb2Smrg GFC_LOGICAL_4 * mask, GFC_LOGICAL_4 back, gfc_charlen_type len_array,
343627f7eb2Smrg gfc_charlen_type len_value)
344627f7eb2Smrg {
345627f7eb2Smrg index_type rank;
346627f7eb2Smrg index_type dstride;
347627f7eb2Smrg index_type * restrict dest;
348627f7eb2Smrg index_type n;
349627f7eb2Smrg
350627f7eb2Smrg if (mask == NULL || *mask)
351627f7eb2Smrg {
352627f7eb2Smrg findloc0_s1 (retarray, array, value, back, len_array, len_value);
353627f7eb2Smrg return;
354627f7eb2Smrg }
355627f7eb2Smrg
356627f7eb2Smrg rank = GFC_DESCRIPTOR_RANK (array);
357627f7eb2Smrg
358627f7eb2Smrg if (rank <= 0)
359627f7eb2Smrg internal_error (NULL, "Rank of array needs to be > 0");
360627f7eb2Smrg
361627f7eb2Smrg if (retarray->base_addr == NULL)
362627f7eb2Smrg {
363627f7eb2Smrg GFC_DIMENSION_SET(retarray->dim[0], 0, rank-1, 1);
364627f7eb2Smrg retarray->dtype.rank = 1;
365627f7eb2Smrg retarray->offset = 0;
366627f7eb2Smrg retarray->base_addr = xmallocarray (rank, sizeof (index_type));
367627f7eb2Smrg }
368627f7eb2Smrg else if (unlikely (compile_options.bounds_check))
369627f7eb2Smrg {
370627f7eb2Smrg bounds_iforeach_return ((array_t *) retarray, (array_t *) array,
371627f7eb2Smrg "FINDLOC");
372627f7eb2Smrg }
373627f7eb2Smrg
374627f7eb2Smrg dstride = GFC_DESCRIPTOR_STRIDE(retarray,0);
375627f7eb2Smrg dest = retarray->base_addr;
376627f7eb2Smrg for (n = 0; n<rank; n++)
377627f7eb2Smrg dest[n * dstride] = 0 ;
378627f7eb2Smrg }
379627f7eb2Smrg
380627f7eb2Smrg #endif
381627f7eb2Smrg
382627f7eb2Smrg
383627f7eb2Smrg
384