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