Home | History | Annotate | Line # | Download | only in generated
      1 /* Implementation of the COUNT intrinsic
      2    Copyright (C) 2002-2024 Free Software Foundation, Inc.
      3    Contributed by Paul Brook <paul (at) nowt.org>
      4 
      5 This file is part of the GNU Fortran runtime library (libgfortran).
      6 
      7 Libgfortran is free software; you can redistribute it and/or
      8 modify it under the terms of the GNU General Public
      9 License as published by the Free Software Foundation; either
     10 version 3 of the License, or (at your option) any later version.
     11 
     12 Libgfortran is distributed in the hope that it will be useful,
     13 but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 Under Section 7 of GPL version 3, you are granted additional
     18 permissions described in the GCC Runtime Library Exception, version
     19 3.1, as published by the Free Software Foundation.
     20 
     21 You should have received a copy of the GNU General Public License and
     22 a copy of the GCC Runtime Library Exception along with this program;
     23 see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     24 <http://www.gnu.org/licenses/>.  */
     25 
     26 #include "libgfortran.h"
     27 
     28 
     29 #if defined (HAVE_GFC_INTEGER_16)
     30 
     31 
     32 extern void count_16_l (gfc_array_i16 * const restrict,
     33 	gfc_array_l1 * const restrict, const index_type * const restrict);
     34 export_proto(count_16_l);
     35 
     36 void
     37 count_16_l (gfc_array_i16 * const restrict retarray,
     38 	gfc_array_l1 * const restrict array,
     39 	const index_type * const restrict pdim)
     40 {
     41   index_type count[GFC_MAX_DIMENSIONS];
     42   index_type extent[GFC_MAX_DIMENSIONS];
     43   index_type sstride[GFC_MAX_DIMENSIONS];
     44   index_type dstride[GFC_MAX_DIMENSIONS];
     45   const GFC_LOGICAL_1 * restrict base;
     46   GFC_INTEGER_16 * restrict dest;
     47   index_type rank;
     48   index_type n;
     49   index_type len;
     50   index_type delta;
     51   index_type dim;
     52   int src_kind;
     53   int continue_loop;
     54 
     55   /* Make dim zero based to avoid confusion.  */
     56   dim = (*pdim) - 1;
     57   rank = GFC_DESCRIPTOR_RANK (array) - 1;
     58 
     59   src_kind = GFC_DESCRIPTOR_SIZE (array);
     60 
     61   len = GFC_DESCRIPTOR_EXTENT(array,dim);
     62   if (len < 0)
     63     len = 0;
     64 
     65   delta = GFC_DESCRIPTOR_STRIDE_BYTES(array,dim);
     66 
     67   for (n = 0; n < dim; n++)
     68     {
     69       sstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(array,n);
     70       extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
     71 
     72       if (extent[n] < 0)
     73 	extent[n] = 0;
     74     }
     75   for (n = dim; n < rank; n++)
     76     {
     77       sstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(array,n + 1);
     78       extent[n] = GFC_DESCRIPTOR_EXTENT(array,n + 1);
     79 
     80       if (extent[n] < 0)
     81 	extent[n] = 0;
     82     }
     83 
     84   if (retarray->base_addr == NULL)
     85     {
     86       size_t alloc_size, str;
     87 
     88       for (n = 0; n < rank; n++)
     89         {
     90           if (n == 0)
     91             str = 1;
     92           else
     93             str = GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1];
     94 
     95 	  GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str);
     96 
     97         }
     98 
     99       retarray->offset = 0;
    100       retarray->dtype.rank = rank;
    101 
    102       alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1];
    103 
    104       retarray->base_addr = xmallocarray (alloc_size, sizeof (GFC_INTEGER_16));
    105       if (alloc_size == 0)
    106 	return;
    107     }
    108   else
    109     {
    110       if (rank != GFC_DESCRIPTOR_RANK (retarray))
    111 	runtime_error ("rank of return array incorrect in"
    112 		       " COUNT intrinsic: is %ld, should be %ld",
    113 		       (long int) GFC_DESCRIPTOR_RANK (retarray),
    114 		       (long int) rank);
    115 
    116       if (unlikely (compile_options.bounds_check))
    117 	{
    118 	  for (n=0; n < rank; n++)
    119 	    {
    120 	      index_type ret_extent;
    121 
    122 	      ret_extent = GFC_DESCRIPTOR_EXTENT(retarray,n);
    123 	      if (extent[n] != ret_extent)
    124 		runtime_error ("Incorrect extent in return value of"
    125 			       " COUNT intrinsic in dimension %d:"
    126 			       " is %ld, should be %ld", (int) n + 1,
    127 			       (long int) ret_extent, (long int) extent[n]);
    128 	    }
    129 	}
    130     }
    131 
    132   for (n = 0; n < rank; n++)
    133     {
    134       count[n] = 0;
    135       dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n);
    136       if (extent[n] <= 0)
    137 	return;
    138     }
    139 
    140   base = array->base_addr;
    141 
    142   if (src_kind == 1 || src_kind == 2 || src_kind == 4 || src_kind == 8
    143 #ifdef HAVE_GFC_LOGICAL_16
    144       || src_kind == 16
    145 #endif
    146     )
    147     {
    148       if (base)
    149 	base = GFOR_POINTER_TO_L1 (base, src_kind);
    150     }
    151   else
    152     internal_error (NULL, "Funny sized logical array in COUNT intrinsic");
    153 
    154   dest = retarray->base_addr;
    155 
    156   continue_loop = 1;
    157   while (continue_loop)
    158     {
    159       const GFC_LOGICAL_1 * restrict src;
    160       GFC_INTEGER_16 result;
    161       src = base;
    162       {
    163 
    164   result = 0;
    165         if (len <= 0)
    166 	  *dest = 0;
    167 	else
    168 	  {
    169 	    for (n = 0; n < len; n++, src += delta)
    170 	      {
    171 
    172   if (*src)
    173     result++;
    174           }
    175 	    *dest = result;
    176 	  }
    177       }
    178       /* Advance to the next element.  */
    179       count[0]++;
    180       base += sstride[0];
    181       dest += dstride[0];
    182       n = 0;
    183       while (count[n] == extent[n])
    184         {
    185           /* When we get to the end of a dimension, reset it and increment
    186              the next dimension.  */
    187           count[n] = 0;
    188           /* We could precalculate these products, but this is a less
    189              frequently used path so probably not worth it.  */
    190           base -= sstride[n] * extent[n];
    191           dest -= dstride[n] * extent[n];
    192           n++;
    193           if (n >= rank)
    194             {
    195               /* Break out of the loop.  */
    196               continue_loop = 0;
    197               break;
    198             }
    199           else
    200             {
    201               count[n]++;
    202               base += sstride[n];
    203               dest += dstride[n];
    204             }
    205         }
    206     }
    207 }
    208 
    209 #endif
    210