xref: /netbsd-src/external/gpl3/gcc/dist/libgfortran/generated/maxloc1_8_s4.c (revision b1e838363e3c6fc78a55519254d99869742dd33c)
1181254a7Smrg /* Implementation of the MAXLOC intrinsic
2*b1e83836Smrg    Copyright (C) 2017-2022 Free Software Foundation, Inc.
3181254a7Smrg    Contributed by Thomas Koenig
4181254a7Smrg 
5181254a7Smrg This file is part of the GNU Fortran runtime library (libgfortran).
6181254a7Smrg 
7181254a7Smrg Libgfortran is free software; you can redistribute it and/or
8181254a7Smrg modify it under the terms of the GNU General Public
9181254a7Smrg License as published by the Free Software Foundation; either
10181254a7Smrg version 3 of the License, or (at your option) any later version.
11181254a7Smrg 
12181254a7Smrg Libgfortran is distributed in the hope that it will be useful,
13181254a7Smrg but WITHOUT ANY WARRANTY; without even the implied warranty of
14181254a7Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15181254a7Smrg GNU General Public License for more details.
16181254a7Smrg 
17181254a7Smrg Under Section 7 of GPL version 3, you are granted additional
18181254a7Smrg permissions described in the GCC Runtime Library Exception, version
19181254a7Smrg 3.1, as published by the Free Software Foundation.
20181254a7Smrg 
21181254a7Smrg You should have received a copy of the GNU General Public License and
22181254a7Smrg a copy of the GCC Runtime Library Exception along with this program;
23181254a7Smrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24181254a7Smrg <http://www.gnu.org/licenses/>.  */
25181254a7Smrg 
26181254a7Smrg #include "libgfortran.h"
27181254a7Smrg 
28181254a7Smrg 
29181254a7Smrg #if defined (HAVE_GFC_UINTEGER_4) && defined (HAVE_GFC_INTEGER_8)
30181254a7Smrg 
31181254a7Smrg #define HAVE_BACK_ARG 1
32181254a7Smrg 
33181254a7Smrg #include <string.h>
34181254a7Smrg #include <assert.h>
35181254a7Smrg 
36181254a7Smrg static inline int
compare_fcn(const GFC_UINTEGER_4 * a,const GFC_UINTEGER_4 * b,gfc_charlen_type n)37181254a7Smrg compare_fcn (const GFC_UINTEGER_4 *a, const GFC_UINTEGER_4 *b, gfc_charlen_type n)
38181254a7Smrg {
39181254a7Smrg   if (sizeof (GFC_UINTEGER_4) == 1)
40181254a7Smrg     return memcmp (a, b, n);
41181254a7Smrg   else
42181254a7Smrg     return memcmp_char4 (a, b, n);
43181254a7Smrg }
44181254a7Smrg 
45181254a7Smrg extern void maxloc1_8_s4 (gfc_array_i8 * const restrict,
46181254a7Smrg 	gfc_array_s4 * const restrict, const index_type * const restrict , GFC_LOGICAL_4 back,
47181254a7Smrg 	gfc_charlen_type);
48181254a7Smrg export_proto(maxloc1_8_s4);
49181254a7Smrg 
50181254a7Smrg void
maxloc1_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)51181254a7Smrg maxloc1_8_s4 (gfc_array_i8 * const restrict retarray,
52181254a7Smrg 	gfc_array_s4 * const restrict array,
53181254a7Smrg 	const index_type * const restrict pdim, GFC_LOGICAL_4 back,
54181254a7Smrg 	gfc_charlen_type string_len)
55181254a7Smrg {
56181254a7Smrg   index_type count[GFC_MAX_DIMENSIONS];
57181254a7Smrg   index_type extent[GFC_MAX_DIMENSIONS];
58181254a7Smrg   index_type sstride[GFC_MAX_DIMENSIONS];
59181254a7Smrg   index_type dstride[GFC_MAX_DIMENSIONS];
60181254a7Smrg   const GFC_UINTEGER_4 * restrict base;
61181254a7Smrg   GFC_INTEGER_8 * restrict dest;
62181254a7Smrg   index_type rank;
63181254a7Smrg   index_type n;
64181254a7Smrg   index_type len;
65181254a7Smrg   index_type delta;
66181254a7Smrg   index_type dim;
67181254a7Smrg   int continue_loop;
68181254a7Smrg 
69181254a7Smrg   /* Make dim zero based to avoid confusion.  */
70181254a7Smrg   rank = GFC_DESCRIPTOR_RANK (array) - 1;
71181254a7Smrg   dim = (*pdim) - 1;
72181254a7Smrg 
73181254a7Smrg   if (unlikely (dim < 0 || dim > rank))
74181254a7Smrg     {
75181254a7Smrg       runtime_error ("Dim argument incorrect in MAXLOC intrinsic: "
76181254a7Smrg  		     "is %ld, should be between 1 and %ld",
77181254a7Smrg 		     (long int) dim + 1, (long int) rank + 1);
78181254a7Smrg     }
79181254a7Smrg 
80181254a7Smrg   len = GFC_DESCRIPTOR_EXTENT(array,dim);
81181254a7Smrg   if (len < 0)
82181254a7Smrg     len = 0;
83181254a7Smrg   delta = GFC_DESCRIPTOR_STRIDE(array,dim) * string_len;
84181254a7Smrg 
85181254a7Smrg   for (n = 0; n < dim; n++)
86181254a7Smrg     {
87181254a7Smrg       sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n) * string_len;
88181254a7Smrg       extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
89181254a7Smrg 
90181254a7Smrg       if (extent[n] < 0)
91181254a7Smrg 	extent[n] = 0;
92181254a7Smrg     }
93181254a7Smrg   for (n = dim; n < rank; n++)
94181254a7Smrg     {
95181254a7Smrg       sstride[n] = GFC_DESCRIPTOR_STRIDE(array, n + 1) * string_len;
96181254a7Smrg       extent[n] = GFC_DESCRIPTOR_EXTENT(array, n + 1);
97181254a7Smrg 
98181254a7Smrg       if (extent[n] < 0)
99181254a7Smrg 	extent[n] = 0;
100181254a7Smrg     }
101181254a7Smrg 
102181254a7Smrg   if (retarray->base_addr == NULL)
103181254a7Smrg     {
104181254a7Smrg       size_t alloc_size, str;
105181254a7Smrg 
106181254a7Smrg       for (n = 0; n < rank; n++)
107181254a7Smrg 	{
108181254a7Smrg 	  if (n == 0)
109181254a7Smrg 	    str = 1;
110181254a7Smrg 	  else
111181254a7Smrg 	    str = GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1];
112181254a7Smrg 
113181254a7Smrg 	  GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str);
114181254a7Smrg 
115181254a7Smrg 	}
116181254a7Smrg 
117181254a7Smrg       retarray->offset = 0;
118181254a7Smrg       retarray->dtype.rank = rank;
119181254a7Smrg 
120181254a7Smrg       alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1];
121181254a7Smrg 
122181254a7Smrg       retarray->base_addr = xmallocarray (alloc_size, sizeof (GFC_INTEGER_8));
123181254a7Smrg       if (alloc_size == 0)
124181254a7Smrg 	{
125181254a7Smrg 	  /* Make sure we have a zero-sized array.  */
126181254a7Smrg 	  GFC_DIMENSION_SET(retarray->dim[0], 0, -1, 1);
127181254a7Smrg 	  return;
128181254a7Smrg 
129181254a7Smrg 	}
130181254a7Smrg     }
131181254a7Smrg   else
132181254a7Smrg     {
133181254a7Smrg       if (rank != GFC_DESCRIPTOR_RANK (retarray))
134181254a7Smrg 	runtime_error ("rank of return array incorrect in"
135181254a7Smrg 		       " MAXLOC intrinsic: is %ld, should be %ld",
136181254a7Smrg 		       (long int) (GFC_DESCRIPTOR_RANK (retarray)),
137181254a7Smrg 		       (long int) rank);
138181254a7Smrg 
139181254a7Smrg       if (unlikely (compile_options.bounds_check))
140181254a7Smrg 	bounds_ifunction_return ((array_t *) retarray, extent,
141181254a7Smrg 				 "return value", "MAXLOC");
142181254a7Smrg     }
143181254a7Smrg 
144181254a7Smrg   for (n = 0; n < rank; n++)
145181254a7Smrg     {
146181254a7Smrg       count[n] = 0;
147181254a7Smrg       dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n);
148181254a7Smrg       if (extent[n] <= 0)
149181254a7Smrg 	return;
150181254a7Smrg     }
151181254a7Smrg 
152181254a7Smrg   base = array->base_addr;
153181254a7Smrg   dest = retarray->base_addr;
154181254a7Smrg 
155181254a7Smrg   continue_loop = 1;
156181254a7Smrg   while (continue_loop)
157181254a7Smrg     {
158181254a7Smrg       const GFC_UINTEGER_4 * restrict src;
159181254a7Smrg       GFC_INTEGER_8 result;
160181254a7Smrg       src = base;
161181254a7Smrg       {
162181254a7Smrg 
163181254a7Smrg 	const GFC_UINTEGER_4 *maxval;
164181254a7Smrg 	maxval = NULL;
165181254a7Smrg 	result = 0;
166181254a7Smrg 	if (len <= 0)
167181254a7Smrg 	  *dest = 0;
168181254a7Smrg 	else
169181254a7Smrg 	  {
170181254a7Smrg 	    for (n = 0; n < len; n++, src += delta)
171181254a7Smrg 	      {
172181254a7Smrg 
173181254a7Smrg 		if (maxval == NULL || (back ? compare_fcn (src, maxval, string_len) >= 0 :
174181254a7Smrg 		   	      	      	      compare_fcn (src, maxval, string_len) > 0))
175181254a7Smrg 		  {
176181254a7Smrg 		    maxval = src;
177181254a7Smrg 		    result = (GFC_INTEGER_8)n + 1;
178181254a7Smrg 		  }
179181254a7Smrg 	      }
180181254a7Smrg 
181181254a7Smrg 	    *dest = result;
182181254a7Smrg 	  }
183181254a7Smrg       }
184181254a7Smrg       /* Advance to the next element.  */
185181254a7Smrg       count[0]++;
186181254a7Smrg       base += sstride[0];
187181254a7Smrg       dest += dstride[0];
188181254a7Smrg       n = 0;
189181254a7Smrg       while (count[n] == extent[n])
190181254a7Smrg 	{
191181254a7Smrg 	  /* When we get to the end of a dimension, reset it and increment
192181254a7Smrg 	     the next dimension.  */
193181254a7Smrg 	  count[n] = 0;
194181254a7Smrg 	  /* We could precalculate these products, but this is a less
195181254a7Smrg 	     frequently used path so probably not worth it.  */
196181254a7Smrg 	  base -= sstride[n] * extent[n];
197181254a7Smrg 	  dest -= dstride[n] * extent[n];
198181254a7Smrg 	  n++;
199181254a7Smrg 	  if (n >= rank)
200181254a7Smrg 	    {
201181254a7Smrg 	      /* Break out of the loop.  */
202181254a7Smrg 	      continue_loop = 0;
203181254a7Smrg 	      break;
204181254a7Smrg 	    }
205181254a7Smrg 	  else
206181254a7Smrg 	    {
207181254a7Smrg 	      count[n]++;
208181254a7Smrg 	      base += sstride[n];
209181254a7Smrg 	      dest += dstride[n];
210181254a7Smrg 	    }
211181254a7Smrg 	}
212181254a7Smrg     }
213181254a7Smrg }
214181254a7Smrg 
215181254a7Smrg 
216181254a7Smrg extern void mmaxloc1_8_s4 (gfc_array_i8 * const restrict,
217181254a7Smrg 	gfc_array_s4 * const restrict, const index_type * const restrict,
218181254a7Smrg 	gfc_array_l1 * const restrict, GFC_LOGICAL_4 back, gfc_charlen_type);
219181254a7Smrg export_proto(mmaxloc1_8_s4);
220181254a7Smrg 
221181254a7Smrg void
mmaxloc1_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)222181254a7Smrg mmaxloc1_8_s4 (gfc_array_i8 * const restrict retarray,
223181254a7Smrg 	gfc_array_s4 * const restrict array,
224181254a7Smrg 	const index_type * const restrict pdim,
225181254a7Smrg 	gfc_array_l1 * const restrict mask, GFC_LOGICAL_4 back,
226181254a7Smrg 	gfc_charlen_type string_len)
227181254a7Smrg {
228181254a7Smrg   index_type count[GFC_MAX_DIMENSIONS];
229181254a7Smrg   index_type extent[GFC_MAX_DIMENSIONS];
230181254a7Smrg   index_type sstride[GFC_MAX_DIMENSIONS];
231181254a7Smrg   index_type dstride[GFC_MAX_DIMENSIONS];
232181254a7Smrg   index_type mstride[GFC_MAX_DIMENSIONS];
233181254a7Smrg   GFC_INTEGER_8 * restrict dest;
234181254a7Smrg   const GFC_UINTEGER_4 * restrict base;
235181254a7Smrg   const GFC_LOGICAL_1 * restrict mbase;
236181254a7Smrg   index_type rank;
237181254a7Smrg   index_type dim;
238181254a7Smrg   index_type n;
239181254a7Smrg   index_type len;
240181254a7Smrg   index_type delta;
241181254a7Smrg   index_type mdelta;
242181254a7Smrg   int mask_kind;
243181254a7Smrg 
244181254a7Smrg   if (mask == NULL)
245181254a7Smrg     {
246181254a7Smrg #ifdef HAVE_BACK_ARG
247181254a7Smrg       maxloc1_8_s4 (retarray, array, pdim, back, string_len);
248181254a7Smrg #else
249181254a7Smrg       maxloc1_8_s4 (retarray, array, pdim, string_len);
250181254a7Smrg #endif
251181254a7Smrg       return;
252181254a7Smrg     }
253181254a7Smrg 
254181254a7Smrg   dim = (*pdim) - 1;
255181254a7Smrg   rank = GFC_DESCRIPTOR_RANK (array) - 1;
256181254a7Smrg 
257181254a7Smrg 
258181254a7Smrg   if (unlikely (dim < 0 || dim > rank))
259181254a7Smrg     {
260181254a7Smrg       runtime_error ("Dim argument incorrect in MAXLOC intrinsic: "
261181254a7Smrg  		     "is %ld, should be between 1 and %ld",
262181254a7Smrg 		     (long int) dim + 1, (long int) rank + 1);
263181254a7Smrg     }
264181254a7Smrg 
265181254a7Smrg   len = GFC_DESCRIPTOR_EXTENT(array,dim);
266181254a7Smrg   if (len <= 0)
267181254a7Smrg     return;
268181254a7Smrg 
269181254a7Smrg   mbase = mask->base_addr;
270181254a7Smrg 
271181254a7Smrg   mask_kind = GFC_DESCRIPTOR_SIZE (mask);
272181254a7Smrg 
273181254a7Smrg   if (mask_kind == 1 || mask_kind == 2 || mask_kind == 4 || mask_kind == 8
274181254a7Smrg #ifdef HAVE_GFC_LOGICAL_16
275181254a7Smrg       || mask_kind == 16
276181254a7Smrg #endif
277181254a7Smrg       )
278181254a7Smrg     mbase = GFOR_POINTER_TO_L1 (mbase, mask_kind);
279181254a7Smrg   else
280181254a7Smrg     runtime_error ("Funny sized logical array");
281181254a7Smrg 
282181254a7Smrg   delta = GFC_DESCRIPTOR_STRIDE(array,dim) * string_len;
283181254a7Smrg   mdelta = GFC_DESCRIPTOR_STRIDE_BYTES(mask,dim);
284181254a7Smrg 
285181254a7Smrg   for (n = 0; n < dim; n++)
286181254a7Smrg     {
287181254a7Smrg       sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n) * string_len;
288181254a7Smrg       mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n);
289181254a7Smrg       extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
290181254a7Smrg 
291181254a7Smrg       if (extent[n] < 0)
292181254a7Smrg 	extent[n] = 0;
293181254a7Smrg 
294181254a7Smrg     }
295181254a7Smrg   for (n = dim; n < rank; n++)
296181254a7Smrg     {
297181254a7Smrg       sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n + 1) * string_len;
298181254a7Smrg       mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask, n + 1);
299181254a7Smrg       extent[n] = GFC_DESCRIPTOR_EXTENT(array, n + 1);
300181254a7Smrg 
301181254a7Smrg       if (extent[n] < 0)
302181254a7Smrg 	extent[n] = 0;
303181254a7Smrg     }
304181254a7Smrg 
305181254a7Smrg   if (retarray->base_addr == NULL)
306181254a7Smrg     {
307181254a7Smrg       size_t alloc_size, str;
308181254a7Smrg 
309181254a7Smrg       for (n = 0; n < rank; n++)
310181254a7Smrg 	{
311181254a7Smrg 	  if (n == 0)
312181254a7Smrg 	    str = 1;
313181254a7Smrg 	  else
314181254a7Smrg 	    str= GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1];
315181254a7Smrg 
316181254a7Smrg 	  GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str);
317181254a7Smrg 
318181254a7Smrg 	}
319181254a7Smrg 
320181254a7Smrg       alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1];
321181254a7Smrg 
322181254a7Smrg       retarray->offset = 0;
323181254a7Smrg       retarray->dtype.rank = rank;
324181254a7Smrg 
325181254a7Smrg       if (alloc_size == 0)
326181254a7Smrg 	{
327181254a7Smrg 	  /* Make sure we have a zero-sized array.  */
328181254a7Smrg 	  GFC_DIMENSION_SET(retarray->dim[0], 0, -1, 1);
329181254a7Smrg 	  return;
330181254a7Smrg 	}
331181254a7Smrg       else
332181254a7Smrg 	retarray->base_addr = xmallocarray (alloc_size, sizeof (GFC_INTEGER_8));
333181254a7Smrg 
334181254a7Smrg     }
335181254a7Smrg   else
336181254a7Smrg     {
337181254a7Smrg       if (rank != GFC_DESCRIPTOR_RANK (retarray))
338181254a7Smrg 	runtime_error ("rank of return array incorrect in MAXLOC intrinsic");
339181254a7Smrg 
340181254a7Smrg       if (unlikely (compile_options.bounds_check))
341181254a7Smrg 	{
342181254a7Smrg 	  bounds_ifunction_return ((array_t *) retarray, extent,
343181254a7Smrg 				   "return value", "MAXLOC");
344181254a7Smrg 	  bounds_equal_extents ((array_t *) mask, (array_t *) array,
345181254a7Smrg 	  			"MASK argument", "MAXLOC");
346181254a7Smrg 	}
347181254a7Smrg     }
348181254a7Smrg 
349181254a7Smrg   for (n = 0; n < rank; n++)
350181254a7Smrg     {
351181254a7Smrg       count[n] = 0;
352181254a7Smrg       dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n);
353181254a7Smrg       if (extent[n] <= 0)
354181254a7Smrg 	return;
355181254a7Smrg     }
356181254a7Smrg 
357181254a7Smrg   dest = retarray->base_addr;
358181254a7Smrg   base = array->base_addr;
359181254a7Smrg 
360181254a7Smrg   while (base)
361181254a7Smrg     {
362181254a7Smrg       const GFC_UINTEGER_4 * restrict src;
363181254a7Smrg       const GFC_LOGICAL_1 * restrict msrc;
364181254a7Smrg       GFC_INTEGER_8 result;
365181254a7Smrg       src = base;
366181254a7Smrg       msrc = mbase;
367181254a7Smrg       {
368181254a7Smrg 
369181254a7Smrg 	const GFC_UINTEGER_4 *maxval;
370181254a7Smrg 	maxval = base;
371181254a7Smrg 	result = 0;
372181254a7Smrg 	for (n = 0; n < len; n++, src += delta, msrc += mdelta)
373181254a7Smrg 	  {
374181254a7Smrg 
375181254a7Smrg 		if (*msrc)
376181254a7Smrg 		      {
377181254a7Smrg 			maxval = src;
378181254a7Smrg 			result = (GFC_INTEGER_8)n + 1;
379181254a7Smrg 			break;
380181254a7Smrg 		      }
381181254a7Smrg 	    }
382181254a7Smrg 	    for (; n < len; n++, src += delta, msrc += mdelta)
383181254a7Smrg 	      {
384181254a7Smrg 		if (*msrc && (back ? compare_fcn (src, maxval, string_len) >= 0 :
385181254a7Smrg 		   	     	     compare_fcn (src, maxval, string_len) > 0))
386181254a7Smrg 		  {
387181254a7Smrg 		    maxval = src;
388181254a7Smrg 		    result = (GFC_INTEGER_8)n + 1;
389181254a7Smrg 		  }
390181254a7Smrg 
391181254a7Smrg 	  }
392181254a7Smrg 	*dest = result;
393181254a7Smrg       }
394181254a7Smrg       /* Advance to the next element.  */
395181254a7Smrg       count[0]++;
396181254a7Smrg       base += sstride[0];
397181254a7Smrg       mbase += mstride[0];
398181254a7Smrg       dest += dstride[0];
399181254a7Smrg       n = 0;
400181254a7Smrg       while (count[n] == extent[n])
401181254a7Smrg 	{
402181254a7Smrg 	  /* When we get to the end of a dimension, reset it and increment
403181254a7Smrg 	     the next dimension.  */
404181254a7Smrg 	  count[n] = 0;
405181254a7Smrg 	  /* We could precalculate these products, but this is a less
406181254a7Smrg 	     frequently used path so probably not worth it.  */
407181254a7Smrg 	  base -= sstride[n] * extent[n];
408181254a7Smrg 	  mbase -= mstride[n] * extent[n];
409181254a7Smrg 	  dest -= dstride[n] * extent[n];
410181254a7Smrg 	  n++;
411181254a7Smrg 	  if (n >= rank)
412181254a7Smrg 	    {
413181254a7Smrg 	      /* Break out of the loop.  */
414181254a7Smrg 	      base = NULL;
415181254a7Smrg 	      break;
416181254a7Smrg 	    }
417181254a7Smrg 	  else
418181254a7Smrg 	    {
419181254a7Smrg 	      count[n]++;
420181254a7Smrg 	      base += sstride[n];
421181254a7Smrg 	      mbase += mstride[n];
422181254a7Smrg 	      dest += dstride[n];
423181254a7Smrg 	    }
424181254a7Smrg 	}
425181254a7Smrg     }
426181254a7Smrg }
427181254a7Smrg 
428181254a7Smrg 
429181254a7Smrg extern void smaxloc1_8_s4 (gfc_array_i8 * const restrict,
430181254a7Smrg 	gfc_array_s4 * const restrict, const index_type * const restrict,
431181254a7Smrg 	GFC_LOGICAL_4 *, GFC_LOGICAL_4 back, gfc_charlen_type);
432181254a7Smrg export_proto(smaxloc1_8_s4);
433181254a7Smrg 
434181254a7Smrg void
smaxloc1_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)435181254a7Smrg smaxloc1_8_s4 (gfc_array_i8 * const restrict retarray,
436181254a7Smrg 	gfc_array_s4 * const restrict array,
437181254a7Smrg 	const index_type * const restrict pdim,
438181254a7Smrg 	GFC_LOGICAL_4 * mask , GFC_LOGICAL_4 back, gfc_charlen_type string_len)
439181254a7Smrg {
440181254a7Smrg   index_type count[GFC_MAX_DIMENSIONS];
441181254a7Smrg   index_type extent[GFC_MAX_DIMENSIONS];
442181254a7Smrg   index_type dstride[GFC_MAX_DIMENSIONS];
443181254a7Smrg   GFC_INTEGER_8 * restrict dest;
444181254a7Smrg   index_type rank;
445181254a7Smrg   index_type n;
446181254a7Smrg   index_type dim;
447181254a7Smrg 
448181254a7Smrg 
449181254a7Smrg   if (mask == NULL || *mask)
450181254a7Smrg     {
451181254a7Smrg #ifdef HAVE_BACK_ARG
452181254a7Smrg       maxloc1_8_s4 (retarray, array, pdim, back, string_len);
453181254a7Smrg #else
454181254a7Smrg       maxloc1_8_s4 (retarray, array, pdim, string_len);
455181254a7Smrg #endif
456181254a7Smrg       return;
457181254a7Smrg     }
458181254a7Smrg   /* Make dim zero based to avoid confusion.  */
459181254a7Smrg   dim = (*pdim) - 1;
460181254a7Smrg   rank = GFC_DESCRIPTOR_RANK (array) - 1;
461181254a7Smrg 
462181254a7Smrg   if (unlikely (dim < 0 || dim > rank))
463181254a7Smrg     {
464181254a7Smrg       runtime_error ("Dim argument incorrect in MAXLOC intrinsic: "
465181254a7Smrg  		     "is %ld, should be between 1 and %ld",
466181254a7Smrg 		     (long int) dim + 1, (long int) rank + 1);
467181254a7Smrg     }
468181254a7Smrg 
469181254a7Smrg   for (n = 0; n < dim; n++)
470181254a7Smrg     {
471181254a7Smrg       extent[n] = GFC_DESCRIPTOR_EXTENT(array,n) * string_len;
472181254a7Smrg 
473181254a7Smrg       if (extent[n] <= 0)
474181254a7Smrg 	extent[n] = 0;
475181254a7Smrg     }
476181254a7Smrg 
477181254a7Smrg   for (n = dim; n < rank; n++)
478181254a7Smrg     {
479181254a7Smrg       extent[n] =
480181254a7Smrg 	GFC_DESCRIPTOR_EXTENT(array,n + 1) * string_len;
481181254a7Smrg 
482181254a7Smrg       if (extent[n] <= 0)
483181254a7Smrg 	extent[n] = 0;
484181254a7Smrg     }
485181254a7Smrg 
486181254a7Smrg   if (retarray->base_addr == NULL)
487181254a7Smrg     {
488181254a7Smrg       size_t alloc_size, str;
489181254a7Smrg 
490181254a7Smrg       for (n = 0; n < rank; n++)
491181254a7Smrg 	{
492181254a7Smrg 	  if (n == 0)
493181254a7Smrg 	    str = 1;
494181254a7Smrg 	  else
495181254a7Smrg 	    str = GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1];
496181254a7Smrg 
497181254a7Smrg 	  GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str);
498181254a7Smrg 
499181254a7Smrg 	}
500181254a7Smrg 
501181254a7Smrg       retarray->offset = 0;
502181254a7Smrg       retarray->dtype.rank = rank;
503181254a7Smrg 
504181254a7Smrg       alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1];
505181254a7Smrg 
506181254a7Smrg       if (alloc_size == 0)
507181254a7Smrg 	{
508181254a7Smrg 	  /* Make sure we have a zero-sized array.  */
509181254a7Smrg 	  GFC_DIMENSION_SET(retarray->dim[0], 0, -1, 1);
510181254a7Smrg 	  return;
511181254a7Smrg 	}
512181254a7Smrg       else
513181254a7Smrg 	retarray->base_addr = xmallocarray (alloc_size, sizeof (GFC_INTEGER_8));
514181254a7Smrg     }
515181254a7Smrg   else
516181254a7Smrg     {
517181254a7Smrg       if (rank != GFC_DESCRIPTOR_RANK (retarray))
518181254a7Smrg 	runtime_error ("rank of return array incorrect in"
519181254a7Smrg 		       " MAXLOC intrinsic: is %ld, should be %ld",
520181254a7Smrg 		       (long int) (GFC_DESCRIPTOR_RANK (retarray)),
521181254a7Smrg 		       (long int) rank);
522181254a7Smrg 
523181254a7Smrg       if (unlikely (compile_options.bounds_check))
524181254a7Smrg 	{
525181254a7Smrg 	  for (n=0; n < rank; n++)
526181254a7Smrg 	    {
527181254a7Smrg 	      index_type ret_extent;
528181254a7Smrg 
529181254a7Smrg 	      ret_extent = GFC_DESCRIPTOR_EXTENT(retarray,n);
530181254a7Smrg 	      if (extent[n] != ret_extent)
531181254a7Smrg 		runtime_error ("Incorrect extent in return value of"
532181254a7Smrg 			       " MAXLOC intrinsic in dimension %ld:"
533181254a7Smrg 			       " is %ld, should be %ld", (long int) n + 1,
534181254a7Smrg 			       (long int) ret_extent, (long int) extent[n]);
535181254a7Smrg 	    }
536181254a7Smrg 	}
537181254a7Smrg     }
538181254a7Smrg 
539181254a7Smrg   for (n = 0; n < rank; n++)
540181254a7Smrg     {
541181254a7Smrg       count[n] = 0;
542181254a7Smrg       dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n);
543181254a7Smrg     }
544181254a7Smrg 
545181254a7Smrg   dest = retarray->base_addr;
546181254a7Smrg 
547181254a7Smrg   while(1)
548181254a7Smrg     {
549181254a7Smrg       *dest = 0;
550181254a7Smrg       count[0]++;
551181254a7Smrg       dest += dstride[0];
552181254a7Smrg       n = 0;
553181254a7Smrg       while (count[n] == extent[n])
554181254a7Smrg 	{
555181254a7Smrg 	  /* When we get to the end of a dimension, reset it and increment
556181254a7Smrg 	     the next dimension.  */
557181254a7Smrg 	  count[n] = 0;
558181254a7Smrg 	  /* We could precalculate these products, but this is a less
559181254a7Smrg 	     frequently used path so probably not worth it.  */
560181254a7Smrg 	  dest -= dstride[n] * extent[n];
561181254a7Smrg 	  n++;
562181254a7Smrg 	  if (n >= rank)
563181254a7Smrg 	    return;
564181254a7Smrg 	  else
565181254a7Smrg 	    {
566181254a7Smrg 	      count[n]++;
567181254a7Smrg 	      dest += dstride[n];
568181254a7Smrg 	    }
569181254a7Smrg       	}
570181254a7Smrg     }
571181254a7Smrg }
572181254a7Smrg 
573181254a7Smrg #endif
574