minloc0_8_i16.c 8.96 KB
Newer Older
1
/* Implementation of the MINLOC intrinsic
2
   Copyright (C) 2002-2014 Free Software Foundation, Inc.
3 4 5 6 7 8 9
   Contributed by Paul Brook <paul@nowt.org>

This file is part of the GNU Fortran 95 runtime library (libgfortran).

Libgfortran is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
10
version 3 of the License, or (at your option) any later version.
11 12 13 14 15 16

Libgfortran is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

17 18 19 20 21 22 23 24
Under Section 7 of GPL version 3, you are granted additional
permissions described in the GCC Runtime Library Exception, version
3.1, as published by the Free Software Foundation.

You should have received a copy of the GNU General Public License and
a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
<http://www.gnu.org/licenses/>.  */
25

26
#include "libgfortran.h"
27 28 29 30 31 32 33 34
#include <stdlib.h>
#include <assert.h>
#include <limits.h>


#if defined (HAVE_GFC_INTEGER_16) && defined (HAVE_GFC_INTEGER_8)


Janne Blomqvist committed
35 36
extern void minloc0_8_i16 (gfc_array_i8 * const restrict retarray, 
	gfc_array_i16 * const restrict array);
37 38 39
export_proto(minloc0_8_i16);

void
Janne Blomqvist committed
40 41
minloc0_8_i16 (gfc_array_i8 * const restrict retarray, 
	gfc_array_i16 * const restrict array)
42 43 44 45 46
{
  index_type count[GFC_MAX_DIMENSIONS];
  index_type extent[GFC_MAX_DIMENSIONS];
  index_type sstride[GFC_MAX_DIMENSIONS];
  index_type dstride;
Janne Blomqvist committed
47
  const GFC_INTEGER_16 *base;
48
  GFC_INTEGER_8 * restrict dest;
49 50 51 52 53 54 55
  index_type rank;
  index_type n;

  rank = GFC_DESCRIPTOR_RANK (array);
  if (rank <= 0)
    runtime_error ("Rank of array needs to be > 0");

56
  if (retarray->base_addr == NULL)
57
    {
58
      GFC_DIMENSION_SET(retarray->dim[0], 0, rank-1, 1);
59 60
      retarray->dtype = (retarray->dtype & ~GFC_DTYPE_RANK_MASK) | 1;
      retarray->offset = 0;
61
      retarray->base_addr = xmalloc (sizeof (GFC_INTEGER_8) * rank);
62 63 64
    }
  else
    {
65
      if (unlikely (compile_options.bounds_check))
66 67
	bounds_iforeach_return ((array_t *) retarray, (array_t *) array,
				"MINLOC");
68 69
    }

70
  dstride = GFC_DESCRIPTOR_STRIDE(retarray,0);
71
  dest = retarray->base_addr;
72 73
  for (n = 0; n < rank; n++)
    {
74 75
      sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n);
      extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
76 77 78 79 80 81 82 83 84 85
      count[n] = 0;
      if (extent[n] <= 0)
	{
	  /* Set the return value.  */
	  for (n = 0; n < rank; n++)
	    dest[n * dstride] = 0;
	  return;
	}
    }

86
  base = array->base_addr;
87 88 89

  /* Initialize the return value.  */
  for (n = 0; n < rank; n++)
90
    dest[n * dstride] = 1;
