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