1 /* Implementation of the MAXVAL intrinsic
2 Copyright (C) 2017-2018 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_INTEGER_1) && defined (HAVE_GFC_INTEGER_1)
30
31 #include <string.h>
32 #include <assert.h>
33
34 static inline int
compare_fcn(const GFC_INTEGER_1 * a,const GFC_INTEGER_1 * b,gfc_charlen_type n)35 compare_fcn (const GFC_INTEGER_1 *a, const GFC_INTEGER_1 *b, gfc_charlen_type n)
36 {
37 if (sizeof (GFC_INTEGER_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_INTEGER_1 * restrict base;
58 GFC_INTEGER_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_INTEGER_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_INTEGER_1 * restrict src;
159 src = base;
160 {
161
162 const GFC_INTEGER_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_INTEGER_1 * restrict dest;
232 const GFC_INTEGER_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 assert (xlen == string_len);
243
244 dim = (*pdim) - 1;
245 rank = GFC_DESCRIPTOR_RANK (array) - 1;
246
247 if (unlikely (dim < 0 || dim > rank))
248 {
249 runtime_error ("Dim argument incorrect in MAXVAL intrinsic: "
250 "is %ld, should be between 1 and %ld",
251 (long int) dim + 1, (long int) rank + 1);
252 }
253
254 len = GFC_DESCRIPTOR_EXTENT(array,dim);
255 if (len <= 0)
256 return;
257
258 mbase = mask->base_addr;
259
260 mask_kind = GFC_DESCRIPTOR_SIZE (mask);
261
262 if (mask_kind == 1 || mask_kind == 2 || mask_kind == 4 || mask_kind == 8
263 #ifdef HAVE_GFC_LOGICAL_16
264 || mask_kind == 16
265 #endif
266 )
267 mbase = GFOR_POINTER_TO_L1 (mbase, mask_kind);
268 else
269 runtime_error ("Funny sized logical array");
270
271 delta = GFC_DESCRIPTOR_STRIDE(array,dim) * string_len;
272 mdelta = GFC_DESCRIPTOR_STRIDE_BYTES(mask,dim);
273
274 for (n = 0; n < dim; n++)
275 {
276 sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n) * string_len;
277 mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n);
278 extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
279
280 if (extent[n] < 0)
281 extent[n] = 0;
282
283 }
284 for (n = dim; n < rank; n++)
285 {
286 sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n + 1) * string_len;
287 mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask, n + 1);
288 extent[n] = GFC_DESCRIPTOR_EXTENT(array, n + 1);
289
290 if (extent[n] < 0)
291 extent[n] = 0;
292 }
293
294 if (retarray->base_addr == NULL)
295 {
296 size_t alloc_size, str;
297
298 for (n = 0; n < rank; n++)
299 {
300 if (n == 0)
301 str = 1;
302 else
303 str= GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1];
304
305 GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str);
306
307 }
308
309 alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1]
310 * string_len;
311
312 retarray->offset = 0;
313 retarray->dtype.rank = rank;
314
315 if (alloc_size == 0)
316 {
317 /* Make sure we have a zero-sized array. */
318 GFC_DIMENSION_SET(retarray->dim[0], 0, -1, 1);
319 return;
320 }
321 else
322 retarray->base_addr = xmallocarray (alloc_size, sizeof (GFC_INTEGER_1));
323
324 }
325 else
326 {
327 if (rank != GFC_DESCRIPTOR_RANK (retarray))
328 runtime_error ("rank of return array incorrect in MAXVAL intrinsic");
329
330 if (unlikely (compile_options.bounds_check))
331 {
332 bounds_ifunction_return ((array_t *) retarray, extent,
333 "return value", "MAXVAL");
334 bounds_equal_extents ((array_t *) mask, (array_t *) array,
335 "MASK argument", "MAXVAL");
336 }
337 }
338
339 for (n = 0; n < rank; n++)
340 {
341 count[n] = 0;
342 dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n) * string_len;
343 if (extent[n] <= 0)
344 return;
345 }
346
347 dest = retarray->base_addr;
348 base = array->base_addr;
349
350 while (base)
351 {
352 const GFC_INTEGER_1 * restrict src;
353 const GFC_LOGICAL_1 * restrict msrc;
354
355 src = base;
356 msrc = mbase;
357 {
358
359 const GFC_INTEGER_1 *retval;
360 memset (dest, 0, sizeof (*dest) * string_len);
361 retval = dest;
362 for (n = 0; n < len; n++, src += delta, msrc += mdelta)
363 {
364
365 if (*msrc)
366 {
367 retval = src;
368 break;
369 }
370 }
371 for (; n < len; n++, src += delta, msrc += mdelta)
372 {
373 if (*msrc && compare_fcn (src, retval, string_len) > 0)
374 {
375 retval = src;
376 }
377
378 }
379 memcpy (dest, retval, sizeof (*dest) * string_len);
380 }
381 /* Advance to the next element. */
382 count[0]++;
383 base += sstride[0];
384 mbase += mstride[0];
385 dest += dstride[0];
386 n = 0;
387 while (count[n] == extent[n])
388 {
389 /* When we get to the end of a dimension, reset it and increment
390 the next dimension. */
391 count[n] = 0;
392 /* We could precalculate these products, but this is a less
393 frequently used path so probably not worth it. */
394 base -= sstride[n] * extent[n];
395 mbase -= mstride[n] * extent[n];
396 dest -= dstride[n] * extent[n];
397 n++;
398 if (n >= rank)
399 {
400 /* Break out of the loop. */
401 base = NULL;
402 break;
403 }
404 else
405 {
406 count[n]++;
407 base += sstride[n];
408 mbase += mstride[n];
409 dest += dstride[n];
410 }
411 }
412 }
413 }
414
415
416 void smaxval1_s1 (gfc_array_s1 * const restrict,
417 gfc_charlen_type, gfc_array_s1 * const restrict,
418 const index_type * const restrict,
419 GFC_LOGICAL_4 *, gfc_charlen_type);
420
421 export_proto(smaxval1_s1);
422
423 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)424 smaxval1_s1 (gfc_array_s1 * const restrict retarray,
425 gfc_charlen_type xlen, gfc_array_s1 * const restrict array,
426 const index_type * const restrict pdim,
427 GFC_LOGICAL_4 *mask, gfc_charlen_type string_len)
428
429 {
430 index_type count[GFC_MAX_DIMENSIONS];
431 index_type extent[GFC_MAX_DIMENSIONS];
432 index_type dstride[GFC_MAX_DIMENSIONS];
433 GFC_INTEGER_1 * restrict dest;
434 index_type rank;
435 index_type n;
436 index_type dim;
437
438
439 if (*mask)
440 {
441 maxval1_s1 (retarray, xlen, array, pdim, string_len);
442 return;
443 }
444 /* Make dim zero based to avoid confusion. */
445 dim = (*pdim) - 1;
446 rank = GFC_DESCRIPTOR_RANK (array) - 1;
447
448 if (unlikely (dim < 0 || dim > rank))
449 {
450 runtime_error ("Dim argument incorrect in MAXVAL intrinsic: "
451 "is %ld, should be between 1 and %ld",
452 (long int) dim + 1, (long int) rank + 1);
453 }
454
455 for (n = 0; n < dim; n++)
456 {
457 extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
458
459 if (extent[n] <= 0)
460 extent[n] = 0;
461 }
462
463 for (n = dim; n < rank; n++)
464 {
465 extent[n] =
466 GFC_DESCRIPTOR_EXTENT(array,n + 1);
467
468 if (extent[n] <= 0)
469 extent[n] = 0;
470 }
471
472 if (retarray->base_addr == NULL)
473 {
474 size_t alloc_size, str;
475
476 for (n = 0; n < rank; n++)
477 {
478 if (n == 0)
479 str = 1;
480 else
481 str = GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1];
482
483 GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str);
484
485 }
486
487 retarray->offset = 0;
488 retarray->dtype.rank = rank;
489
490 alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1]
491 * string_len;
492
493 if (alloc_size == 0)
494 {
495 /* Make sure we have a zero-sized array. */
496 GFC_DIMENSION_SET(retarray->dim[0], 0, -1, 1);
497 return;
498 }
499 else
500 retarray->base_addr = xmallocarray (alloc_size, sizeof (GFC_INTEGER_1));
501 }
502 else
503 {
504 if (rank != GFC_DESCRIPTOR_RANK (retarray))
505 runtime_error ("rank of return array incorrect in"
506 " MAXVAL intrinsic: is %ld, should be %ld",
507 (long int) (GFC_DESCRIPTOR_RANK (retarray)),
508 (long int) rank);
509
510 if (unlikely (compile_options.bounds_check))
511 {
512 for (n=0; n < rank; n++)
513 {
514 index_type ret_extent;
515
516 ret_extent = GFC_DESCRIPTOR_EXTENT(retarray,n);
517 if (extent[n] != ret_extent)
518 runtime_error ("Incorrect extent in return value of"
519 " MAXVAL intrinsic in dimension %ld:"
520 " is %ld, should be %ld", (long int) n + 1,
521 (long int) ret_extent, (long int) extent[n]);
522 }
523 }
524 }
525
526 for (n = 0; n < rank; n++)
527 {
528 count[n] = 0;
529 dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n) * string_len;
530 }
531
532 dest = retarray->base_addr;
533
534 while(1)
535 {
536 memset (dest, 0, sizeof (*dest) * string_len);
537 count[0]++;
538 dest += dstride[0];
539 n = 0;
540 while (count[n] == extent[n])
541 {
542 /* When we get to the end of a dimension, reset it and increment
543 the next dimension. */
544 count[n] = 0;
545 /* We could precalculate these products, but this is a less
546 frequently used path so probably not worth it. */
547 dest -= dstride[n] * extent[n];
548 n++;
549 if (n >= rank)
550 return;
551 else
552 {
553 count[n]++;
554 dest += dstride[n];
555 }
556 }
557 }
558 }
559
560 #endif
561