91 92
  {

93 94 95 96
    GFC_INTEGER_16 minval;
#if defined(GFC_INTEGER_16_QUIET_NAN)
    int fast = 0;
#endif
97

98 99 100 101 102
#if defined(GFC_INTEGER_16_INFINITY)
    minval = GFC_INTEGER_16_INFINITY;
#else
    minval = GFC_INTEGER_16_HUGE;
#endif
103 104
  while (base)
    {
105 106 107
      do
	{
	  /* Implementation start.  */
108

109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
#if defined(GFC_INTEGER_16_QUIET_NAN)
	}
      while (0);
      if (unlikely (!fast))
	{
	  do
	    {
	      if (*base <= minval)
		{
		  fast = 1;
		  minval = *base;
		  for (n = 0; n < rank; n++)
		    dest[n * dstride] = count[n] + 1;
		  break;
		}
	      base += sstride[0];
	    }
	  while (++count[0] != extent[0]);
	  if (likely (fast))
	    continue;
	}
      else do
	{
#endif
	  if (*base < minval)
	    {
	      minval = *base;
	      for (n = 0; n < rank; n++)
		dest[n * dstride] = count[n] + 1;
	    }
	  /* Implementation end.  */
	  /* Advance to the next element.  */
	  base += sstride[0];
	}
      while (++count[0] != extent[0]);
144
      n = 0;
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
      do
	{
	  /* When we get to the end of a dimension, reset it and increment
	     the next dimension.  */
	  count[n] = 0;
	  /* We could precalculate these products, but this is a less
	     frequently used path so probably not worth it.  */
	  base -= sstride[n] * extent[n];
	  n++;
	  if (n == rank)
	    {
	      /* Break out of the loop.  */
	      base = NULL;
	      break;
	    }
	  else
	    {
	      count[n]++;
	      base += sstride[n];
	    }
	}
      while (count[n] == extent[n]);
167 168 169 170 171
    }
  }
}


Janne Blomqvist committed
172
extern void mminloc0_8_i16 (gfc_array_i8 * const restrict, 
173
	gfc_array_i16 * const restrict, gfc_array_l1 * const restrict);
174 175 176
export_proto(mminloc0_8_i16);

void
Janne Blomqvist committed
177 178
mminloc0_8_i16 (gfc_array_i8 * const restrict retarray, 
	gfc_array_i16 * const restrict array,
179
	gfc_array_l1 * const restrict mask)
180 181 182 183 184 185 186
{
  index_type count[GFC_MAX_DIMENSIONS];
  index_type extent[GFC_MAX_DIMENSIONS];
  index_type sstride[GFC_MAX_DIMENSIONS];
  index_type mstride[GFC_MAX_DIMENSIONS];
  index_type dstride;
  GFC_INTEGER_8 *dest;
Janne Blomqvist committed
187
  const GFC_INTEGER_16 *base;
188
  GFC_LOGICAL_1 *mbase;
189 190
  int rank;
  index_type n;
191
  int mask_kind;
192 193 194 195 196

  rank = GFC_DESCRIPTOR_RANK (array);
  if (rank <= 0)
    runtime_error ("Rank of array needs to be > 0");

197
  if (retarray->base_addr == NULL)
198
    {
199
      GFC_DIMENSION_SET(retarray->dim[0], 0, rank - 1, 1);
200 201
      retarray->dtype = (retarray->dtype & ~GFC_DTYPE_RANK_MASK) | 1;
      retarray->offset = 0;
202
      retarray->base_addr = xmalloc (sizeof (GFC_INTEGER_8) * rank);
203 204 205
    }
  else
    {
206
      if (unlikely (compile_options.bounds_check))
207
	{
Thomas Koenig committed
208 209 210 211 212

	  bounds_iforeach_return ((array_t *) retarray, (array_t *) array,
				  "MINLOC");
	  bounds_equal_extents ((array_t *) mask, (array_t *) array,
				  "MASK argument", "MINLOC");
213
	}
214 215
    }

216 217
  mask_kind = GFC_DESCRIPTOR_SIZE (mask);

218
  mbase = mask->base_addr;
219 220 221 222 223 224 225 226 227 228

  if (mask_kind == 1 || mask_kind == 2 || mask_kind == 4 || mask_kind == 8
#ifdef HAVE_GFC_LOGICAL_16
      || mask_kind == 16
#endif
      )
    mbase = GFOR_POINTER_TO_L1 (mbase, mask_kind);
  else
    runtime_error ("Funny sized logical array");

229
  dstride = GFC_DESCRIPTOR_STRIDE(retarray,0);
230
  dest = retarray->base_addr;
231 232
  for (n = 0; n < rank; n++)
    {
233 234 235
      sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n);
      mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n);
      extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
236 237 238 239 240 241 242 243 244 245
      count[n] = 0;
      if (extent[n] <= 0)
	{
	  /* Set the return value.  */
	  for (n = 0; n < rank; n++)
	    dest[n * dstride] = 0;
	  return;
	}
    }

