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