1*b1e83836Smrg /* Implementation of the MAXLOC intrinsic
2*b1e83836Smrg Copyright (C) 2002-2022 Free Software Foundation, Inc.
3*b1e83836Smrg Contributed by Paul Brook <paul@nowt.org>
4*b1e83836Smrg
5*b1e83836Smrg This file is part of the GNU Fortran runtime library (libgfortran).
6*b1e83836Smrg
7*b1e83836Smrg Libgfortran is free software; you can redistribute it and/or
8*b1e83836Smrg modify it under the terms of the GNU General Public
9*b1e83836Smrg License as published by the Free Software Foundation; either
10*b1e83836Smrg version 3 of the License, or (at your option) any later version.
11*b1e83836Smrg
12*b1e83836Smrg Libgfortran is distributed in the hope that it will be useful,
13*b1e83836Smrg but WITHOUT ANY WARRANTY; without even the implied warranty of
14*b1e83836Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15*b1e83836Smrg GNU General Public License for more details.
16*b1e83836Smrg
17*b1e83836Smrg Under Section 7 of GPL version 3, you are granted additional
18*b1e83836Smrg permissions described in the GCC Runtime Library Exception, version
19*b1e83836Smrg 3.1, as published by the Free Software Foundation.
20*b1e83836Smrg
21*b1e83836Smrg You should have received a copy of the GNU General Public License and
22*b1e83836Smrg a copy of the GCC Runtime Library Exception along with this program;
23*b1e83836Smrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24*b1e83836Smrg <http://www.gnu.org/licenses/>. */
25*b1e83836Smrg
26*b1e83836Smrg #include "libgfortran.h"
27*b1e83836Smrg #include <assert.h>
28*b1e83836Smrg
29*b1e83836Smrg
30*b1e83836Smrg #if defined (HAVE_GFC_REAL_17) && defined (HAVE_GFC_INTEGER_4)
31*b1e83836Smrg
32*b1e83836Smrg #define HAVE_BACK_ARG 1
33*b1e83836Smrg
34*b1e83836Smrg
35*b1e83836Smrg extern void maxloc1_4_r17 (gfc_array_i4 * const restrict,
36*b1e83836Smrg gfc_array_r17 * const restrict, const index_type * const restrict, GFC_LOGICAL_4 back);
37*b1e83836Smrg export_proto(maxloc1_4_r17);
38*b1e83836Smrg
39*b1e83836Smrg void
maxloc1_4_r17(gfc_array_i4 * const restrict retarray,gfc_array_r17 * const restrict array,const index_type * const restrict pdim,GFC_LOGICAL_4 back)40*b1e83836Smrg maxloc1_4_r17 (gfc_array_i4 * const restrict retarray,
41*b1e83836Smrg gfc_array_r17 * const restrict array,
42*b1e83836Smrg const index_type * const restrict pdim, GFC_LOGICAL_4 back)
43*b1e83836Smrg {
44*b1e83836Smrg index_type count[GFC_MAX_DIMENSIONS];
45*b1e83836Smrg index_type extent[GFC_MAX_DIMENSIONS];
46*b1e83836Smrg index_type sstride[GFC_MAX_DIMENSIONS];
47*b1e83836Smrg index_type dstride[GFC_MAX_DIMENSIONS];
48*b1e83836Smrg const GFC_REAL_17 * restrict base;
49*b1e83836Smrg GFC_INTEGER_4 * restrict dest;
50*b1e83836Smrg index_type rank;
51*b1e83836Smrg index_type n;
52*b1e83836Smrg index_type len;
53*b1e83836Smrg index_type delta;
54*b1e83836Smrg index_type dim;
55*b1e83836Smrg int continue_loop;
56*b1e83836Smrg
57*b1e83836Smrg /* Make dim zero based to avoid confusion. */
58*b1e83836Smrg rank = GFC_DESCRIPTOR_RANK (array) - 1;
59*b1e83836Smrg dim = (*pdim) - 1;
60*b1e83836Smrg
61*b1e83836Smrg if (unlikely (dim < 0 || dim > rank))
62*b1e83836Smrg {
63*b1e83836Smrg runtime_error ("Dim argument incorrect in MAXLOC intrinsic: "
64*b1e83836Smrg "is %ld, should be between 1 and %ld",
65*b1e83836Smrg (long int) dim + 1, (long int) rank + 1);
66*b1e83836Smrg }
67*b1e83836Smrg
68*b1e83836Smrg len = GFC_DESCRIPTOR_EXTENT(array,dim);
69*b1e83836Smrg if (len < 0)
70*b1e83836Smrg len = 0;
71*b1e83836Smrg delta = GFC_DESCRIPTOR_STRIDE(array,dim);
72*b1e83836Smrg
73*b1e83836Smrg for (n = 0; n < dim; n++)
74*b1e83836Smrg {
75*b1e83836Smrg sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n);
76*b1e83836Smrg extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
77*b1e83836Smrg
78*b1e83836Smrg if (extent[n] < 0)
79*b1e83836Smrg extent[n] = 0;
80*b1e83836Smrg }
81*b1e83836Smrg for (n = dim; n < rank; n++)
82*b1e83836Smrg {
83*b1e83836Smrg sstride[n] = GFC_DESCRIPTOR_STRIDE(array, n + 1);
84*b1e83836Smrg extent[n] = GFC_DESCRIPTOR_EXTENT(array, n + 1);
85*b1e83836Smrg
86*b1e83836Smrg if (extent[n] < 0)
87*b1e83836Smrg extent[n] = 0;
88*b1e83836Smrg }
89*b1e83836Smrg
90*b1e83836Smrg if (retarray->base_addr == NULL)
91*b1e83836Smrg {
92*b1e83836Smrg size_t alloc_size, str;
93*b1e83836Smrg
94*b1e83836Smrg for (n = 0; n < rank; n++)
95*b1e83836Smrg {
96*b1e83836Smrg if (n == 0)
97*b1e83836Smrg str = 1;
98*b1e83836Smrg else
99*b1e83836Smrg str = GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1];
100*b1e83836Smrg
101*b1e83836Smrg GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str);
102*b1e83836Smrg
103*b1e83836Smrg }
104*b1e83836Smrg
105*b1e83836Smrg retarray->offset = 0;
106*b1e83836Smrg retarray->dtype.rank = rank;
107*b1e83836Smrg
108*b1e83836Smrg alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1];
109*b1e83836Smrg
110*b1e83836Smrg retarray->base_addr = xmallocarray (alloc_size, sizeof (GFC_INTEGER_4));
111*b1e83836Smrg if (alloc_size == 0)
112*b1e83836Smrg {
113*b1e83836Smrg /* Make sure we have a zero-sized array. */
114*b1e83836Smrg GFC_DIMENSION_SET(retarray->dim[0], 0, -1, 1);
115*b1e83836Smrg return;
116*b1e83836Smrg
117*b1e83836Smrg }
118*b1e83836Smrg }
119*b1e83836Smrg else
120*b1e83836Smrg {
121*b1e83836Smrg if (rank != GFC_DESCRIPTOR_RANK (retarray))
122*b1e83836Smrg runtime_error ("rank of return array incorrect in"
123*b1e83836Smrg " MAXLOC intrinsic: is %ld, should be %ld",
124*b1e83836Smrg (long int) (GFC_DESCRIPTOR_RANK (retarray)),
125*b1e83836Smrg (long int) rank);
126*b1e83836Smrg
127*b1e83836Smrg if (unlikely (compile_options.bounds_check))
128*b1e83836Smrg bounds_ifunction_return ((array_t *) retarray, extent,
129*b1e83836Smrg "return value", "MAXLOC");
130*b1e83836Smrg }
131*b1e83836Smrg
132*b1e83836Smrg for (n = 0; n < rank; n++)
133*b1e83836Smrg {
134*b1e83836Smrg count[n] = 0;
135*b1e83836Smrg dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n);
136*b1e83836Smrg if (extent[n] <= 0)
137*b1e83836Smrg return;
138*b1e83836Smrg }
139*b1e83836Smrg
140*b1e83836Smrg base = array->base_addr;
141*b1e83836Smrg dest = retarray->base_addr;
142*b1e83836Smrg
143*b1e83836Smrg continue_loop = 1;
144*b1e83836Smrg while (continue_loop)
145*b1e83836Smrg {
146*b1e83836Smrg const GFC_REAL_17 * restrict src;
147*b1e83836Smrg GFC_INTEGER_4 result;
148*b1e83836Smrg src = base;
149*b1e83836Smrg {
150*b1e83836Smrg
151*b1e83836Smrg GFC_REAL_17 maxval;
152*b1e83836Smrg #if defined (GFC_REAL_17_INFINITY)
153*b1e83836Smrg maxval = -GFC_REAL_17_INFINITY;
154*b1e83836Smrg #else
155*b1e83836Smrg maxval = -GFC_REAL_17_HUGE;
156*b1e83836Smrg #endif
157*b1e83836Smrg result = 1;
158*b1e83836Smrg if (len <= 0)
159*b1e83836Smrg *dest = 0;
160*b1e83836Smrg else
161*b1e83836Smrg {
162*b1e83836Smrg #if ! defined HAVE_BACK_ARG
163*b1e83836Smrg for (n = 0; n < len; n++, src += delta)
164*b1e83836Smrg {
165*b1e83836Smrg #endif
166*b1e83836Smrg
167*b1e83836Smrg #if defined (GFC_REAL_17_QUIET_NAN)
168*b1e83836Smrg for (n = 0; n < len; n++, src += delta)
169*b1e83836Smrg {
170*b1e83836Smrg if (*src >= maxval)
171*b1e83836Smrg {
172*b1e83836Smrg maxval = *src;
173*b1e83836Smrg result = (GFC_INTEGER_4)n + 1;
174*b1e83836Smrg break;
175*b1e83836Smrg }
176*b1e83836Smrg }
177*b1e83836Smrg #else
178*b1e83836Smrg n = 0;
179*b1e83836Smrg #endif
180*b1e83836Smrg for (; n < len; n++, src += delta)
181*b1e83836Smrg {
182*b1e83836Smrg if (back ? *src >= maxval : *src > maxval)
183*b1e83836Smrg {
184*b1e83836Smrg maxval = *src;
185*b1e83836Smrg result = (GFC_INTEGER_4)n + 1;
186*b1e83836Smrg }
187*b1e83836Smrg }
188*b1e83836Smrg
189*b1e83836Smrg *dest = result;
190*b1e83836Smrg }
191*b1e83836Smrg }
192*b1e83836Smrg /* Advance to the next element. */
193*b1e83836Smrg count[0]++;
194*b1e83836Smrg base += sstride[0];
195*b1e83836Smrg dest += dstride[0];
196*b1e83836Smrg n = 0;
197*b1e83836Smrg while (count[n] == extent[n])
198*b1e83836Smrg {
199*b1e83836Smrg /* When we get to the end of a dimension, reset it and increment
200*b1e83836Smrg the next dimension. */
201*b1e83836Smrg count[n] = 0;
202*b1e83836Smrg /* We could precalculate these products, but this is a less
203*b1e83836Smrg frequently used path so probably not worth it. */
204*b1e83836Smrg base -= sstride[n] * extent[n];
205*b1e83836Smrg dest -= dstride[n] * extent[n];
206*b1e83836Smrg n++;
207*b1e83836Smrg if (n >= rank)
208*b1e83836Smrg {
209*b1e83836Smrg /* Break out of the loop. */
210*b1e83836Smrg continue_loop = 0;
211*b1e83836Smrg break;
212*b1e83836Smrg }
213*b1e83836Smrg else
214*b1e83836Smrg {
215*b1e83836Smrg count[n]++;
216*b1e83836Smrg base += sstride[n];
217*b1e83836Smrg dest += dstride[n];
218*b1e83836Smrg }
219*b1e83836Smrg }
220*b1e83836Smrg }
221*b1e83836Smrg }
222*b1e83836Smrg
223*b1e83836Smrg
224*b1e83836Smrg extern void mmaxloc1_4_r17 (gfc_array_i4 * const restrict,
225*b1e83836Smrg gfc_array_r17 * const restrict, const index_type * const restrict,
226*b1e83836Smrg gfc_array_l1 * const restrict, GFC_LOGICAL_4 back);
227*b1e83836Smrg export_proto(mmaxloc1_4_r17);
228*b1e83836Smrg
229*b1e83836Smrg void
230*b1e83836Smrg mmaxloc1_4_r17 (gfc_array_i4 * const restrict retarray,
231*b1e83836Smrg gfc_array_r17 * const restrict array,
232*b1e83836Smrg const index_type * const restrict pdim,
233*b1e83836Smrg gfc_array_l1 * const restrict mask, GFC_LOGICAL_4 back)
234*b1e83836Smrg {
235*b1e83836Smrg index_type count[GFC_MAX_DIMENSIONS];
236*b1e83836Smrg index_type extent[GFC_MAX_DIMENSIONS];
237*b1e83836Smrg index_type sstride[GFC_MAX_DIMENSIONS];
238*b1e83836Smrg index_type dstride[GFC_MAX_DIMENSIONS];
239*b1e83836Smrg index_type mstride[GFC_MAX_DIMENSIONS];
240*b1e83836Smrg GFC_INTEGER_4 * restrict dest;
241*b1e83836Smrg const GFC_REAL_17 * restrict base;
242*b1e83836Smrg const GFC_LOGICAL_1 * restrict mbase;
243*b1e83836Smrg index_type rank;
244*b1e83836Smrg index_type dim;
245*b1e83836Smrg index_type n;
246*b1e83836Smrg index_type len;
247*b1e83836Smrg index_type delta;
248*b1e83836Smrg index_type mdelta;
249*b1e83836Smrg int mask_kind;
250*b1e83836Smrg
251*b1e83836Smrg if (mask == NULL)
252*b1e83836Smrg {
253*b1e83836Smrg #ifdef HAVE_BACK_ARG
254*b1e83836Smrg maxloc1_4_r17 (retarray, array, pdim, back);
255*b1e83836Smrg #else
256*b1e83836Smrg maxloc1_4_r17 (retarray, array, pdim);
257*b1e83836Smrg #endif
258*b1e83836Smrg return;
259*b1e83836Smrg }
260*b1e83836Smrg
261*b1e83836Smrg dim = (*pdim) - 1;
262*b1e83836Smrg rank = GFC_DESCRIPTOR_RANK (array) - 1;
263*b1e83836Smrg
264*b1e83836Smrg
265*b1e83836Smrg if (unlikely (dim < 0 || dim > rank))
266*b1e83836Smrg {
267*b1e83836Smrg runtime_error ("Dim argument incorrect in MAXLOC intrinsic: "
268*b1e83836Smrg "is %ld, should be between 1 and %ld",
269*b1e83836Smrg (long int) dim + 1, (long int) rank + 1);
270*b1e83836Smrg }
271*b1e83836Smrg
272*b1e83836Smrg len = GFC_DESCRIPTOR_EXTENT(array,dim);
273*b1e83836Smrg if (len <= 0)
274*b1e83836Smrg return;
275*b1e83836Smrg
276*b1e83836Smrg mbase = mask->base_addr;
277*b1e83836Smrg
278*b1e83836Smrg mask_kind = GFC_DESCRIPTOR_SIZE (mask);
279*b1e83836Smrg
280*b1e83836Smrg if (mask_kind == 1 || mask_kind == 2 || mask_kind == 4 || mask_kind == 8
281*b1e83836Smrg #ifdef HAVE_GFC_LOGICAL_16
282*b1e83836Smrg || mask_kind == 16
283*b1e83836Smrg #endif
284*b1e83836Smrg )
285*b1e83836Smrg mbase = GFOR_POINTER_TO_L1 (mbase, mask_kind);
286*b1e83836Smrg else
287*b1e83836Smrg runtime_error ("Funny sized logical array");
288*b1e83836Smrg
289*b1e83836Smrg delta = GFC_DESCRIPTOR_STRIDE(array,dim);
290*b1e83836Smrg mdelta = GFC_DESCRIPTOR_STRIDE_BYTES(mask,dim);
291*b1e83836Smrg
292*b1e83836Smrg for (n = 0; n < dim; n++)
293*b1e83836Smrg {
294*b1e83836Smrg sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n);
295*b1e83836Smrg mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n);
296*b1e83836Smrg extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
297*b1e83836Smrg
298*b1e83836Smrg if (extent[n] < 0)
299*b1e83836Smrg extent[n] = 0;
300*b1e83836Smrg
301*b1e83836Smrg }
302*b1e83836Smrg for (n = dim; n < rank; n++)
303*b1e83836Smrg {
304*b1e83836Smrg sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n + 1);
305*b1e83836Smrg mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask, n + 1);
306*b1e83836Smrg extent[n] = GFC_DESCRIPTOR_EXTENT(array, n + 1);
307*b1e83836Smrg
308*b1e83836Smrg if (extent[n] < 0)
309*b1e83836Smrg extent[n] = 0;
310*b1e83836Smrg }
311*b1e83836Smrg
312*b1e83836Smrg if (retarray->base_addr == NULL)
313*b1e83836Smrg {
314*b1e83836Smrg size_t alloc_size, str;
315*b1e83836Smrg
316*b1e83836Smrg for (n = 0; n < rank; n++)
317*b1e83836Smrg {
318*b1e83836Smrg if (n == 0)
319*b1e83836Smrg str = 1;
320*b1e83836Smrg else
321*b1e83836Smrg str= GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1];
322*b1e83836Smrg
323*b1e83836Smrg GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str);
324*b1e83836Smrg
325*b1e83836Smrg }
326*b1e83836Smrg
327*b1e83836Smrg alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1];
328*b1e83836Smrg
329*b1e83836Smrg retarray->offset = 0;
330*b1e83836Smrg retarray->dtype.rank = rank;
331*b1e83836Smrg
332*b1e83836Smrg if (alloc_size == 0)
333*b1e83836Smrg {
334*b1e83836Smrg /* Make sure we have a zero-sized array. */
335*b1e83836Smrg GFC_DIMENSION_SET(retarray->dim[0], 0, -1, 1);
336*b1e83836Smrg return;
337*b1e83836Smrg }
338*b1e83836Smrg else
339*b1e83836Smrg retarray->base_addr = xmallocarray (alloc_size, sizeof (GFC_INTEGER_4));
340*b1e83836Smrg
341*b1e83836Smrg }
342*b1e83836Smrg else
343*b1e83836Smrg {
344*b1e83836Smrg if (rank != GFC_DESCRIPTOR_RANK (retarray))
345*b1e83836Smrg runtime_error ("rank of return array incorrect in MAXLOC intrinsic");
346*b1e83836Smrg
347*b1e83836Smrg if (unlikely (compile_options.bounds_check))
348*b1e83836Smrg {
349*b1e83836Smrg bounds_ifunction_return ((array_t *) retarray, extent,
350*b1e83836Smrg "return value", "MAXLOC");
351*b1e83836Smrg bounds_equal_extents ((array_t *) mask, (array_t *) array,
352*b1e83836Smrg "MASK argument", "MAXLOC");
353*b1e83836Smrg }
354*b1e83836Smrg }
355*b1e83836Smrg
356*b1e83836Smrg for (n = 0; n < rank; n++)
357*b1e83836Smrg {
358*b1e83836Smrg count[n] = 0;
359*b1e83836Smrg dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n);
360*b1e83836Smrg if (extent[n] <= 0)
361*b1e83836Smrg return;
362*b1e83836Smrg }
363*b1e83836Smrg
364*b1e83836Smrg dest = retarray->base_addr;
365*b1e83836Smrg base = array->base_addr;
366*b1e83836Smrg
367*b1e83836Smrg while (base)
368*b1e83836Smrg {
369*b1e83836Smrg const GFC_REAL_17 * restrict src;
370*b1e83836Smrg const GFC_LOGICAL_1 * restrict msrc;
371*b1e83836Smrg GFC_INTEGER_4 result;
372*b1e83836Smrg src = base;
373*b1e83836Smrg msrc = mbase;
374*b1e83836Smrg {
375*b1e83836Smrg
376*b1e83836Smrg GFC_REAL_17 maxval;
377*b1e83836Smrg #if defined (GFC_REAL_17_INFINITY)
378*b1e83836Smrg maxval = -GFC_REAL_17_INFINITY;
379*b1e83836Smrg #else
380*b1e83836Smrg maxval = -GFC_REAL_17_HUGE;
381*b1e83836Smrg #endif
382*b1e83836Smrg #if defined (GFC_REAL_17_QUIET_NAN)
383*b1e83836Smrg GFC_INTEGER_4 result2 = 0;
384*b1e83836Smrg #endif
385*b1e83836Smrg result = 0;
386*b1e83836Smrg for (n = 0; n < len; n++, src += delta, msrc += mdelta)
387*b1e83836Smrg {
388*b1e83836Smrg
389*b1e83836Smrg if (*msrc)
390*b1e83836Smrg {
391*b1e83836Smrg #if defined (GFC_REAL_17_QUIET_NAN)
392*b1e83836Smrg if (!result2)
393*b1e83836Smrg result2 = (GFC_INTEGER_4)n + 1;
394*b1e83836Smrg if (*src >= maxval)
395*b1e83836Smrg #endif
396*b1e83836Smrg {
397*b1e83836Smrg maxval = *src;
398*b1e83836Smrg result = (GFC_INTEGER_4)n + 1;
399*b1e83836Smrg break;
400*b1e83836Smrg }
401*b1e83836Smrg }
402*b1e83836Smrg }
403*b1e83836Smrg #if defined (GFC_REAL_17_QUIET_NAN)
404*b1e83836Smrg if (unlikely (n >= len))
405*b1e83836Smrg result = result2;
406*b1e83836Smrg else
407*b1e83836Smrg #endif
408*b1e83836Smrg if (back)
409*b1e83836Smrg for (; n < len; n++, src += delta, msrc += mdelta)
410*b1e83836Smrg {
411*b1e83836Smrg if (*msrc && unlikely (*src >= maxval))
412*b1e83836Smrg {
413*b1e83836Smrg maxval = *src;
414*b1e83836Smrg result = (GFC_INTEGER_4)n + 1;
415*b1e83836Smrg }
416*b1e83836Smrg }
417*b1e83836Smrg else
418*b1e83836Smrg for (; n < len; n++, src += delta, msrc += mdelta)
419*b1e83836Smrg {
420*b1e83836Smrg if (*msrc && unlikely (*src > maxval))
421*b1e83836Smrg {
422*b1e83836Smrg maxval = *src;
423*b1e83836Smrg result = (GFC_INTEGER_4)n + 1;
424*b1e83836Smrg }
425*b1e83836Smrg }
426*b1e83836Smrg *dest = result;
427*b1e83836Smrg }
428*b1e83836Smrg /* Advance to the next element. */
429*b1e83836Smrg count[0]++;
430*b1e83836Smrg base += sstride[0];
431*b1e83836Smrg mbase += mstride[0];
432*b1e83836Smrg dest += dstride[0];
433*b1e83836Smrg n = 0;
434*b1e83836Smrg while (count[n] == extent[n])
435*b1e83836Smrg {
436*b1e83836Smrg /* When we get to the end of a dimension, reset it and increment
437*b1e83836Smrg the next dimension. */
438*b1e83836Smrg count[n] = 0;
439*b1e83836Smrg /* We could precalculate these products, but this is a less
440*b1e83836Smrg frequently used path so probably not worth it. */
441*b1e83836Smrg base -= sstride[n] * extent[n];
442*b1e83836Smrg mbase -= mstride[n] * extent[n];
443*b1e83836Smrg dest -= dstride[n] * extent[n];
444*b1e83836Smrg n++;
445*b1e83836Smrg if (n >= rank)
446*b1e83836Smrg {
447*b1e83836Smrg /* Break out of the loop. */
448*b1e83836Smrg base = NULL;
449*b1e83836Smrg break;
450*b1e83836Smrg }
451*b1e83836Smrg else
452*b1e83836Smrg {
453*b1e83836Smrg count[n]++;
454*b1e83836Smrg base += sstride[n];
455*b1e83836Smrg mbase += mstride[n];
456*b1e83836Smrg dest += dstride[n];
457*b1e83836Smrg }
458*b1e83836Smrg }
459*b1e83836Smrg }
460*b1e83836Smrg }
461*b1e83836Smrg
462*b1e83836Smrg
463*b1e83836Smrg extern void smaxloc1_4_r17 (gfc_array_i4 * const restrict,
464*b1e83836Smrg gfc_array_r17 * const restrict, const index_type * const restrict,
465*b1e83836Smrg GFC_LOGICAL_4 *, GFC_LOGICAL_4 back);
466*b1e83836Smrg export_proto(smaxloc1_4_r17);
467*b1e83836Smrg
468*b1e83836Smrg void
469*b1e83836Smrg smaxloc1_4_r17 (gfc_array_i4 * const restrict retarray,
470*b1e83836Smrg gfc_array_r17 * const restrict array,
471*b1e83836Smrg const index_type * const restrict pdim,
472*b1e83836Smrg GFC_LOGICAL_4 * mask, GFC_LOGICAL_4 back)
473*b1e83836Smrg {
474*b1e83836Smrg index_type count[GFC_MAX_DIMENSIONS];
475*b1e83836Smrg index_type extent[GFC_MAX_DIMENSIONS];
476*b1e83836Smrg index_type dstride[GFC_MAX_DIMENSIONS];
477*b1e83836Smrg GFC_INTEGER_4 * restrict dest;
478*b1e83836Smrg index_type rank;
479*b1e83836Smrg index_type n;
480*b1e83836Smrg index_type dim;
481*b1e83836Smrg
482*b1e83836Smrg
483*b1e83836Smrg if (mask == NULL || *mask)
484*b1e83836Smrg {
485*b1e83836Smrg #ifdef HAVE_BACK_ARG
486*b1e83836Smrg maxloc1_4_r17 (retarray, array, pdim, back);
487*b1e83836Smrg #else
488*b1e83836Smrg maxloc1_4_r17 (retarray, array, pdim);
489*b1e83836Smrg #endif
490*b1e83836Smrg return;
491*b1e83836Smrg }
492*b1e83836Smrg /* Make dim zero based to avoid confusion. */
493*b1e83836Smrg dim = (*pdim) - 1;
494*b1e83836Smrg rank = GFC_DESCRIPTOR_RANK (array) - 1;
495*b1e83836Smrg
496*b1e83836Smrg if (unlikely (dim < 0 || dim > rank))
497*b1e83836Smrg {
498*b1e83836Smrg runtime_error ("Dim argument incorrect in MAXLOC intrinsic: "
499*b1e83836Smrg "is %ld, should be between 1 and %ld",
500*b1e83836Smrg (long int) dim + 1, (long int) rank + 1);
501*b1e83836Smrg }
502*b1e83836Smrg
503*b1e83836Smrg for (n = 0; n < dim; n++)
504*b1e83836Smrg {
505*b1e83836Smrg extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
506*b1e83836Smrg
507*b1e83836Smrg if (extent[n] <= 0)
508*b1e83836Smrg extent[n] = 0;
509*b1e83836Smrg }
510*b1e83836Smrg
511*b1e83836Smrg for (n = dim; n < rank; n++)
512*b1e83836Smrg {
513*b1e83836Smrg extent[n] =
514*b1e83836Smrg GFC_DESCRIPTOR_EXTENT(array,n + 1);
515*b1e83836Smrg
516*b1e83836Smrg if (extent[n] <= 0)
517*b1e83836Smrg extent[n] = 0;
518*b1e83836Smrg }
519*b1e83836Smrg
520*b1e83836Smrg if (retarray->base_addr == NULL)
521*b1e83836Smrg {
522*b1e83836Smrg size_t alloc_size, str;
523*b1e83836Smrg
524*b1e83836Smrg for (n = 0; n < rank; n++)
525*b1e83836Smrg {
526*b1e83836Smrg if (n == 0)
527*b1e83836Smrg str = 1;
528*b1e83836Smrg else
529*b1e83836Smrg str = GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1];
530*b1e83836Smrg
531*b1e83836Smrg GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str);
532*b1e83836Smrg
533*b1e83836Smrg }
534*b1e83836Smrg
535*b1e83836Smrg retarray->offset = 0;
536*b1e83836Smrg retarray->dtype.rank = rank;
537*b1e83836Smrg
538*b1e83836Smrg alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1];
539*b1e83836Smrg
540*b1e83836Smrg if (alloc_size == 0)
541*b1e83836Smrg {
542*b1e83836Smrg /* Make sure we have a zero-sized array. */
543*b1e83836Smrg GFC_DIMENSION_SET(retarray->dim[0], 0, -1, 1);
544*b1e83836Smrg return;
545*b1e83836Smrg }
546*b1e83836Smrg else
547*b1e83836Smrg retarray->base_addr = xmallocarray (alloc_size, sizeof (GFC_INTEGER_4));
548*b1e83836Smrg }
549*b1e83836Smrg else
550*b1e83836Smrg {
551*b1e83836Smrg if (rank != GFC_DESCRIPTOR_RANK (retarray))
552*b1e83836Smrg runtime_error ("rank of return array incorrect in"
553*b1e83836Smrg " MAXLOC intrinsic: is %ld, should be %ld",
554*b1e83836Smrg (long int) (GFC_DESCRIPTOR_RANK (retarray)),
555*b1e83836Smrg (long int) rank);
556*b1e83836Smrg
557*b1e83836Smrg if (unlikely (compile_options.bounds_check))
558*b1e83836Smrg {
559*b1e83836Smrg for (n=0; n < rank; n++)
560*b1e83836Smrg {
561*b1e83836Smrg index_type ret_extent;
562*b1e83836Smrg
563*b1e83836Smrg ret_extent = GFC_DESCRIPTOR_EXTENT(retarray,n);
564*b1e83836Smrg if (extent[n] != ret_extent)
565*b1e83836Smrg runtime_error ("Incorrect extent in return value of"
566*b1e83836Smrg " MAXLOC intrinsic in dimension %ld:"
567*b1e83836Smrg " is %ld, should be %ld", (long int) n + 1,
568*b1e83836Smrg (long int) ret_extent, (long int) extent[n]);
569*b1e83836Smrg }
570*b1e83836Smrg }
571*b1e83836Smrg }
572*b1e83836Smrg
573*b1e83836Smrg for (n = 0; n < rank; n++)
574*b1e83836Smrg {
575*b1e83836Smrg count[n] = 0;
576*b1e83836Smrg dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n);
577*b1e83836Smrg }
578*b1e83836Smrg
579*b1e83836Smrg dest = retarray->base_addr;
580*b1e83836Smrg
581*b1e83836Smrg while(1)
582*b1e83836Smrg {
583*b1e83836Smrg *dest = 0;
584*b1e83836Smrg count[0]++;
585*b1e83836Smrg dest += dstride[0];
586*b1e83836Smrg n = 0;
587*b1e83836Smrg while (count[n] == extent[n])
588*b1e83836Smrg {
589*b1e83836Smrg /* When we get to the end of a dimension, reset it and increment
590*b1e83836Smrg the next dimension. */
591*b1e83836Smrg count[n] = 0;
592*b1e83836Smrg /* We could precalculate these products, but this is a less
593*b1e83836Smrg frequently used path so probably not worth it. */
594*b1e83836Smrg dest -= dstride[n] * extent[n];
595*b1e83836Smrg n++;
596*b1e83836Smrg if (n >= rank)
597*b1e83836Smrg return;
598*b1e83836Smrg else
599*b1e83836Smrg {
600*b1e83836Smrg count[n]++;
601*b1e83836Smrg dest += dstride[n];
602*b1e83836Smrg }
603*b1e83836Smrg }
604*b1e83836Smrg }
605*b1e83836Smrg }
606*b1e83836Smrg
607*b1e83836Smrg #endif
608