246
  base = array->base_addr;
247 248 249

  /* Initialize the return value.  */
  for (n = 0; n < rank; n++)
250
    dest[n * dstride] = 0;
251 252 253
  {

  GFC_INTEGER_16 minval;
254
   int fast = 0;
255

256 257 258 259 260
#if defined(GFC_INTEGER_16_INFINITY)
    minval = GFC_INTEGER_16_INFINITY;
#else
    minval = GFC_INTEGER_16_HUGE;
#endif
261 262
  while (base)
    {
263 264 265
      do
	{
	  /* Implementation start.  */
266

267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
	}
      while (0);
      if (unlikely (!fast))
	{
	  do
	    {
	      if (*mbase)
		{
#if defined(GFC_INTEGER_16_QUIET_NAN)
		  if (unlikely (dest[0] == 0))
		    for (n = 0; n < rank; n++)
		      dest[n * dstride] = count[n] + 1;
		  if (*base <= minval)
#endif
		    {
		      fast = 1;
		      minval = *base;
		      for (n = 0; n < rank; n++)
			dest[n * dstride] = count[n] + 1;
		      break;
		    }
		}
	      base += sstride[0];
	      mbase += mstride[0];
	    }
	  while (++count[0] != extent[0]);
	  if (likely (fast))
	    continue;
	}
      else do
	{
	  if (*mbase && *base < minval)
	    {
	      minval = *base;
	      for (n = 0; n < rank; n++)
		dest[n * dstride] = count[n] + 1;
	    }
	  /* Implementation end.  */
	  /* Advance to the next element.  */
	  base += sstride[0];
	  mbase += mstride[0];
	}
      while (++count[0] != extent[0]);
310
      n = 0;
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
      do
	{
	  /* When we get to the end of a dimension, reset it and increment
	     the next dimension.  */
	  count[n] = 0;
	  /* We could precalculate these products, but this is a less
	     frequently used path so probably not worth it.  */
	  base -= sstride[n] * extent[n];
	  mbase -= mstride[n] * extent[n];
	  n++;
	  if (n == rank)
	    {
	      /* Break out of the loop.  */
	      base = NULL;
	      break;
	    }
	  else
	    {
	      count[n]++;
	      base += sstride[n];
	      mbase += mstride[n];
	    }
	}
      while (count[n] == extent[n]);
335 336 337 338
    }
  }
}

339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364

extern void sminloc0_8_i16 (gfc_array_i8 * const restrict, 
	gfc_array_i16 * const restrict, GFC_LOGICAL_4 *);
export_proto(sminloc0_8_i16);

void
sminloc0_8_i16 (gfc_array_i8 * const restrict retarray, 
	gfc_array_i16 * const restrict array,
	GFC_LOGICAL_4 * mask)
{
  index_type rank;
  index_type dstride;
  index_type n;
  GFC_INTEGER_8 *dest;

  if (*mask)
    {
      minloc0_8_i16 (retarray, array);
      return;
    }

  rank = GFC_DESCRIPTOR_RANK (array);

  if (rank <= 0)
    runtime_error ("Rank of array needs to be > 0");

365
  if (retarray->base_addr == NULL)
366
    {
367
      GFC_DIMENSION_SET(retarray->dim[0], 0, rank-1, 1);
368 369
      retarray->dtype = (retarray->dtype & ~GFC_DTYPE_RANK_MASK) | 1;
      retarray->offset = 0;
370
      retarray->base_addr = xmalloc (sizeof (GFC_INTEGER_8) * rank);
371
    }
Thomas Koenig committed
372
  else if (unlikely (compile_options.bounds_check))
373
    {
Thomas Koenig committed
374 375
       bounds_iforeach_return ((array_t *) retarray, (array_t *) array,
			       "MINLOC");
376 377
    }

378
  dstride = GFC_DESCRIPTOR_STRIDE(retarray,0);
379
  dest = retarray->base_addr;
380 381 382
  for (n = 0; n<rank; n++)
    dest[n * dstride] = 0 ;
}
383
#endif