1627f7eb2Smrg /* Implementation of the MINLOC intrinsic
2*4c3eb207Smrg Copyright (C) 2017-2020 Free Software Foundation, Inc.
3627f7eb2Smrg Contributed by Thomas Koenig
4627f7eb2Smrg
5627f7eb2Smrg This file is part of the GNU Fortran 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
28627f7eb2Smrg
29627f7eb2Smrg #if defined (HAVE_GFC_UINTEGER_4) && defined (HAVE_GFC_INTEGER_8)
30627f7eb2Smrg
31627f7eb2Smrg #define HAVE_BACK_ARG 1
32627f7eb2Smrg
33627f7eb2Smrg #include <string.h>
34627f7eb2Smrg #include <assert.h>
35627f7eb2Smrg
36627f7eb2Smrg static inline int
compare_fcn(const GFC_UINTEGER_4 * a,const GFC_UINTEGER_4 * b,gfc_charlen_type n)37627f7eb2Smrg compare_fcn (const GFC_UINTEGER_4 *a, const GFC_UINTEGER_4 *b, gfc_charlen_type n)
38627f7eb2Smrg {
39627f7eb2Smrg if (sizeof (GFC_UINTEGER_4) == 1)
40627f7eb2Smrg return memcmp (a, b, n);
41627f7eb2Smrg else
42627f7eb2Smrg return memcmp_char4 (a, b, n);
43627f7eb2Smrg }
44627f7eb2Smrg
45627f7eb2Smrg extern void minloc1_8_s4 (gfc_array_i8 * const restrict,
46627f7eb2Smrg gfc_array_s4 * const restrict, const index_type * const restrict , GFC_LOGICAL_4 back,
47627f7eb2Smrg gfc_charlen_type);
48627f7eb2Smrg export_proto(minloc1_8_s4);
49627f7eb2Smrg
50627f7eb2Smrg void
minloc1_8_s4(gfc_array_i8 * const restrict retarray,gfc_array_s4 * const restrict array,const index_type * const restrict pdim,GFC_LOGICAL_4 back,gfc_charlen_type string_len)51627f7eb2Smrg minloc1_8_s4 (gfc_array_i8 * const restrict retarray,
52627f7eb2Smrg gfc_array_s4 * const restrict array,
53627f7eb2Smrg const index_type * const restrict pdim, GFC_LOGICAL_4 back,
54627f7eb2Smrg gfc_charlen_type string_len)
55627f7eb2Smrg {
56627f7eb2Smrg index_type count[GFC_MAX_DIMENSIONS];
57627f7eb2Smrg index_type extent[GFC_MAX_DIMENSIONS];
58627f7eb2Smrg index_type sstride[GFC_MAX_DIMENSIONS];
59627f7eb2Smrg index_type dstride[GFC_MAX_DIMENSIONS];
60627f7eb2Smrg const GFC_UINTEGER_4 * restrict base;
61627f7eb2Smrg GFC_INTEGER_8 * restrict dest;
62627f7eb2Smrg index_type rank;
63627f7eb2Smrg index_type n;
64627f7eb2Smrg index_type len;
65627f7eb2Smrg index_type delta;
66627f7eb2Smrg index_type dim;
67627f7eb2Smrg int continue_loop;
68627f7eb2Smrg
69627f7eb2Smrg /* Make dim zero based to avoid confusion. */
70627f7eb2Smrg rank = GFC_DESCRIPTOR_RANK (array) - 1;
71627f7eb2Smrg dim = (*pdim) - 1;
72627f7eb2Smrg
73627f7eb2Smrg if (unlikely (dim < 0 || dim > rank))
74627f7eb2Smrg {
75627f7eb2Smrg runtime_error ("Dim argument incorrect in MINLOC intrinsic: "
76627f7eb2Smrg "is %ld, should be between 1 and %ld",
77627f7eb2Smrg (long int) dim + 1, (long int) rank + 1);
78627f7eb2Smrg }
79627f7eb2Smrg
80627f7eb2Smrg len = GFC_DESCRIPTOR_EXTENT(array,dim);
81627f7eb2Smrg if (len < 0)
82627f7eb2Smrg len = 0;
83627f7eb2Smrg delta = GFC_DESCRIPTOR_STRIDE(array,dim) * string_len;
84627f7eb2Smrg
85627f7eb2Smrg for (n = 0; n < dim; n++)
86627f7eb2Smrg {
87627f7eb2Smrg sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n) * string_len;
88627f7eb2Smrg extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
89627f7eb2Smrg
90627f7eb2Smrg if (extent[n] < 0)
91627f7eb2Smrg extent[n] = 0;
92627f7eb2Smrg }
93627f7eb2Smrg for (n = dim; n < rank; n++)
94627f7eb2Smrg {
95627f7eb2Smrg sstride[n] = GFC_DESCRIPTOR_STRIDE(array, n + 1) * string_len;
96627f7eb2Smrg extent[n] = GFC_DESCRIPTOR_EXTENT(array, n + 1);
97627f7eb2Smrg
98627f7eb2Smrg if (extent[n] < 0)
99627f7eb2Smrg extent[n] = 0;
100627f7eb2Smrg }
101627f7eb2Smrg
102627f7eb2Smrg if (retarray->base_addr == NULL)
103627f7eb2Smrg {
104627f7eb2Smrg size_t alloc_size, str;
105627f7eb2Smrg
106627f7eb2Smrg for (n = 0; n < rank; n++)
107627f7eb2Smrg {
108627f7eb2Smrg if (n == 0)
109627f7eb2Smrg str = 1;
110627f7eb2Smrg else
111627f7eb2Smrg str = GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1];
112627f7eb2Smrg
113627f7eb2Smrg GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str);
114627f7eb2Smrg
115627f7eb2Smrg }
116627f7eb2Smrg
117627f7eb2Smrg retarray->offset = 0;
118627f7eb2Smrg retarray->dtype.rank = rank;
119627f7eb2Smrg
120627f7eb2Smrg alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1];
121627f7eb2Smrg
122627f7eb2Smrg retarray->base_addr = xmallocarray (alloc_size, sizeof (GFC_INTEGER_8));
123627f7eb2Smrg if (alloc_size == 0)
124627f7eb2Smrg {
125627f7eb2Smrg /* Make sure we have a zero-sized array. */
126627f7eb2Smrg GFC_DIMENSION_SET(retarray->dim[0], 0, -1, 1);
127627f7eb2Smrg return;
128627f7eb2Smrg
129627f7eb2Smrg }
130627f7eb2Smrg }
131627f7eb2Smrg else
132627f7eb2Smrg {
133627f7eb2Smrg if (rank != GFC_DESCRIPTOR_RANK (retarray))
134627f7eb2Smrg runtime_error ("rank of return array incorrect in"
135627f7eb2Smrg " MINLOC intrinsic: is %ld, should be %ld",
136627f7eb2Smrg (long int) (GFC_DESCRIPTOR_RANK (retarray)),
137627f7eb2Smrg (long int) rank);
138627f7eb2Smrg
139627f7eb2Smrg if (unlikely (compile_options.bounds_check))
140627f7eb2Smrg bounds_ifunction_return ((array_t *) retarray, extent,
141627f7eb2Smrg "return value", "MINLOC");
142627f7eb2Smrg }
143627f7eb2Smrg
144627f7eb2Smrg for (n = 0; n < rank; n++)
145627f7eb2Smrg {
146627f7eb2Smrg count[n] = 0;
147627f7eb2Smrg dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n);
148627f7eb2Smrg if (extent[n] <= 0)
149627f7eb2Smrg return;
150627f7eb2Smrg }
151627f7eb2Smrg
152627f7eb2Smrg base = array->base_addr;
153627f7eb2Smrg dest = retarray->base_addr;
154627f7eb2Smrg
155627f7eb2Smrg continue_loop = 1;
156627f7eb2Smrg while (continue_loop)
157627f7eb2Smrg {
158627f7eb2Smrg const GFC_UINTEGER_4 * restrict src;
159627f7eb2Smrg GFC_INTEGER_8 result;
160627f7eb2Smrg src = base;
161627f7eb2Smrg {
162627f7eb2Smrg
163627f7eb2Smrg const GFC_UINTEGER_4 *minval;
164627f7eb2Smrg minval = NULL;
165627f7eb2Smrg result = 0;
166627f7eb2Smrg if (len <= 0)
167627f7eb2Smrg *dest = 0;
168627f7eb2Smrg else
169627f7eb2Smrg {
170627f7eb2Smrg for (n = 0; n < len; n++, src += delta)
171627f7eb2Smrg {
172627f7eb2Smrg
173627f7eb2Smrg if (minval == NULL || (back ? compare_fcn (src, minval, string_len) <= 0 :
174627f7eb2Smrg compare_fcn (src, minval, string_len) < 0))
175627f7eb2Smrg {
176627f7eb2Smrg minval = src;
177627f7eb2Smrg result = (GFC_INTEGER_8)n + 1;
178627f7eb2Smrg }
179627f7eb2Smrg }
180627f7eb2Smrg
181627f7eb2Smrg *dest = result;
182627f7eb2Smrg }
183627f7eb2Smrg }
184627f7eb2Smrg /* Advance to the next element. */
185627f7eb2Smrg count[0]++;
186627f7eb2Smrg base += sstride[0];
187627f7eb2Smrg dest += dstride[0];
188627f7eb2Smrg n = 0;
189627f7eb2Smrg while (count[n] == extent[n])
190627f7eb2Smrg {
191627f7eb2Smrg /* When we get to the end of a dimension, reset it and increment
192627f7eb2Smrg the next dimension. */
193627f7eb2Smrg count[n] = 0;
194627f7eb2Smrg /* We could precalculate these products, but this is a less
195627f7eb2Smrg frequently used path so probably not worth it. */
196627f7eb2Smrg base -= sstride[n] * extent[n];
197627f7eb2Smrg dest -= dstride[n] * extent[n];
198627f7eb2Smrg n++;
199627f7eb2Smrg if (n >= rank)
200627f7eb2Smrg {
201627f7eb2Smrg /* Break out of the loop. */
202627f7eb2Smrg continue_loop = 0;
203627f7eb2Smrg break;
204627f7eb2Smrg }
205627f7eb2Smrg else
206627f7eb2Smrg {
207627f7eb2Smrg count[n]++;
208627f7eb2Smrg base += sstride[n];
209627f7eb2Smrg dest += dstride[n];
210627f7eb2Smrg }
211627f7eb2Smrg }
212627f7eb2Smrg }
213627f7eb2Smrg }
214627f7eb2Smrg
215627f7eb2Smrg
216627f7eb2Smrg extern void mminloc1_8_s4 (gfc_array_i8 * const restrict,
217627f7eb2Smrg gfc_array_s4 * const restrict, const index_type * const restrict,
218627f7eb2Smrg gfc_array_l1 * const restrict, GFC_LOGICAL_4 back, gfc_charlen_type);
219627f7eb2Smrg export_proto(mminloc1_8_s4);
220627f7eb2Smrg
221627f7eb2Smrg void
mminloc1_8_s4(gfc_array_i8 * const restrict retarray,gfc_array_s4 * const restrict array,const index_type * const restrict pdim,gfc_array_l1 * const restrict mask,GFC_LOGICAL_4 back,gfc_charlen_type string_len)222627f7eb2Smrg mminloc1_8_s4 (gfc_array_i8 * const restrict retarray,
223627f7eb2Smrg gfc_array_s4 * const restrict array,
224627f7eb2Smrg const index_type * const restrict pdim,
225627f7eb2Smrg gfc_array_l1 * const restrict mask, GFC_LOGICAL_4 back,
226627f7eb2Smrg gfc_charlen_type string_len)
227627f7eb2Smrg {
228627f7eb2Smrg index_type count[GFC_MAX_DIMENSIONS];
229627f7eb2Smrg index_type extent[GFC_MAX_DIMENSIONS];
230627f7eb2Smrg index_type sstride[GFC_MAX_DIMENSIONS];
231627f7eb2Smrg index_type dstride[GFC_MAX_DIMENSIONS];
232627f7eb2Smrg index_type mstride[GFC_MAX_DIMENSIONS];
233627f7eb2Smrg GFC_INTEGER_8 * restrict dest;
234627f7eb2Smrg const GFC_UINTEGER_4 * restrict base;
235627f7eb2Smrg const GFC_LOGICAL_1 * restrict mbase;
236627f7eb2Smrg index_type rank;
237627f7eb2Smrg index_type dim;
238627f7eb2Smrg index_type n;
239627f7eb2Smrg index_type len;
240627f7eb2Smrg index_type delta;
241627f7eb2Smrg index_type mdelta;
242627f7eb2Smrg int mask_kind;
243627f7eb2Smrg
244627f7eb2Smrg if (mask == NULL)
245627f7eb2Smrg {
246627f7eb2Smrg #ifdef HAVE_BACK_ARG
247627f7eb2Smrg minloc1_8_s4 (retarray, array, pdim, back, string_len);
248627f7eb2Smrg #else
249627f7eb2Smrg minloc1_8_s4 (retarray, array, pdim, string_len);
250627f7eb2Smrg #endif
251627f7eb2Smrg return;
252627f7eb2Smrg }
253627f7eb2Smrg
254627f7eb2Smrg dim = (*pdim) - 1;
255627f7eb2Smrg rank = GFC_DESCRIPTOR_RANK (array) - 1;
256627f7eb2Smrg
257627f7eb2Smrg
258627f7eb2Smrg if (unlikely (dim < 0 || dim > rank))
259627f7eb2Smrg {
260627f7eb2Smrg runtime_error ("Dim argument incorrect in MINLOC intrinsic: "
261627f7eb2Smrg "is %ld, should be between 1 and %ld",
262627f7eb2Smrg (long int) dim + 1, (long int) rank + 1);
263627f7eb2Smrg }
264627f7eb2Smrg
265627f7eb2Smrg len = GFC_DESCRIPTOR_EXTENT(array,dim);
266627f7eb2Smrg if (len <= 0)
267627f7eb2Smrg return;
268627f7eb2Smrg
269627f7eb2Smrg mbase = mask->base_addr;
270627f7eb2Smrg
271627f7eb2Smrg mask_kind = GFC_DESCRIPTOR_SIZE (mask);
272627f7eb2Smrg
273627f7eb2Smrg if (mask_kind == 1 || mask_kind == 2 || mask_kind == 4 || mask_kind == 8
274627f7eb2Smrg #ifdef HAVE_GFC_LOGICAL_16
275627f7eb2Smrg || mask_kind == 16
276627f7eb2Smrg #endif
277627f7eb2Smrg )
278627f7eb2Smrg mbase = GFOR_POINTER_TO_L1 (mbase, mask_kind);
279627f7eb2Smrg else
280627f7eb2Smrg runtime_error ("Funny sized logical array");
281627f7eb2Smrg
282627f7eb2Smrg delta = GFC_DESCRIPTOR_STRIDE(array,dim) * string_len;
283627f7eb2Smrg mdelta = GFC_DESCRIPTOR_STRIDE_BYTES(mask,dim);
284627f7eb2Smrg
285627f7eb2Smrg for (n = 0; n < dim; n++)
286627f7eb2Smrg {
287627f7eb2Smrg sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n) * string_len;
288627f7eb2Smrg mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n);
289627f7eb2Smrg extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
290627f7eb2Smrg
291627f7eb2Smrg if (extent[n] < 0)
292627f7eb2Smrg extent[n] = 0;
293627f7eb2Smrg
294627f7eb2Smrg }
295627f7eb2Smrg for (n = dim; n < rank; n++)
296627f7eb2Smrg {
297627f7eb2Smrg sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n + 1) * string_len;
298627f7eb2Smrg mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask, n + 1);
299627f7eb2Smrg extent[n] = GFC_DESCRIPTOR_EXTENT(array, n + 1);
300627f7eb2Smrg
301627f7eb2Smrg if (extent[n] < 0)
302627f7eb2Smrg extent[n] = 0;
303627f7eb2Smrg }
304627f7eb2Smrg
305627f7eb2Smrg if (retarray->base_addr == NULL)
306627f7eb2Smrg {
307627f7eb2Smrg size_t alloc_size, str;
308627f7eb2Smrg
309627f7eb2Smrg for (n = 0; n < rank; n++)
310627f7eb2Smrg {
311627f7eb2Smrg if (n == 0)
312627f7eb2Smrg str = 1;
313627f7eb2Smrg else
314627f7eb2Smrg str= GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1];
315627f7eb2Smrg
316627f7eb2Smrg GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str);
317627f7eb2Smrg
318627f7eb2Smrg }
319627f7eb2Smrg
320627f7eb2Smrg alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1];
321627f7eb2Smrg
322627f7eb2Smrg retarray->offset = 0;
323627f7eb2Smrg retarray->dtype.rank = rank;
324627f7eb2Smrg
325627f7eb2Smrg if (alloc_size == 0)
326627f7eb2Smrg {
327627f7eb2Smrg /* Make sure we have a zero-sized array. */
328627f7eb2Smrg GFC_DIMENSION_SET(retarray->dim[0], 0, -1, 1);
329627f7eb2Smrg return;
330627f7eb2Smrg }
331627f7eb2Smrg else
332627f7eb2Smrg retarray->base_addr = xmallocarray (alloc_size, sizeof (GFC_INTEGER_8));
333627f7eb2Smrg
334627f7eb2Smrg }
335627f7eb2Smrg else
336627f7eb2Smrg {
337627f7eb2Smrg if (rank != GFC_DESCRIPTOR_RANK (retarray))
338627f7eb2Smrg runtime_error ("rank of return array incorrect in MINLOC intrinsic");
339627f7eb2Smrg
340627f7eb2Smrg if (unlikely (compile_options.bounds_check))
341627f7eb2Smrg {
342627f7eb2Smrg bounds_ifunction_return ((array_t *) retarray, extent,
343627f7eb2Smrg "return value", "MINLOC");
344627f7eb2Smrg bounds_equal_extents ((array_t *) mask, (array_t *) array,
345627f7eb2Smrg "MASK argument", "MINLOC");
346627f7eb2Smrg }
347627f7eb2Smrg }
348627f7eb2Smrg
349627f7eb2Smrg for (n = 0; n < rank; n++)
350627f7eb2Smrg {
351627f7eb2Smrg count[n] = 0;
352627f7eb2Smrg dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n);
353627f7eb2Smrg if (extent[n] <= 0)
354627f7eb2Smrg return;
355627f7eb2Smrg }
356627f7eb2Smrg
357627f7eb2Smrg dest = retarray->base_addr;
358627f7eb2Smrg base = array->base_addr;
359627f7eb2Smrg
360627f7eb2Smrg while (base)
361627f7eb2Smrg {
362627f7eb2Smrg const GFC_UINTEGER_4 * restrict src;
363627f7eb2Smrg const GFC_LOGICAL_1 * restrict msrc;
364627f7eb2Smrg GFC_INTEGER_8 result;
365627f7eb2Smrg src = base;
366627f7eb2Smrg msrc = mbase;
367627f7eb2Smrg {
368627f7eb2Smrg
369627f7eb2Smrg const GFC_UINTEGER_4 *minval;
370627f7eb2Smrg minval = base;
371627f7eb2Smrg result = 0;
372627f7eb2Smrg for (n = 0; n < len; n++, src += delta, msrc += mdelta)
373627f7eb2Smrg {
374627f7eb2Smrg
375627f7eb2Smrg if (*msrc)
376627f7eb2Smrg {
377627f7eb2Smrg minval = src;
378627f7eb2Smrg result = (GFC_INTEGER_8)n + 1;
379627f7eb2Smrg break;
380627f7eb2Smrg }
381627f7eb2Smrg }
382627f7eb2Smrg for (; n < len; n++, src += delta, msrc += mdelta)
383627f7eb2Smrg {
384627f7eb2Smrg if (*msrc && (back ? compare_fcn (src, minval, string_len) <= 0 :
385627f7eb2Smrg compare_fcn (src, minval, string_len) < 0))
386627f7eb2Smrg {
387627f7eb2Smrg minval = src;
388627f7eb2Smrg result = (GFC_INTEGER_8)n + 1;
389627f7eb2Smrg }
390627f7eb2Smrg
391627f7eb2Smrg }
392627f7eb2Smrg *dest = result;
393627f7eb2Smrg }
394627f7eb2Smrg /* Advance to the next element. */
395627f7eb2Smrg count[0]++;
396627f7eb2Smrg base += sstride[0];
397627f7eb2Smrg mbase += mstride[0];
398627f7eb2Smrg dest += dstride[0];
399627f7eb2Smrg n = 0;
400627f7eb2Smrg while (count[n] == extent[n])
401627f7eb2Smrg {
402627f7eb2Smrg /* When we get to the end of a dimension, reset it and increment
403627f7eb2Smrg the next dimension. */
404627f7eb2Smrg count[n] = 0;
405627f7eb2Smrg /* We could precalculate these products, but this is a less
406627f7eb2Smrg frequently used path so probably not worth it. */
407627f7eb2Smrg base -= sstride[n] * extent[n];
408627f7eb2Smrg mbase -= mstride[n] * extent[n];
409627f7eb2Smrg dest -= dstride[n] * extent[n];
410627f7eb2Smrg n++;
411627f7eb2Smrg if (n >= rank)
412627f7eb2Smrg {
413627f7eb2Smrg /* Break out of the loop. */
414627f7eb2Smrg base = NULL;
415627f7eb2Smrg break;
416627f7eb2Smrg }
417627f7eb2Smrg else
418627f7eb2Smrg {
419627f7eb2Smrg count[n]++;
420627f7eb2Smrg base += sstride[n];
421627f7eb2Smrg mbase += mstride[n];
422627f7eb2Smrg dest += dstride[n];
423627f7eb2Smrg }
424627f7eb2Smrg }
425627f7eb2Smrg }
426627f7eb2Smrg }
427627f7eb2Smrg
428627f7eb2Smrg
429627f7eb2Smrg extern void sminloc1_8_s4 (gfc_array_i8 * const restrict,
430627f7eb2Smrg gfc_array_s4 * const restrict, const index_type * const restrict,
431627f7eb2Smrg GFC_LOGICAL_4 *, GFC_LOGICAL_4 back, gfc_charlen_type);
432627f7eb2Smrg export_proto(sminloc1_8_s4);
433627f7eb2Smrg
434627f7eb2Smrg void
sminloc1_8_s4(gfc_array_i8 * const restrict retarray,gfc_array_s4 * const restrict array,const index_type * const restrict pdim,GFC_LOGICAL_4 * mask,GFC_LOGICAL_4 back,gfc_charlen_type string_len)435627f7eb2Smrg sminloc1_8_s4 (gfc_array_i8 * const restrict retarray,
436627f7eb2Smrg gfc_array_s4 * const restrict array,
437627f7eb2Smrg const index_type * const restrict pdim,
438627f7eb2Smrg GFC_LOGICAL_4 * mask , GFC_LOGICAL_4 back, gfc_charlen_type string_len)
439627f7eb2Smrg {
440627f7eb2Smrg index_type count[GFC_MAX_DIMENSIONS];
441627f7eb2Smrg index_type extent[GFC_MAX_DIMENSIONS];
442627f7eb2Smrg index_type dstride[GFC_MAX_DIMENSIONS];
443627f7eb2Smrg GFC_INTEGER_8 * restrict dest;
444627f7eb2Smrg index_type rank;
445627f7eb2Smrg index_type n;
446627f7eb2Smrg index_type dim;
447627f7eb2Smrg
448627f7eb2Smrg
449627f7eb2Smrg if (mask == NULL || *mask)
450627f7eb2Smrg {
451627f7eb2Smrg #ifdef HAVE_BACK_ARG
452627f7eb2Smrg minloc1_8_s4 (retarray, array, pdim, back, string_len);
453627f7eb2Smrg #else
454627f7eb2Smrg minloc1_8_s4 (retarray, array, pdim, string_len);
455627f7eb2Smrg #endif
456627f7eb2Smrg return;
457627f7eb2Smrg }
458627f7eb2Smrg /* Make dim zero based to avoid confusion. */
459627f7eb2Smrg dim = (*pdim) - 1;
460627f7eb2Smrg rank = GFC_DESCRIPTOR_RANK (array) - 1;
461627f7eb2Smrg
462627f7eb2Smrg if (unlikely (dim < 0 || dim > rank))
463627f7eb2Smrg {
464627f7eb2Smrg runtime_error ("Dim argument incorrect in MINLOC intrinsic: "
465627f7eb2Smrg "is %ld, should be between 1 and %ld",
466627f7eb2Smrg (long int) dim + 1, (long int) rank + 1);
467627f7eb2Smrg }
468627f7eb2Smrg
469627f7eb2Smrg for (n = 0; n < dim; n++)
470627f7eb2Smrg {
471627f7eb2Smrg extent[n] = GFC_DESCRIPTOR_EXTENT(array,n) * string_len;
472627f7eb2Smrg
473627f7eb2Smrg if (extent[n] <= 0)
474627f7eb2Smrg extent[n] = 0;
475627f7eb2Smrg }
476627f7eb2Smrg
477627f7eb2Smrg for (n = dim; n < rank; n++)
478627f7eb2Smrg {
479627f7eb2Smrg extent[n] =
480627f7eb2Smrg GFC_DESCRIPTOR_EXTENT(array,n + 1) * string_len;
481627f7eb2Smrg
482627f7eb2Smrg if (extent[n] <= 0)
483627f7eb2Smrg extent[n] = 0;
484627f7eb2Smrg }
485627f7eb2Smrg
486627f7eb2Smrg if (retarray->base_addr == NULL)
487627f7eb2Smrg {
488627f7eb2Smrg size_t alloc_size, str;
489627f7eb2Smrg
490627f7eb2Smrg for (n = 0; n < rank; n++)
491627f7eb2Smrg {
492627f7eb2Smrg if (n == 0)
493627f7eb2Smrg str = 1;
494627f7eb2Smrg else
495627f7eb2Smrg str = GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1];
496627f7eb2Smrg
497627f7eb2Smrg GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str);
498627f7eb2Smrg
499627f7eb2Smrg }
500627f7eb2Smrg
501627f7eb2Smrg retarray->offset = 0;
502627f7eb2Smrg retarray->dtype.rank = rank;
503627f7eb2Smrg
504627f7eb2Smrg alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1];
505627f7eb2Smrg
506627f7eb2Smrg if (alloc_size == 0)
507627f7eb2Smrg {
508627f7eb2Smrg /* Make sure we have a zero-sized array. */
509627f7eb2Smrg GFC_DIMENSION_SET(retarray->dim[0], 0, -1, 1);
510627f7eb2Smrg return;
511627f7eb2Smrg }
512627f7eb2Smrg else
513627f7eb2Smrg retarray->base_addr = xmallocarray (alloc_size, sizeof (GFC_INTEGER_8));
514627f7eb2Smrg }
515627f7eb2Smrg else
516627f7eb2Smrg {
517627f7eb2Smrg if (rank != GFC_DESCRIPTOR_RANK (retarray))
518627f7eb2Smrg runtime_error ("rank of return array incorrect in"
519627f7eb2Smrg " MINLOC intrinsic: is %ld, should be %ld",
520627f7eb2Smrg (long int) (GFC_DESCRIPTOR_RANK (retarray)),
521627f7eb2Smrg (long int) rank);
522627f7eb2Smrg
523627f7eb2Smrg if (unlikely (compile_options.bounds_check))
524627f7eb2Smrg {
525627f7eb2Smrg for (n=0; n < rank; n++)
526627f7eb2Smrg {
527627f7eb2Smrg index_type ret_extent;
528627f7eb2Smrg
529627f7eb2Smrg ret_extent = GFC_DESCRIPTOR_EXTENT(retarray,n);
530627f7eb2Smrg if (extent[n] != ret_extent)
531627f7eb2Smrg runtime_error ("Incorrect extent in return value of"
532627f7eb2Smrg " MINLOC intrinsic in dimension %ld:"
533627f7eb2Smrg " is %ld, should be %ld", (long int) n + 1,
534627f7eb2Smrg (long int) ret_extent, (long int) extent[n]);
535627f7eb2Smrg }
536627f7eb2Smrg }
537627f7eb2Smrg }
538627f7eb2Smrg
539627f7eb2Smrg for (n = 0; n < rank; n++)
540627f7eb2Smrg {
541627f7eb2Smrg count[n] = 0;
542627f7eb2Smrg dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n);
543627f7eb2Smrg }
544627f7eb2Smrg
545627f7eb2Smrg dest = retarray->base_addr;
546627f7eb2Smrg
547627f7eb2Smrg while(1)
548627f7eb2Smrg {
549627f7eb2Smrg *dest = 0;
550627f7eb2Smrg count[0]++;
551627f7eb2Smrg dest += dstride[0];
552627f7eb2Smrg n = 0;
553627f7eb2Smrg while (count[n] == extent[n])
554627f7eb2Smrg {
555627f7eb2Smrg /* When we get to the end of a dimension, reset it and increment
556627f7eb2Smrg the next dimension. */
557627f7eb2Smrg count[n] = 0;
558627f7eb2Smrg /* We could precalculate these products, but this is a less
559627f7eb2Smrg frequently used path so probably not worth it. */
560627f7eb2Smrg dest -= dstride[n] * extent[n];
561627f7eb2Smrg n++;
562627f7eb2Smrg if (n >= rank)
563627f7eb2Smrg return;
564627f7eb2Smrg else
565627f7eb2Smrg {
566627f7eb2Smrg count[n]++;
567627f7eb2Smrg dest += dstride[n];
568627f7eb2Smrg }
569627f7eb2Smrg }
570627f7eb2Smrg }
571627f7eb2Smrg }
572627f7eb2Smrg
573627f7eb2Smrg #endif
574