1 /* Implementation of the FINDLOC intrinsic
2    Copyright (C) 2018-2019 Free Software Foundation, Inc.
3    Contributed by Thomas König <tk@tkoenig.net>
4 
5 This file is part of the GNU Fortran 95 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 #include <assert.h>
28 
29 #if defined (HAVE_GFC_REAL_4)
30 extern void findloc1_r4 (gfc_array_index_type * const restrict retarray,
31 		         gfc_array_r4 * const restrict array, GFC_REAL_4 value,
32 			 const index_type * restrict pdim, GFC_LOGICAL_4 back);
33 export_proto(findloc1_r4);
34 
35 extern void
findloc1_r4(gfc_array_index_type * const restrict retarray,gfc_array_r4 * const restrict array,GFC_REAL_4 value,const index_type * restrict pdim,GFC_LOGICAL_4 back)36 findloc1_r4 (gfc_array_index_type * const restrict retarray,
37 	    gfc_array_r4 * const restrict array, GFC_REAL_4 value,
38 	    const index_type * restrict pdim, GFC_LOGICAL_4 back)
39 {
40   index_type count[GFC_MAX_DIMENSIONS];
41   index_type extent[GFC_MAX_DIMENSIONS];
42   index_type sstride[GFC_MAX_DIMENSIONS];
43   index_type dstride[GFC_MAX_DIMENSIONS];
44   const GFC_REAL_4 * restrict base;
45   index_type * restrict dest;
46   index_type rank;
47   index_type n;
48   index_type len;
49   index_type delta;
50   index_type dim;
51   int continue_loop;
52 
53   /* Make dim zero based to avoid confusion.  */
54   rank = GFC_DESCRIPTOR_RANK (array) - 1;
55   dim = (*pdim) - 1;
56 
57   if (unlikely (dim < 0 || dim > rank))
58     {
59       runtime_error ("Dim argument incorrect in FINDLOC intrinsic: "
60  		     "is %ld, should be between 1 and %ld",
61 		     (long int) dim + 1, (long int) rank + 1);
62     }
63 
64   len = GFC_DESCRIPTOR_EXTENT(array,dim);
65   if (len < 0)
66     len = 0;
67   delta = GFC_DESCRIPTOR_STRIDE(array,dim);
68 
69   for (n = 0; n < dim; n++)
70     {
71       sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n);
72       extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
73 
74       if (extent[n] < 0)
75 	extent[n] = 0;
76     }
77   for (n = dim; n < rank; n++)
78     {
79       sstride[n] = GFC_DESCRIPTOR_STRIDE(array, n + 1);
80       extent[n] = GFC_DESCRIPTOR_EXTENT(array, n + 1);
81 
82       if (extent[n] < 0)
83 	extent[n] = 0;
84     }
85 
86   if (retarray->base_addr == NULL)
87     {
88       size_t alloc_size, str;
89 
90       for (n = 0; n < rank; n++)
91 	{
92 	  if (n == 0)
93 	    str = 1;
94 	  else
95 	    str = GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1];
96 
97 	  GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str);
98 
99 	}
100 
101       retarray->offset = 0;
102       retarray->dtype.rank = rank;
103 
104       alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1];
105 
106       retarray->base_addr = xmallocarray (alloc_size, sizeof (index_type));
107       if (alloc_size == 0)
108 	{
109 	  /* Make sure we have a zero-sized array.  */
110 	  GFC_DIMENSION_SET(retarray->dim[0], 0, -1, 1);
111 	  return;
112 	}
113     }
114   else
115     {
116       if (rank != GFC_DESCRIPTOR_RANK (retarray))
117 	runtime_error ("rank of return array incorrect in"
118 		       " FINDLOC intrinsic: is %ld, should be %ld",
119 		       (long int) (GFC_DESCRIPTOR_RANK (retarray)),
120 		       (long int) rank);
121 
122       if (unlikely (compile_options.bounds_check))
123 	bounds_ifunction_return ((array_t *) retarray, extent,
124 				 "return value", "FINDLOC");
125     }
126 
127   for (n = 0; n < rank; n++)
128     {
129       count[n] = 0;
130       dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n);
131       if (extent[n] <= 0)
132 	return;
133     }
134 
135   dest = retarray->base_addr;
136   continue_loop = 1;
137 
138   base = array->base_addr;
139   while (continue_loop)
140     {
141       const GFC_REAL_4 * restrict src;
142       index_type result;
143 
144       result = 0;
145       if (back)
146 	{
147 	  src = base + (len - 1) * delta * 1;
148 	  for (n = len; n > 0; n--, src -= delta * 1)
149 	    {
150 	      if (*src == value)
151 		{
152 		  result = n;
153 		  break;
154 		}
155 	    }
156 	}
157       else
158 	{
159 	  src = base;
160 	  for (n = 1; n <= len; n++, src += delta * 1)
161 	    {
162 	      if (*src == value)
163 		{
164 		  result = n;
165 		  break;
166 		}
167 	    }
168 	}
169       *dest = result;
170 
171       count[0]++;
172       base += sstride[0] * 1;
173       dest += dstride[0];
174       n = 0;
175       while (count[n] == extent[n])
176 	{
177 	  count[n] = 0;
178 	  base -= sstride[n] * extent[n] * 1;
179 	  dest -= dstride[n] * extent[n];
180 	  n++;
181 	  if (n >= rank)
182 	    {
183 	      continue_loop = 0;
184 	      break;
185 	    }
186 	  else
187 	    {
188 	      count[n]++;
189 	      base += sstride[n] * 1;
190 	      dest += dstride[n];
191 	    }
192 	}
193     }
194 }
195 extern void mfindloc1_r4 (gfc_array_index_type * const restrict retarray,
196 		         gfc_array_r4 * const restrict array, GFC_REAL_4 value,
197 			 const index_type * restrict pdim, gfc_array_l1 *const restrict mask,
198 			 GFC_LOGICAL_4 back);
199 export_proto(mfindloc1_r4);
200 
201 extern void
mfindloc1_r4(gfc_array_index_type * const restrict retarray,gfc_array_r4 * const restrict array,GFC_REAL_4 value,const index_type * restrict pdim,gfc_array_l1 * const restrict mask,GFC_LOGICAL_4 back)202 mfindloc1_r4 (gfc_array_index_type * const restrict retarray,
203 	    gfc_array_r4 * const restrict array, GFC_REAL_4 value,
204 	    const index_type * restrict pdim, gfc_array_l1 *const restrict mask,
205 	    GFC_LOGICAL_4 back)
206 {
207   index_type count[GFC_MAX_DIMENSIONS];
208   index_type extent[GFC_MAX_DIMENSIONS];
209   index_type sstride[GFC_MAX_DIMENSIONS];
210   index_type mstride[GFC_MAX_DIMENSIONS];
211   index_type dstride[GFC_MAX_DIMENSIONS];
212   const GFC_REAL_4 * restrict base;
213   const GFC_LOGICAL_1 * restrict mbase;
214   index_type * restrict dest;
215   index_type rank;
216   index_type n;
217   index_type len;
218   index_type delta;
219   index_type mdelta;
220   index_type dim;
221   int mask_kind;
222   int continue_loop;
223 
224   /* Make dim zero based to avoid confusion.  */
225   rank = GFC_DESCRIPTOR_RANK (array) - 1;
226   dim = (*pdim) - 1;
227 
228   if (unlikely (dim < 0 || dim > rank))
229     {
230       runtime_error ("Dim argument incorrect in FINDLOC intrinsic: "
231  		     "is %ld, should be between 1 and %ld",
232 		     (long int) dim + 1, (long int) rank + 1);
233     }
234 
235   len = GFC_DESCRIPTOR_EXTENT(array,dim);
236   if (len < 0)
237     len = 0;
238 
239   delta = GFC_DESCRIPTOR_STRIDE(array,dim);
240   mdelta = GFC_DESCRIPTOR_STRIDE_BYTES(mask,dim);
241 
242   mbase = mask->base_addr;
243 
244   mask_kind = GFC_DESCRIPTOR_SIZE (mask);
245 
246   if (mask_kind == 1 || mask_kind == 2 || mask_kind == 4 || mask_kind == 8
247 #ifdef HAVE_GFC_LOGICAL_16
248       || mask_kind == 16
249 #endif
250       )
251     mbase = GFOR_POINTER_TO_L1 (mbase, mask_kind);
252   else
253     internal_error (NULL, "Funny sized logical array");
254 
255   for (n = 0; n < dim; n++)
256     {
257       sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n);
258       mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n);
259       extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
260 
261       if (extent[n] < 0)
262 	extent[n] = 0;
263     }
264   for (n = dim; n < rank; n++)
265     {
266       sstride[n] = GFC_DESCRIPTOR_STRIDE(array, n + 1);
267       mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask, n + 1);
268       extent[n] = GFC_DESCRIPTOR_EXTENT(array, n + 1);
269 
270       if (extent[n] < 0)
271 	extent[n] = 0;
272     }
273 
274   if (retarray->base_addr == NULL)
275     {
276       size_t alloc_size, str;
277 
278       for (n = 0; n < rank; n++)
279 	{
280 	  if (n == 0)
281 	    str = 1;
282 	  else
283 	    str = GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1];
284 
285 	  GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str);
286 
287 	}
288 
289       retarray->offset = 0;
290       retarray->dtype.rank = rank;
291 
292       alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1];
293 
294       retarray->base_addr = xmallocarray (alloc_size, sizeof (index_type));
295       if (alloc_size == 0)
296 	{
297 	  /* Make sure we have a zero-sized array.  */
298 	  GFC_DIMENSION_SET(retarray->dim[0], 0, -1, 1);
299 	  return;
300 	}
301     }
302   else
303     {
304       if (rank != GFC_DESCRIPTOR_RANK (retarray))
305 	runtime_error ("rank of return array incorrect in"
306 		       " FINDLOC intrinsic: is %ld, should be %ld",
307 		       (long int) (GFC_DESCRIPTOR_RANK (retarray)),
308 		       (long int) rank);
309 
310       if (unlikely (compile_options.bounds_check))
311 	bounds_ifunction_return ((array_t *) retarray, extent,
312 				 "return value", "FINDLOC");
313     }
314 
315   for (n = 0; n < rank; n++)
316     {
317       count[n] = 0;
318       dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n);
319       if (extent[n] <= 0)
320 	return;
321     }
322 
323   dest = retarray->base_addr;
324   continue_loop = 1;
325 
326   base = array->base_addr;
327   while (continue_loop)
328     {
329       const GFC_REAL_4 * restrict src;
330       const GFC_LOGICAL_1 * restrict msrc;
331       index_type result;
332 
333       result = 0;
334       if (back)
335 	{
336 	  src = base + (len - 1) * delta * 1;
337 	  msrc = mbase + (len - 1) * mdelta;
338 	  for (n = len; n > 0; n--, src -= delta * 1, msrc -= mdelta)
339 	    {
340 	      if (*msrc && *src == value)
341 		{
342 		  result = n;
343 		  break;
344 		}
345 	    }
346 	}
347       else
348 	{
349 	  src = base;
350 	  msrc = mbase;
351 	  for (n = 1; n <= len; n++, src += delta * 1, msrc += mdelta)
352 	    {
353 	      if (*msrc && *src == value)
354 		{
355 		  result = n;
356 		  break;
357 		}
358 	    }
359 	}
360       *dest = result;
361 
362       count[0]++;
363       base += sstride[0] * 1;
364       mbase += mstride[0];
365       dest += dstride[0];
366       n = 0;
367       while (count[n] == extent[n])
368 	{
369 	  count[n] = 0;
370 	  base -= sstride[n] * extent[n] * 1;
371 	  mbase -= mstride[n] * extent[n];
372 	  dest -= dstride[n] * extent[n];
373 	  n++;
374 	  if (n >= rank)
375 	    {
376 	      continue_loop = 0;
377 	      break;
378 	    }
379 	  else
380 	    {
381 	      count[n]++;
382 	      base += sstride[n] * 1;
383 	      dest += dstride[n];
384 	    }
385 	}
386     }
387 }
388 extern void sfindloc1_r4 (gfc_array_index_type * const restrict retarray,
389 		         gfc_array_r4 * const restrict array, GFC_REAL_4 value,
390 			 const index_type * restrict pdim, GFC_LOGICAL_4 *const restrict mask,
391 			 GFC_LOGICAL_4 back);
392 export_proto(sfindloc1_r4);
393 
394 extern void
sfindloc1_r4(gfc_array_index_type * const restrict retarray,gfc_array_r4 * const restrict array,GFC_REAL_4 value,const index_type * restrict pdim,GFC_LOGICAL_4 * const restrict mask,GFC_LOGICAL_4 back)395 sfindloc1_r4 (gfc_array_index_type * const restrict retarray,
396 	    gfc_array_r4 * const restrict array, GFC_REAL_4 value,
397 	    const index_type * restrict pdim, GFC_LOGICAL_4 *const restrict  mask,
398 	    GFC_LOGICAL_4 back)
399 {
400   index_type count[GFC_MAX_DIMENSIONS];
401   index_type extent[GFC_MAX_DIMENSIONS];
402   index_type dstride[GFC_MAX_DIMENSIONS];
403   index_type * restrict dest;
404   index_type rank;
405   index_type n;
406   index_type len;
407   index_type dim;
408   bool continue_loop;
409 
410   if (mask == NULL || *mask)
411     {
412       findloc1_r4 (retarray, array, value, pdim, back);
413       return;
414     }
415     /* Make dim zero based to avoid confusion.  */
416   rank = GFC_DESCRIPTOR_RANK (array) - 1;
417   dim = (*pdim) - 1;
418 
419   if (unlikely (dim < 0 || dim > rank))
420     {
421       runtime_error ("Dim argument incorrect in FINDLOC intrinsic: "
422  		     "is %ld, should be between 1 and %ld",
423 		     (long int) dim + 1, (long int) rank + 1);
424     }
425 
426   len = GFC_DESCRIPTOR_EXTENT(array,dim);
427   if (len < 0)
428     len = 0;
429 
430   for (n = 0; n < dim; n++)
431     {
432       extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
433 
434       if (extent[n] <= 0)
435 	extent[n] = 0;
436     }
437 
438   for (n = dim; n < rank; n++)
439     {
440       extent[n] =
441 	GFC_DESCRIPTOR_EXTENT(array,n + 1);
442 
443       if (extent[n] <= 0)
444 	extent[n] = 0;
445     }
446 
447 
448   if (retarray->base_addr == NULL)
449     {
450       size_t alloc_size, str;
451 
452       for (n = 0; n < rank; n++)
453 	{
454 	  if (n == 0)
455 	    str = 1;
456 	  else
457 	    str = GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1];
458 
459 	  GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str);
460 	}
461 
462       retarray->offset = 0;
463       retarray->dtype.rank = rank;
464 
465       alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1];
466 
467       retarray->base_addr = xmallocarray (alloc_size, sizeof (index_type));
468       if (alloc_size == 0)
469 	{
470 	  /* Make sure we have a zero-sized array.  */
471 	  GFC_DIMENSION_SET(retarray->dim[0], 0, -1, 1);
472 	  return;
473 	}
474     }
475   else
476     {
477       if (rank != GFC_DESCRIPTOR_RANK (retarray))
478 	runtime_error ("rank of return array incorrect in"
479 		       " FINDLOC intrinsic: is %ld, should be %ld",
480 		       (long int) (GFC_DESCRIPTOR_RANK (retarray)),
481 		       (long int) rank);
482 
483       if (unlikely (compile_options.bounds_check))
484 	bounds_ifunction_return ((array_t *) retarray, extent,
485 				 "return value", "FINDLOC");
486     }
487 
488   for (n = 0; n < rank; n++)
489     {
490       count[n] = 0;
491       dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n);
492       if (extent[n] <= 0)
493 	return;
494     }
495   dest = retarray->base_addr;
496   continue_loop = 1;
497 
498   while (continue_loop)
499     {
500       *dest = 0;
501 
502       count[0]++;
503       dest += dstride[0];
504       n = 0;
505       while (count[n] == extent[n])
506 	{
507 	  count[n] = 0;
508 	  dest -= dstride[n] * extent[n];
509 	  n++;
510 	  if (n >= rank)
511 	    {
512 	      continue_loop = 0;
513 	      break;
514 	    }
515 	  else
516 	    {
517 	      count[n]++;
518 	      dest += dstride[n];
519 	    }
520 	}
521     }
522 }
523 #endif
524