Home | History | Annotate | Line # | Download | only in generated
      1      1.1  mrg /* Implementation of the MAXLOC intrinsic
      2  1.1.1.4  mrg    Copyright (C) 2017-2024 Free Software Foundation, Inc.
      3      1.1  mrg    Contributed by Thomas Koenig
      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 <stdlib.h>
     28      1.1  mrg #include <string.h>
     29      1.1  mrg #include <assert.h>
     30      1.1  mrg #include <limits.h>
     31      1.1  mrg 
     32      1.1  mrg 
     33      1.1  mrg #if defined (HAVE_GFC_UINTEGER_1) && defined (HAVE_GFC_INTEGER_16)
     34      1.1  mrg 
     35      1.1  mrg #define HAVE_BACK_ARG 1
     36      1.1  mrg 
     37      1.1  mrg static inline int
     38      1.1  mrg compare_fcn (const GFC_UINTEGER_1 *a, const GFC_UINTEGER_1 *b, gfc_charlen_type n)
     39      1.1  mrg {
     40      1.1  mrg   if (sizeof (GFC_UINTEGER_1) == 1)
     41      1.1  mrg     return memcmp (a, b, n);
     42      1.1  mrg   else
     43      1.1  mrg     return memcmp_char4 (a, b, n);
     44      1.1  mrg 
     45      1.1  mrg }
     46      1.1  mrg 
     47      1.1  mrg extern void maxloc0_16_s1 (gfc_array_i16 * const restrict retarray,
     48      1.1  mrg 	gfc_array_s1 * const restrict array, GFC_LOGICAL_4 back, gfc_charlen_type len);
     49      1.1  mrg export_proto(maxloc0_16_s1);
     50      1.1  mrg 
     51      1.1  mrg void
     52      1.1  mrg maxloc0_16_s1 (gfc_array_i16 * const restrict retarray,
     53      1.1  mrg 	gfc_array_s1 * const restrict array, GFC_LOGICAL_4 back, gfc_charlen_type len)
     54      1.1  mrg {
     55      1.1  mrg   index_type count[GFC_MAX_DIMENSIONS];
     56      1.1  mrg   index_type extent[GFC_MAX_DIMENSIONS];
     57      1.1  mrg   index_type sstride[GFC_MAX_DIMENSIONS];
     58      1.1  mrg   index_type dstride;
     59      1.1  mrg   const GFC_UINTEGER_1 *base;
     60      1.1  mrg   GFC_INTEGER_16 * restrict dest;
     61      1.1  mrg   index_type rank;
     62      1.1  mrg   index_type n;
     63      1.1  mrg 
     64      1.1  mrg   rank = GFC_DESCRIPTOR_RANK (array);
     65      1.1  mrg   if (rank <= 0)
     66      1.1  mrg     runtime_error ("Rank of array needs to be > 0");
     67      1.1  mrg 
     68      1.1  mrg   if (retarray->base_addr == NULL)
     69      1.1  mrg     {
     70      1.1  mrg       GFC_DIMENSION_SET(retarray->dim[0], 0, rank-1, 1);
     71      1.1  mrg       retarray->dtype.rank = 1;
     72      1.1  mrg       retarray->offset = 0;
     73      1.1  mrg       retarray->base_addr = xmallocarray (rank, sizeof (GFC_INTEGER_16));
     74      1.1  mrg     }
     75      1.1  mrg   else
     76      1.1  mrg     {
     77      1.1  mrg       if (unlikely (compile_options.bounds_check))
     78      1.1  mrg 	bounds_iforeach_return ((array_t *) retarray, (array_t *) array,
     79      1.1  mrg 				"MAXLOC");
     80      1.1  mrg     }
     81      1.1  mrg 
     82      1.1  mrg   dstride = GFC_DESCRIPTOR_STRIDE(retarray,0);
     83      1.1  mrg   dest = retarray->base_addr;
     84      1.1  mrg   for (n = 0; n < rank; n++)
     85      1.1  mrg     {
     86      1.1  mrg       sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n) * len;
     87      1.1  mrg       extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
     88      1.1  mrg       count[n] = 0;
     89      1.1  mrg       if (extent[n] <= 0)
     90      1.1  mrg 	{
     91      1.1  mrg 	  /* Set the return value.  */
     92      1.1  mrg 	  for (n = 0; n < rank; n++)
     93      1.1  mrg 	    dest[n * dstride] = 0;
     94      1.1  mrg 	  return;
     95      1.1  mrg 	}
     96      1.1  mrg     }
     97      1.1  mrg 
     98      1.1  mrg   base = array->base_addr;
     99      1.1  mrg 
    100      1.1  mrg   /* Initialize the return value.  */
    101      1.1  mrg   for (n = 0; n < rank; n++)
    102      1.1  mrg     dest[n * dstride] = 1;
    103      1.1  mrg   {
    104      1.1  mrg 
    105      1.1  mrg   const GFC_UINTEGER_1 *maxval;
    106      1.1  mrg    maxval = NULL;
    107      1.1  mrg 
    108      1.1  mrg   while (base)
    109      1.1  mrg     {
    110      1.1  mrg       do
    111      1.1  mrg 	{
    112      1.1  mrg 	  /* Implementation start.  */
    113      1.1  mrg 
    114      1.1  mrg     if (maxval == NULL || (back ? compare_fcn (base, maxval, len) >= 0 :
    115      1.1  mrg      		   	   	   compare_fcn (base, maxval, len) > 0))
    116      1.1  mrg     {
    117      1.1  mrg       maxval = base;
    118      1.1  mrg       for (n = 0; n < rank; n++)
    119      1.1  mrg         dest[n * dstride] = count[n] + 1;
    120      1.1  mrg     }
    121      1.1  mrg 	  /* Implementation end.  */
    122      1.1  mrg 	  /* Advance to the next element.  */
    123      1.1  mrg 	  base += sstride[0];
    124      1.1  mrg 	}
    125      1.1  mrg       while (++count[0] != extent[0]);
    126      1.1  mrg       n = 0;
    127      1.1  mrg       do
    128      1.1  mrg 	{
    129      1.1  mrg 	  /* When we get to the end of a dimension, reset it and increment
    130      1.1  mrg 	     the next dimension.  */
    131      1.1  mrg 	  count[n] = 0;
    132      1.1  mrg 	  /* We could precalculate these products, but this is a less
    133      1.1  mrg 	     frequently used path so probably not worth it.  */
    134      1.1  mrg 	  base -= sstride[n] * extent[n];
    135      1.1  mrg 	  n++;
    136      1.1  mrg 	  if (n >= rank)
    137      1.1  mrg 	    {
    138      1.1  mrg 	      /* Break out of the loop.  */
    139      1.1  mrg 	      base = NULL;
    140      1.1  mrg 	      break;
    141      1.1  mrg 	    }
    142      1.1  mrg 	  else
    143      1.1  mrg 	    {
    144      1.1  mrg 	      count[n]++;
    145      1.1  mrg 	      base += sstride[n];
    146      1.1  mrg 	    }
    147      1.1  mrg 	}
    148      1.1  mrg       while (count[n] == extent[n]);
    149      1.1  mrg     }
    150      1.1  mrg   }
    151      1.1  mrg }
    152      1.1  mrg 
    153      1.1  mrg 
    154      1.1  mrg extern void mmaxloc0_16_s1 (gfc_array_i16 * const restrict,
    155      1.1  mrg 	gfc_array_s1 * const restrict, gfc_array_l1 * const restrict , GFC_LOGICAL_4 back,
    156      1.1  mrg 	gfc_charlen_type len);
    157      1.1  mrg export_proto(mmaxloc0_16_s1);
    158      1.1  mrg 
    159      1.1  mrg void
    160      1.1  mrg mmaxloc0_16_s1 (gfc_array_i16 * const restrict retarray,
    161      1.1  mrg 	gfc_array_s1 * const restrict array,
    162      1.1  mrg 	gfc_array_l1 * const restrict mask, GFC_LOGICAL_4 back,
    163      1.1  mrg 	gfc_charlen_type len)
    164      1.1  mrg {
    165      1.1  mrg   index_type count[GFC_MAX_DIMENSIONS];
    166      1.1  mrg   index_type extent[GFC_MAX_DIMENSIONS];
    167      1.1  mrg   index_type sstride[GFC_MAX_DIMENSIONS];
    168      1.1  mrg   index_type mstride[GFC_MAX_DIMENSIONS];
    169      1.1  mrg   index_type dstride;
    170      1.1  mrg   GFC_INTEGER_16 *dest;
    171      1.1  mrg   const GFC_UINTEGER_1 *base;
    172      1.1  mrg   GFC_LOGICAL_1 *mbase;
    173      1.1  mrg   int rank;
    174      1.1  mrg   index_type n;
    175      1.1  mrg   int mask_kind;
    176      1.1  mrg 
    177      1.1  mrg   if (mask == NULL)
    178      1.1  mrg     {
    179      1.1  mrg #ifdef HAVE_BACK_ARG
    180      1.1  mrg       maxloc0_16_s1 (retarray, array, back, len);
    181      1.1  mrg #else
    182      1.1  mrg       maxloc0_16_s1 (retarray, array, len);
    183      1.1  mrg #endif
    184      1.1  mrg       return;
    185      1.1  mrg     }
    186      1.1  mrg 
    187      1.1  mrg   rank = GFC_DESCRIPTOR_RANK (array);
    188      1.1  mrg   if (rank <= 0)
    189      1.1  mrg     runtime_error ("Rank of array needs to be > 0");
    190      1.1  mrg 
    191      1.1  mrg   if (retarray->base_addr == NULL)
    192      1.1  mrg     {
    193      1.1  mrg       GFC_DIMENSION_SET(retarray->dim[0], 0, rank - 1, 1);
    194      1.1  mrg       retarray->dtype.rank = 1;
    195      1.1  mrg       retarray->offset = 0;
    196      1.1  mrg       retarray->base_addr = xmallocarray (rank, sizeof (GFC_INTEGER_16));
    197      1.1  mrg     }
    198      1.1  mrg   else
    199      1.1  mrg     {
    200      1.1  mrg       if (unlikely (compile_options.bounds_check))
    201      1.1  mrg 	{
    202      1.1  mrg 
    203      1.1  mrg 	  bounds_iforeach_return ((array_t *) retarray, (array_t *) array,
    204      1.1  mrg 				  "MAXLOC");
    205      1.1  mrg 	  bounds_equal_extents ((array_t *) mask, (array_t *) array,
    206      1.1  mrg 				  "MASK argument", "MAXLOC");
    207      1.1  mrg 	}
    208      1.1  mrg     }
    209      1.1  mrg 
    210      1.1  mrg   mask_kind = GFC_DESCRIPTOR_SIZE (mask);
    211      1.1  mrg 
    212      1.1  mrg   mbase = mask->base_addr;
    213      1.1  mrg 
    214      1.1  mrg   if (mask_kind == 1 || mask_kind == 2 || mask_kind == 4 || mask_kind == 8
    215      1.1  mrg #ifdef HAVE_GFC_LOGICAL_16
    216      1.1  mrg       || mask_kind == 16
    217      1.1  mrg #endif
    218      1.1  mrg       )
    219      1.1  mrg     mbase = GFOR_POINTER_TO_L1 (mbase, mask_kind);
    220      1.1  mrg   else
    221      1.1  mrg     runtime_error ("Funny sized logical array");
    222      1.1  mrg 
    223      1.1  mrg   dstride = GFC_DESCRIPTOR_STRIDE(retarray,0);
    224      1.1  mrg   dest = retarray->base_addr;
    225      1.1  mrg   for (n = 0; n < rank; n++)
    226      1.1  mrg     {
    227      1.1  mrg       sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n) * len;
    228      1.1  mrg       mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n);
    229      1.1  mrg       extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
    230      1.1  mrg       count[n] = 0;
    231      1.1  mrg       if (extent[n] <= 0)
    232      1.1  mrg 	{
    233      1.1  mrg 	  /* Set the return value.  */
    234      1.1  mrg 	  for (n = 0; n < rank; n++)
    235      1.1  mrg 	    dest[n * dstride] = 0;
    236      1.1  mrg 	  return;
    237      1.1  mrg 	}
    238      1.1  mrg     }
    239      1.1  mrg 
    240      1.1  mrg   base = array->base_addr;
    241      1.1  mrg 
    242      1.1  mrg   /* Initialize the return value.  */
    243      1.1  mrg   for (n = 0; n < rank; n++)
    244      1.1  mrg     dest[n * dstride] = 0;
    245      1.1  mrg   {
    246      1.1  mrg 
    247      1.1  mrg   const GFC_UINTEGER_1 *maxval;
    248      1.1  mrg 
    249      1.1  mrg   maxval = NULL;
    250      1.1  mrg 
    251      1.1  mrg   while (base)
    252      1.1  mrg     {
    253      1.1  mrg       do
    254      1.1  mrg 	{
    255      1.1  mrg 	  /* Implementation start.  */
    256      1.1  mrg 
    257      1.1  mrg   if (*mbase &&
    258      1.1  mrg         (maxval == NULL || (back ? compare_fcn (base, maxval, len) >= 0:
    259      1.1  mrg 		   	   	   compare_fcn (base, maxval, len) > 0)))
    260      1.1  mrg     {
    261      1.1  mrg       maxval = base;
    262      1.1  mrg       for (n = 0; n < rank; n++)
    263      1.1  mrg         dest[n * dstride] = count[n] + 1;
    264      1.1  mrg     }
    265      1.1  mrg 	  /* Implementation end.  */
    266      1.1  mrg 	  /* Advance to the next element.  */
    267      1.1  mrg 	  base += sstride[0];
    268      1.1  mrg 	  mbase += mstride[0];
    269      1.1  mrg 	}
    270      1.1  mrg       while (++count[0] != extent[0]);
    271      1.1  mrg       n = 0;
    272      1.1  mrg       do
    273      1.1  mrg 	{
    274      1.1  mrg 	  /* When we get to the end of a dimension, reset it and increment
    275      1.1  mrg 	     the next dimension.  */
    276      1.1  mrg 	  count[n] = 0;
    277      1.1  mrg 	  /* We could precalculate these products, but this is a less
    278      1.1  mrg 	     frequently used path so probably not worth it.  */
    279      1.1  mrg 	  base -= sstride[n] * extent[n];
    280      1.1  mrg 	  mbase -= mstride[n] * extent[n];
    281      1.1  mrg 	  n++;
    282      1.1  mrg 	  if (n >= rank)
    283      1.1  mrg 	    {
    284      1.1  mrg 	      /* Break out of the loop.  */
    285      1.1  mrg 	      base = NULL;
    286      1.1  mrg 	      break;
    287      1.1  mrg 	    }
    288      1.1  mrg 	  else
    289      1.1  mrg 	    {
    290      1.1  mrg 	      count[n]++;
    291      1.1  mrg 	      base += sstride[n];
    292      1.1  mrg 	      mbase += mstride[n];
    293      1.1  mrg 	    }
    294      1.1  mrg 	}
    295      1.1  mrg       while (count[n] == extent[n]);
    296      1.1  mrg     }
    297      1.1  mrg   }
    298      1.1  mrg }
    299      1.1  mrg 
    300      1.1  mrg 
    301      1.1  mrg extern void smaxloc0_16_s1 (gfc_array_i16 * const restrict,
    302      1.1  mrg 	gfc_array_s1 * const restrict, GFC_LOGICAL_4 *, GFC_LOGICAL_4 back,
    303      1.1  mrg 	gfc_charlen_type len);
    304      1.1  mrg export_proto(smaxloc0_16_s1);
    305      1.1  mrg 
    306      1.1  mrg void
    307      1.1  mrg smaxloc0_16_s1 (gfc_array_i16 * const restrict retarray,
    308      1.1  mrg 	gfc_array_s1 * const restrict array,
    309      1.1  mrg 	GFC_LOGICAL_4 * mask, GFC_LOGICAL_4 back,
    310      1.1  mrg 	gfc_charlen_type len)
    311      1.1  mrg {
    312      1.1  mrg   index_type rank;
    313      1.1  mrg   index_type dstride;
    314      1.1  mrg   index_type n;
    315      1.1  mrg   GFC_INTEGER_16 *dest;
    316      1.1  mrg 
    317      1.1  mrg   if (mask == NULL || *mask)
    318      1.1  mrg     {
    319      1.1  mrg #ifdef HAVE_BACK_ARG
    320      1.1  mrg       maxloc0_16_s1 (retarray, array, back, len);
    321      1.1  mrg #else
    322      1.1  mrg       maxloc0_16_s1 (retarray, array, len);
    323      1.1  mrg #endif
    324      1.1  mrg       return;
    325      1.1  mrg     }
    326      1.1  mrg 
    327      1.1  mrg   rank = GFC_DESCRIPTOR_RANK (array);
    328      1.1  mrg 
    329      1.1  mrg   if (rank <= 0)
    330      1.1  mrg     runtime_error ("Rank of array needs to be > 0");
    331      1.1  mrg 
    332      1.1  mrg   if (retarray->base_addr == NULL)
    333      1.1  mrg     {
    334      1.1  mrg       GFC_DIMENSION_SET(retarray->dim[0], 0, rank-1, 1);
    335      1.1  mrg       retarray->dtype.rank = 1;
    336      1.1  mrg       retarray->offset = 0;
    337      1.1  mrg       retarray->base_addr = xmallocarray (rank, sizeof (GFC_INTEGER_16));
    338      1.1  mrg     }
    339      1.1  mrg   else if (unlikely (compile_options.bounds_check))
    340      1.1  mrg     {
    341      1.1  mrg        bounds_iforeach_return ((array_t *) retarray, (array_t *) array,
    342      1.1  mrg 			       "MAXLOC");
    343      1.1  mrg     }
    344      1.1  mrg 
    345      1.1  mrg   dstride = GFC_DESCRIPTOR_STRIDE(retarray,0);
    346      1.1  mrg   dest = retarray->base_addr;
    347      1.1  mrg   for (n = 0; n<rank; n++)
    348      1.1  mrg     dest[n * dstride] = 0 ;
    349      1.1  mrg }
    350      1.1  mrg #endif
    351