1181254a7Smrg
2181254a7Smrg /* Implementation of the FINDLOC intrinsic
3*b1e83836Smrg Copyright (C) 2018-2022 Free Software Foundation, Inc.
4181254a7Smrg Contributed by Thomas König <tk@tkoenig.net>
5181254a7Smrg
6181254a7Smrg This file is part of the GNU Fortran 95 runtime library (libgfortran).
7181254a7Smrg
8181254a7Smrg Libgfortran is free software; you can redistribute it and/or
9181254a7Smrg modify it under the terms of the GNU General Public
10181254a7Smrg License as published by the Free Software Foundation; either
11181254a7Smrg version 3 of the License, or (at your option) any later version.
12181254a7Smrg
13181254a7Smrg Libgfortran is distributed in the hope that it will be useful,
14181254a7Smrg but WITHOUT ANY WARRANTY; without even the implied warranty of
15181254a7Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16181254a7Smrg GNU General Public License for more details.
17181254a7Smrg
18181254a7Smrg Under Section 7 of GPL version 3, you are granted additional
19181254a7Smrg permissions described in the GCC Runtime Library Exception, version
20181254a7Smrg 3.1, as published by the Free Software Foundation.
21181254a7Smrg
22181254a7Smrg You should have received a copy of the GNU General Public License and
23181254a7Smrg a copy of the GCC Runtime Library Exception along with this program;
24181254a7Smrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25181254a7Smrg <http://www.gnu.org/licenses/>. */
26181254a7Smrg
27181254a7Smrg #include "libgfortran.h"
28181254a7Smrg #include <assert.h>
29181254a7Smrg
30181254a7Smrg #if defined (HAVE_GFC_UINTEGER_1)
31181254a7Smrg extern void findloc0_s1 (gfc_array_index_type * const restrict retarray,
32181254a7Smrg gfc_array_s1 * const restrict array, GFC_UINTEGER_1 *value,
33181254a7Smrg GFC_LOGICAL_4 back, gfc_charlen_type len_array, gfc_charlen_type len_value);
34181254a7Smrg
35181254a7Smrg export_proto(findloc0_s1);
36181254a7Smrg
37181254a7Smrg 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)38181254a7Smrg findloc0_s1 (gfc_array_index_type * const restrict retarray,
39181254a7Smrg gfc_array_s1 * const restrict array, GFC_UINTEGER_1 *value,
40181254a7Smrg GFC_LOGICAL_4 back, gfc_charlen_type len_array, gfc_charlen_type len_value)
41181254a7Smrg {
42181254a7Smrg index_type count[GFC_MAX_DIMENSIONS];
43181254a7Smrg index_type extent[GFC_MAX_DIMENSIONS];
44181254a7Smrg index_type sstride[GFC_MAX_DIMENSIONS];
45181254a7Smrg index_type dstride;
46181254a7Smrg const GFC_UINTEGER_1 *base;
47181254a7Smrg index_type * restrict dest;
48181254a7Smrg index_type rank;
49181254a7Smrg index_type n;
50181254a7Smrg index_type sz;
51181254a7Smrg
52181254a7Smrg rank = GFC_DESCRIPTOR_RANK (array);
53181254a7Smrg if (rank <= 0)
54181254a7Smrg runtime_error ("Rank of array needs to be > 0");
55181254a7Smrg
56181254a7Smrg if (retarray->base_addr == NULL)
57181254a7Smrg {
58181254a7Smrg GFC_DIMENSION_SET(retarray->dim[0], 0, rank-1, 1);
59181254a7Smrg retarray->dtype.rank = 1;
60181254a7Smrg retarray->offset = 0;
61181254a7Smrg retarray->base_addr = xmallocarray (rank, sizeof (index_type));
62181254a7Smrg }
63181254a7Smrg else
64181254a7Smrg {
65181254a7Smrg if (unlikely (compile_options.bounds_check))
66181254a7Smrg bounds_iforeach_return ((array_t *) retarray, (array_t *) array,
67181254a7Smrg "FINDLOC");
68181254a7Smrg }
69181254a7Smrg
70181254a7Smrg dstride = GFC_DESCRIPTOR_STRIDE(retarray,0);
71181254a7Smrg dest = retarray->base_addr;
72181254a7Smrg
73181254a7Smrg /* Set the return value. */
74181254a7Smrg for (n = 0; n < rank; n++)
75181254a7Smrg dest[n * dstride] = 0;
76181254a7Smrg
77181254a7Smrg sz = 1;
78181254a7Smrg for (n = 0; n < rank; n++)
79181254a7Smrg {
80181254a7Smrg sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n);
81181254a7Smrg extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
82181254a7Smrg sz *= extent[n];
83181254a7Smrg if (extent[n] <= 0)
84181254a7Smrg return;
85181254a7Smrg }
86181254a7Smrg
87181254a7Smrg for (n = 0; n < rank; n++)
88181254a7Smrg count[n] = 0;
89181254a7Smrg
90181254a7Smrg if (back)
91181254a7Smrg {
92181254a7Smrg base = array->base_addr + (sz - 1) * len_array;
93181254a7Smrg
94181254a7Smrg while (1)
95181254a7Smrg {
96181254a7Smrg do
97181254a7Smrg {
98181254a7Smrg if (unlikely(compare_string (len_array, (char *) base, len_value, (char *) value) == 0))
99181254a7Smrg {
100181254a7Smrg for (n = 0; n < rank; n++)
101181254a7Smrg dest[n * dstride] = extent[n] - count[n];
102181254a7Smrg
103181254a7Smrg return;
104181254a7Smrg }
105181254a7Smrg base -= sstride[0] * len_array;
106181254a7Smrg } while(++count[0] != extent[0]);
107181254a7Smrg
108181254a7Smrg n = 0;
109181254a7Smrg do
110181254a7Smrg {
111181254a7Smrg /* When we get to the end of a dimension, reset it and increment
112181254a7Smrg the next dimension. */
113181254a7Smrg count[n] = 0;
114181254a7Smrg /* We could precalculate these products, but this is a less
115181254a7Smrg frequently used path so probably not worth it. */
116181254a7Smrg base += sstride[n] * extent[n] * len_array;
117181254a7Smrg n++;
118181254a7Smrg if (n >= rank)
119181254a7Smrg return;
120181254a7Smrg else
121181254a7Smrg {
122181254a7Smrg count[n]++;
123181254a7Smrg base -= sstride[n] * len_array;
124181254a7Smrg }
125181254a7Smrg } while (count[n] == extent[n]);
126181254a7Smrg }
127181254a7Smrg }
128181254a7Smrg else
129181254a7Smrg {
130181254a7Smrg base = array->base_addr;
131181254a7Smrg while (1)
132181254a7Smrg {
133181254a7Smrg do
134181254a7Smrg {
135181254a7Smrg if (unlikely(compare_string (len_array, (char *) base, len_value, (char *) value) == 0))
136181254a7Smrg {
137181254a7Smrg for (n = 0; n < rank; n++)
138181254a7Smrg dest[n * dstride] = count[n] + 1;
139181254a7Smrg
140181254a7Smrg return;
141181254a7Smrg }
142181254a7Smrg base += sstride[0] * len_array;
143181254a7Smrg } while(++count[0] != extent[0]);
144181254a7Smrg
145181254a7Smrg n = 0;
146181254a7Smrg do
147181254a7Smrg {
148181254a7Smrg /* When we get to the end of a dimension, reset it and increment
149181254a7Smrg the next dimension. */
150181254a7Smrg count[n] = 0;
151181254a7Smrg /* We could precalculate these products, but this is a less
152181254a7Smrg frequently used path so probably not worth it. */
153181254a7Smrg base -= sstride[n] * extent[n] * len_array;
154181254a7Smrg n++;
155181254a7Smrg if (n >= rank)
156181254a7Smrg return;
157181254a7Smrg else
158181254a7Smrg {
159181254a7Smrg count[n]++;
160181254a7Smrg base += sstride[n] * len_array;
161181254a7Smrg }
162181254a7Smrg } while (count[n] == extent[n]);
163181254a7Smrg }
164181254a7Smrg }
165181254a7Smrg return;
166181254a7Smrg }
167181254a7Smrg
168181254a7Smrg extern void mfindloc0_s1 (gfc_array_index_type * const restrict retarray,
169181254a7Smrg gfc_array_s1 * const restrict array, GFC_UINTEGER_1 *value,
170181254a7Smrg gfc_array_l1 *const restrict, GFC_LOGICAL_4 back, gfc_charlen_type len_array,
171181254a7Smrg gfc_charlen_type len_value);
172181254a7Smrg export_proto(mfindloc0_s1);
173181254a7Smrg
174181254a7Smrg 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)175181254a7Smrg mfindloc0_s1 (gfc_array_index_type * const restrict retarray,
176181254a7Smrg gfc_array_s1 * const restrict array, GFC_UINTEGER_1 *value,
177181254a7Smrg gfc_array_l1 *const restrict mask, GFC_LOGICAL_4 back,
178181254a7Smrg gfc_charlen_type len_array, gfc_charlen_type len_value)
179181254a7Smrg {
180181254a7Smrg index_type count[GFC_MAX_DIMENSIONS];
181181254a7Smrg index_type extent[GFC_MAX_DIMENSIONS];
182181254a7Smrg index_type sstride[GFC_MAX_DIMENSIONS];
183181254a7Smrg index_type mstride[GFC_MAX_DIMENSIONS];
184181254a7Smrg index_type dstride;
185181254a7Smrg const GFC_UINTEGER_1 *base;
186181254a7Smrg index_type * restrict dest;
187181254a7Smrg GFC_LOGICAL_1 *mbase;
188181254a7Smrg index_type rank;
189181254a7Smrg index_type n;
190181254a7Smrg int mask_kind;
191181254a7Smrg index_type sz;
192181254a7Smrg
193181254a7Smrg rank = GFC_DESCRIPTOR_RANK (array);
194181254a7Smrg if (rank <= 0)
195181254a7Smrg runtime_error ("Rank of array needs to be > 0");
196181254a7Smrg
197181254a7Smrg if (retarray->base_addr == NULL)
198181254a7Smrg {
199181254a7Smrg GFC_DIMENSION_SET(retarray->dim[0], 0, rank-1, 1);
200181254a7Smrg retarray->dtype.rank = 1;
201181254a7Smrg retarray->offset = 0;
202181254a7Smrg retarray->base_addr = xmallocarray (rank, sizeof (index_type));
203181254a7Smrg }
204181254a7Smrg else
205181254a7Smrg {
206181254a7Smrg if (unlikely (compile_options.bounds_check))
207181254a7Smrg {
208181254a7Smrg bounds_iforeach_return ((array_t *) retarray, (array_t *) array,
209181254a7Smrg "FINDLOC");
210181254a7Smrg bounds_equal_extents ((array_t *) mask, (array_t *) array,
211181254a7Smrg "MASK argument", "FINDLOC");
212181254a7Smrg }
213181254a7Smrg }
214181254a7Smrg
215181254a7Smrg mask_kind = GFC_DESCRIPTOR_SIZE (mask);
216181254a7Smrg
217181254a7Smrg mbase = mask->base_addr;
218181254a7Smrg
219181254a7Smrg if (mask_kind == 1 || mask_kind == 2 || mask_kind == 4 || mask_kind == 8
220181254a7Smrg #ifdef HAVE_GFC_LOGICAL_16
221181254a7Smrg || mask_kind == 16
222181254a7Smrg #endif
223181254a7Smrg )
224181254a7Smrg mbase = GFOR_POINTER_TO_L1 (mbase, mask_kind);
225181254a7Smrg else
226181254a7Smrg internal_error (NULL, "Funny sized logical array");
227181254a7Smrg
228181254a7Smrg dstride = GFC_DESCRIPTOR_STRIDE(retarray,0);
229181254a7Smrg dest = retarray->base_addr;
230181254a7Smrg
231181254a7Smrg /* Set the return value. */
232181254a7Smrg for (n = 0; n < rank; n++)
233181254a7Smrg dest[n * dstride] = 0;
234181254a7Smrg
235181254a7Smrg sz = 1;
236181254a7Smrg for (n = 0; n < rank; n++)
237181254a7Smrg {
238181254a7Smrg sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n);
239181254a7Smrg mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n);
240181254a7Smrg extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
241181254a7Smrg sz *= extent[n];
242181254a7Smrg if (extent[n] <= 0)
243181254a7Smrg return;
244181254a7Smrg }
245181254a7Smrg
246181254a7Smrg for (n = 0; n < rank; n++)
247181254a7Smrg count[n] = 0;
248181254a7Smrg
249181254a7Smrg if (back)
250181254a7Smrg {
251181254a7Smrg base = array->base_addr + (sz - 1) * len_array;
252181254a7Smrg mbase = mbase + (sz - 1) * mask_kind;
253181254a7Smrg while (1)
254181254a7Smrg {
255181254a7Smrg do
256181254a7Smrg {
257181254a7Smrg if (unlikely(*mbase && compare_string (len_array, (char *) base, len_value, (char *) value) == 0))
258181254a7Smrg {
259181254a7Smrg for (n = 0; n < rank; n++)
260181254a7Smrg dest[n * dstride] = extent[n] - count[n];
261181254a7Smrg
262181254a7Smrg return;
263181254a7Smrg }
264181254a7Smrg base -= sstride[0] * len_array;
265181254a7Smrg mbase -= mstride[0];
266181254a7Smrg } while(++count[0] != extent[0]);
267181254a7Smrg
268181254a7Smrg n = 0;
269181254a7Smrg do
270181254a7Smrg {
271181254a7Smrg /* When we get to the end of a dimension, reset it and increment
272181254a7Smrg the next dimension. */
273181254a7Smrg count[n] = 0;
274181254a7Smrg /* We could precalculate these products, but this is a less
275181254a7Smrg frequently used path so probably not worth it. */
276181254a7Smrg base += sstride[n] * extent[n] * len_array;
277181254a7Smrg mbase -= mstride[n] * extent[n];
278181254a7Smrg n++;
279181254a7Smrg if (n >= rank)
280181254a7Smrg return;
281181254a7Smrg else
282181254a7Smrg {
283181254a7Smrg count[n]++;
284181254a7Smrg base -= sstride[n] * len_array;
285181254a7Smrg mbase += mstride[n];
286181254a7Smrg }
287181254a7Smrg } while (count[n] == extent[n]);
288181254a7Smrg }
289181254a7Smrg }
290181254a7Smrg else
291181254a7Smrg {
292181254a7Smrg base = array->base_addr;
293181254a7Smrg while (1)
294181254a7Smrg {
295181254a7Smrg do
296181254a7Smrg {
297181254a7Smrg if (unlikely(*mbase && compare_string (len_array, (char *) base, len_value, (char *) value) == 0))
298181254a7Smrg {
299181254a7Smrg for (n = 0; n < rank; n++)
300181254a7Smrg dest[n * dstride] = count[n] + 1;
301181254a7Smrg
302181254a7Smrg return;
303181254a7Smrg }
304181254a7Smrg base += sstride[0] * len_array;
305181254a7Smrg mbase += mstride[0];
306181254a7Smrg } while(++count[0] != extent[0]);
307181254a7Smrg
308181254a7Smrg n = 0;
309181254a7Smrg do
310181254a7Smrg {
311181254a7Smrg /* When we get to the end of a dimension, reset it and increment
312181254a7Smrg the next dimension. */
313181254a7Smrg count[n] = 0;
314181254a7Smrg /* We could precalculate these products, but this is a less
315181254a7Smrg frequently used path so probably not worth it. */
316181254a7Smrg base -= sstride[n] * extent[n] * len_array;
317181254a7Smrg mbase -= mstride[n] * extent[n];
318181254a7Smrg n++;
319181254a7Smrg if (n >= rank)
320181254a7Smrg return;
321181254a7Smrg else
322181254a7Smrg {
323181254a7Smrg count[n]++;
324181254a7Smrg base += sstride[n]* len_array;
325181254a7Smrg mbase += mstride[n];
326181254a7Smrg }
327181254a7Smrg } while (count[n] == extent[n]);
328181254a7Smrg }
329181254a7Smrg }
330181254a7Smrg return;
331181254a7Smrg }
332181254a7Smrg
333181254a7Smrg extern void sfindloc0_s1 (gfc_array_index_type * const restrict retarray,
334181254a7Smrg gfc_array_s1 * const restrict array, GFC_UINTEGER_1 *value,
335181254a7Smrg GFC_LOGICAL_4 *, GFC_LOGICAL_4 back, gfc_charlen_type len_array,
336181254a7Smrg gfc_charlen_type len_value);
337181254a7Smrg export_proto(sfindloc0_s1);
338181254a7Smrg
339181254a7Smrg 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)340181254a7Smrg sfindloc0_s1 (gfc_array_index_type * const restrict retarray,
341181254a7Smrg gfc_array_s1 * const restrict array, GFC_UINTEGER_1 *value,
342181254a7Smrg GFC_LOGICAL_4 * mask, GFC_LOGICAL_4 back, gfc_charlen_type len_array,
343181254a7Smrg gfc_charlen_type len_value)
344181254a7Smrg {
345181254a7Smrg index_type rank;
346181254a7Smrg index_type dstride;
347181254a7Smrg index_type * restrict dest;
348181254a7Smrg index_type n;
349181254a7Smrg
350181254a7Smrg if (mask == NULL || *mask)
351181254a7Smrg {
352181254a7Smrg findloc0_s1 (retarray, array, value, back, len_array, len_value);
353181254a7Smrg return;
354181254a7Smrg }
355181254a7Smrg
356181254a7Smrg rank = GFC_DESCRIPTOR_RANK (array);
357181254a7Smrg
358181254a7Smrg if (rank <= 0)
359181254a7Smrg internal_error (NULL, "Rank of array needs to be > 0");
360181254a7Smrg
361181254a7Smrg if (retarray->base_addr == NULL)
362181254a7Smrg {
363181254a7Smrg GFC_DIMENSION_SET(retarray->dim[0], 0, rank-1, 1);
364181254a7Smrg retarray->dtype.rank = 1;
365181254a7Smrg retarray->offset = 0;
366181254a7Smrg retarray->base_addr = xmallocarray (rank, sizeof (index_type));
367181254a7Smrg }
368181254a7Smrg else if (unlikely (compile_options.bounds_check))
369181254a7Smrg {
370181254a7Smrg bounds_iforeach_return ((array_t *) retarray, (array_t *) array,
371181254a7Smrg "FINDLOC");
372181254a7Smrg }
373181254a7Smrg
374181254a7Smrg dstride = GFC_DESCRIPTOR_STRIDE(retarray,0);
375181254a7Smrg dest = retarray->base_addr;
376181254a7Smrg for (n = 0; n<rank; n++)
377181254a7Smrg dest[n * dstride] = 0 ;
378181254a7Smrg }
379181254a7Smrg
380181254a7Smrg #endif
381181254a7Smrg
382181254a7Smrg
383181254a7Smrg
384