1  
       2  /* Implementation of the FINDLOC intrinsic
       3     Copyright (C) 2018-2023 Free Software Foundation, Inc.
       4     Contributed by Thomas König <tk@tkoenig.net>
       5  
       6  This file is part of the GNU Fortran 95 runtime library (libgfortran).
       7  
       8  Libgfortran is free software; you can redistribute it and/or
       9  modify it under the terms of the GNU General Public
      10  License as published by the Free Software Foundation; either
      11  version 3 of the License, or (at your option) any later version.
      12  
      13  Libgfortran is distributed in the hope that it will be useful,
      14  but WITHOUT ANY WARRANTY; without even the implied warranty of
      15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16  GNU General Public License for more details.
      17  
      18  Under Section 7 of GPL version 3, you are granted additional
      19  permissions described in the GCC Runtime Library Exception, version
      20  3.1, as published by the Free Software Foundation.
      21  
      22  You should have received a copy of the GNU General Public License and
      23  a copy of the GCC Runtime Library Exception along with this program;
      24  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
      25  <http://www.gnu.org/licenses/>.  */
      26  
      27  #include "libgfortran.h"
      28  #include <assert.h>
      29  
      30  #if defined (HAVE_GFC_UINTEGER_1)
      31  extern void findloc0_s1 (gfc_array_index_type * const restrict retarray,
      32         	    		gfc_array_s1 * const restrict array, GFC_UINTEGER_1 *value,
      33  			 GFC_LOGICAL_4 back, gfc_charlen_type len_array, gfc_charlen_type len_value);
      34  
      35  export_proto(findloc0_s1);
      36  
      37  void
      38  findloc0_s1 (gfc_array_index_type * const restrict retarray,
      39      	    gfc_array_s1 * const restrict array, GFC_UINTEGER_1 *value,
      40  	    GFC_LOGICAL_4 back, gfc_charlen_type len_array, gfc_charlen_type len_value)
      41  {
      42    index_type count[GFC_MAX_DIMENSIONS];
      43    index_type extent[GFC_MAX_DIMENSIONS];
      44    index_type sstride[GFC_MAX_DIMENSIONS];
      45    index_type dstride;
      46    const GFC_UINTEGER_1 *base;
      47    index_type * restrict dest;
      48    index_type rank;
      49    index_type n;
      50    index_type sz;
      51  
      52    rank = GFC_DESCRIPTOR_RANK (array);
      53    if (rank <= 0)
      54      runtime_error ("Rank of array needs to be > 0");
      55  
      56    if (retarray->base_addr == NULL)
      57      {
      58        GFC_DIMENSION_SET(retarray->dim[0], 0, rank-1, 1);
      59        retarray->dtype.rank = 1;
      60        retarray->offset = 0;
      61        retarray->base_addr = xmallocarray (rank, sizeof (index_type));
      62      }
      63    else
      64      {
      65        if (unlikely (compile_options.bounds_check))
      66  	bounds_iforeach_return ((array_t *) retarray, (array_t *) array,
      67  				"FINDLOC");
      68      }
      69  
      70    dstride = GFC_DESCRIPTOR_STRIDE(retarray,0);
      71    dest = retarray->base_addr;
      72  
      73    /* Set the return value.  */
      74    for (n = 0; n < rank; n++)
      75      dest[n * dstride] = 0;
      76  
      77    sz = 1;
      78    for (n = 0; n < rank; n++)
      79      {
      80        sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n);
      81        extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
      82        sz *= extent[n];
      83        if (extent[n] <= 0)
      84  	return;
      85      }
      86  
      87      for (n = 0; n < rank; n++)
      88        count[n] = 0;
      89  
      90    if (back)
      91      {
      92        base = array->base_addr + (sz - 1) * len_array;
      93  
      94        while (1)
      95          {
      96  	  do
      97  	    {
      98  	      if (unlikely(compare_string (len_array, (char *) base, len_value, (char *) value) == 0))
      99  	        {
     100  		  for (n = 0; n < rank; n++)
     101  		    dest[n * dstride] = extent[n] - count[n];
     102  
     103  		  return;
     104  		}
     105  	      base -= sstride[0] * len_array;
     106  	    } while(++count[0] != extent[0]);
     107  
     108  	  n = 0;
     109  	  do
     110  	    {
     111  	      /* When we get to the end of a dimension, reset it and increment
     112  		 the next dimension.  */
     113  	      count[n] = 0;
     114  	      /* We could precalculate these products, but this is a less
     115  		 frequently used path so probably not worth it.  */
     116  	      base += sstride[n] * extent[n] * len_array;
     117  	      n++;
     118  	      if (n >= rank)
     119  	        return;
     120  	      else
     121  		{
     122  		  count[n]++;
     123  		  base -= sstride[n] * len_array;
     124  		}
     125  	    } while (count[n] == extent[n]);      
     126  	}
     127      }
     128    else
     129      {
     130        base = array->base_addr;
     131        while (1)
     132          {
     133  	  do
     134  	    {
     135  	      if (unlikely(compare_string (len_array, (char *) base, len_value, (char *) value) == 0))
     136  	        {
     137  		  for (n = 0; n < rank; n++)
     138  		    dest[n * dstride] = count[n] + 1;
     139  
     140  		  return;
     141  		}
     142  	      base += sstride[0] * len_array;
     143  	    } while(++count[0] != extent[0]);
     144  
     145  	  n = 0;
     146  	  do
     147  	    {
     148  	      /* When we get to the end of a dimension, reset it and increment
     149  		 the next dimension.  */
     150  	      count[n] = 0;
     151  	      /* We could precalculate these products, but this is a less
     152  		 frequently used path so probably not worth it.  */
     153  	      base -= sstride[n] * extent[n] * len_array;
     154  	      n++;
     155  	      if (n >= rank)
     156  	        return;
     157  	      else
     158  		{
     159  		  count[n]++;
     160  		  base += sstride[n] * len_array;
     161  		}
     162  	    } while (count[n] == extent[n]);
     163  	}
     164      }
     165    return;
     166  }
     167  
     168  extern void mfindloc0_s1 (gfc_array_index_type * const restrict retarray,
     169         	    		gfc_array_s1 * const restrict array, GFC_UINTEGER_1 *value,
     170  			 gfc_array_l1 *const restrict, GFC_LOGICAL_4 back, gfc_charlen_type len_array,
     171  			 gfc_charlen_type len_value);
     172  export_proto(mfindloc0_s1);
     173  
     174  void
     175  mfindloc0_s1 (gfc_array_index_type * const restrict retarray,
     176      	    gfc_array_s1 * const restrict array, GFC_UINTEGER_1 *value,
     177  	    gfc_array_l1 *const restrict mask, GFC_LOGICAL_4 back,
     178  	    gfc_charlen_type len_array, gfc_charlen_type len_value)
     179  {
     180    index_type count[GFC_MAX_DIMENSIONS];
     181    index_type extent[GFC_MAX_DIMENSIONS];
     182    index_type sstride[GFC_MAX_DIMENSIONS];
     183    index_type mstride[GFC_MAX_DIMENSIONS];
     184    index_type dstride;
     185    const GFC_UINTEGER_1 *base;
     186    index_type * restrict dest;
     187    GFC_LOGICAL_1 *mbase;
     188    index_type rank;
     189    index_type n;
     190    int mask_kind;
     191    index_type sz;
     192  
     193    rank = GFC_DESCRIPTOR_RANK (array);
     194    if (rank <= 0)
     195      runtime_error ("Rank of array needs to be > 0");
     196  
     197    if (retarray->base_addr == NULL)
     198      {
     199        GFC_DIMENSION_SET(retarray->dim[0], 0, rank-1, 1);
     200        retarray->dtype.rank = 1;
     201        retarray->offset = 0;
     202        retarray->base_addr = xmallocarray (rank, sizeof (index_type));
     203      }
     204    else
     205      {
     206        if (unlikely (compile_options.bounds_check))
     207  	{
     208  	  bounds_iforeach_return ((array_t *) retarray, (array_t *) array,
     209  				  "FINDLOC");
     210  	  bounds_equal_extents ((array_t *) mask, (array_t *) array,
     211  				"MASK argument", "FINDLOC");
     212  	}
     213      }
     214  
     215    mask_kind = GFC_DESCRIPTOR_SIZE (mask);
     216  
     217    mbase = mask->base_addr;
     218  
     219    if (mask_kind == 1 || mask_kind == 2 || mask_kind == 4 || mask_kind == 8
     220  #ifdef HAVE_GFC_LOGICAL_16
     221        || mask_kind == 16
     222  #endif
     223        )
     224      mbase = GFOR_POINTER_TO_L1 (mbase, mask_kind);
     225    else
     226      internal_error (NULL, "Funny sized logical array");
     227  
     228    dstride = GFC_DESCRIPTOR_STRIDE(retarray,0);
     229    dest = retarray->base_addr;
     230  
     231    /* Set the return value.  */
     232    for (n = 0; n < rank; n++)
     233      dest[n * dstride] = 0;
     234  
     235    sz = 1;
     236    for (n = 0; n < rank; n++)
     237      {
     238        sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n);
     239        mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n);
     240        extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
     241        sz *= extent[n];
     242        if (extent[n] <= 0)
     243  	return;
     244      }
     245  
     246      for (n = 0; n < rank; n++)
     247        count[n] = 0;
     248  
     249    if (back)
     250      {
     251        base = array->base_addr + (sz - 1) * len_array;
     252        mbase = mbase + (sz - 1) * mask_kind;
     253        while (1)
     254          {
     255  	  do
     256  	    {
     257  	      if (unlikely(*mbase && compare_string (len_array, (char *) base, len_value, (char *) value) == 0))
     258  	        {
     259  		  for (n = 0; n < rank; n++)
     260  		    dest[n * dstride] = extent[n] - count[n];
     261  
     262  		  return;
     263  		}
     264  	      base -= sstride[0] * len_array;
     265  	      mbase -= mstride[0];
     266  	    } while(++count[0] != extent[0]);
     267  
     268  	  n = 0;
     269  	  do
     270  	    {
     271  	      /* When we get to the end of a dimension, reset it and increment
     272  		 the next dimension.  */
     273  	      count[n] = 0;
     274  	      /* We could precalculate these products, but this is a less
     275  		 frequently used path so probably not worth it.  */
     276  	      base += sstride[n] * extent[n] * len_array;
     277  	      mbase -= mstride[n] * extent[n];
     278  	      n++;
     279  	      if (n >= rank)
     280  		return;
     281  	      else
     282  		{
     283  		  count[n]++;
     284  		  base -= sstride[n] * len_array;
     285  		  mbase += mstride[n];
     286  		}
     287  	    } while (count[n] == extent[n]);      
     288  	}
     289      }
     290    else
     291      {
     292        base = array->base_addr;
     293        while (1)
     294          {
     295  	  do
     296  	    {
     297  	      if (unlikely(*mbase && compare_string (len_array, (char *) base, len_value, (char *) value) == 0))
     298  	        {
     299  		  for (n = 0; n < rank; n++)
     300  		    dest[n * dstride] = count[n] + 1;
     301  
     302  		  return;
     303  		}
     304  	      base += sstride[0] * len_array;
     305  	      mbase += mstride[0];
     306  	    } while(++count[0] != extent[0]);
     307  
     308  	  n = 0;
     309  	  do
     310  	    {
     311  	      /* When we get to the end of a dimension, reset it and increment
     312  		 the next dimension.  */
     313  	      count[n] = 0;
     314  	      /* We could precalculate these products, but this is a less
     315  		 frequently used path so probably not worth it.  */
     316  	      base -= sstride[n] * extent[n] * len_array;
     317  	      mbase -= mstride[n] * extent[n];
     318  	      n++;
     319  	      if (n >= rank)
     320  		return;
     321  	      else
     322  		{
     323  		  count[n]++;
     324  		  base += sstride[n]* len_array;
     325  		  mbase += mstride[n];
     326  		}
     327  	    } while (count[n] == extent[n]);
     328  	}
     329      }
     330    return;
     331  }
     332  
     333  extern void sfindloc0_s1 (gfc_array_index_type * const restrict retarray,
     334         	    		gfc_array_s1 * const restrict array, GFC_UINTEGER_1 *value,
     335  			 GFC_LOGICAL_4 *, GFC_LOGICAL_4 back, gfc_charlen_type len_array,
     336  			 gfc_charlen_type len_value);
     337  export_proto(sfindloc0_s1);
     338  
     339  void
     340  sfindloc0_s1 (gfc_array_index_type * const restrict retarray,
     341      	    gfc_array_s1 * const restrict array, GFC_UINTEGER_1 *value,
     342  	    GFC_LOGICAL_4 * mask, GFC_LOGICAL_4 back, gfc_charlen_type len_array,
     343  	    gfc_charlen_type len_value)
     344  {
     345    index_type rank;
     346    index_type dstride;
     347    index_type * restrict dest;
     348    index_type n;
     349  
     350    if (mask == NULL || *mask)
     351      {
     352        findloc0_s1 (retarray, array, value, back, len_array, len_value);
     353        return;
     354      }
     355  
     356    rank = GFC_DESCRIPTOR_RANK (array);
     357  
     358    if (rank <= 0)
     359      internal_error (NULL, "Rank of array needs to be > 0");
     360  
     361    if (retarray->base_addr == NULL)
     362      {
     363        GFC_DIMENSION_SET(retarray->dim[0], 0, rank-1, 1);
     364        retarray->dtype.rank = 1;
     365        retarray->offset = 0;
     366        retarray->base_addr = xmallocarray (rank, sizeof (index_type));
     367      }
     368    else if (unlikely (compile_options.bounds_check))
     369      {
     370         bounds_iforeach_return ((array_t *) retarray, (array_t *) array,
     371  			       "FINDLOC");
     372      }
     373  
     374    dstride = GFC_DESCRIPTOR_STRIDE(retarray,0);
     375    dest = retarray->base_addr;
     376    for (n = 0; n<rank; n++)
     377      dest[n * dstride] = 0 ;
     378  }
     379  
     380  #endif
     381  
     382  
     383