1 /* Implementation of the MAXVAL intrinsic
2 Copyright (C) 2017-2021 Free Software Foundation, Inc.
3 Contributed by Thomas Koenig
5 This file is part of the GNU Fortran runtime library (libgfortran).
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.
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.
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.
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/>. */
26 #include "libgfortran.h"
29 #if defined (HAVE_GFC_UINTEGER_4) && defined (HAVE_GFC_UINTEGER_4)
35 compare_fcn (const GFC_UINTEGER_4
*a
, const GFC_UINTEGER_4
*b
, gfc_charlen_type n
)
37 if (sizeof (GFC_UINTEGER_4
) == 1)
38 return memcmp (a
, b
, n
);
40 return memcmp_char4 (a
, b
, n
);
43 extern void minval1_s4 (gfc_array_s4
* const restrict
,
44 gfc_charlen_type
, gfc_array_s4
* const restrict
,
45 const index_type
* const restrict
, gfc_charlen_type
);
46 export_proto(minval1_s4
);
49 minval1_s4 (gfc_array_s4
* const restrict retarray
,
50 gfc_charlen_type xlen
, gfc_array_s4
* const restrict array
,
51 const index_type
* const restrict pdim
, gfc_charlen_type string_len
)
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_4
* restrict base
;
58 GFC_UINTEGER_4
* restrict dest
;
66 assert (xlen
== string_len
);
67 /* Make dim zero based to avoid confusion. */
68 rank
= GFC_DESCRIPTOR_RANK (array
) - 1;
71 if (unlikely (dim
< 0 || dim
> rank
))
73 runtime_error ("Dim argument incorrect in MINVAL intrinsic: "
74 "is %ld, should be between 1 and %ld",
75 (long int) dim
+ 1, (long int) rank
+ 1);
78 len
= GFC_DESCRIPTOR_EXTENT(array
,dim
);
82 delta
= GFC_DESCRIPTOR_STRIDE(array
,dim
) * string_len
;
84 for (n
= 0; n
< dim
; n
++)
86 sstride
[n
] = GFC_DESCRIPTOR_STRIDE(array
,n
) * string_len
;
87 extent
[n
] = GFC_DESCRIPTOR_EXTENT(array
,n
);
92 for (n
= dim
; n
< rank
; n
++)
94 sstride
[n
] = GFC_DESCRIPTOR_STRIDE(array
, n
+ 1) * string_len
;
95 extent
[n
] = GFC_DESCRIPTOR_EXTENT(array
, n
+ 1);
101 if (retarray
->base_addr
== NULL
)
103 size_t alloc_size
, str
;
105 for (n
= 0; n
< rank
; n
++)
110 str
= GFC_DESCRIPTOR_STRIDE(retarray
,n
-1) * extent
[n
-1];
112 GFC_DIMENSION_SET(retarray
->dim
[n
], 0, extent
[n
] - 1, str
);
116 retarray
->offset
= 0;
117 retarray
->dtype
.rank
= rank
;
119 alloc_size
= GFC_DESCRIPTOR_STRIDE(retarray
,rank
-1) * extent
[rank
-1]
122 retarray
->base_addr
= xmallocarray (alloc_size
, sizeof (GFC_UINTEGER_4
));
125 /* Make sure we have a zero-sized array. */
126 GFC_DIMENSION_SET(retarray
->dim
[0], 0, -1, 1);
133 if (rank
!= GFC_DESCRIPTOR_RANK (retarray
))
134 runtime_error ("rank of return array incorrect in"
135 " MINVAL intrinsic: is %ld, should be %ld",
136 (long int) (GFC_DESCRIPTOR_RANK (retarray
)),
139 if (unlikely (compile_options
.bounds_check
))
140 bounds_ifunction_return ((array_t
*) retarray
, extent
,
141 "return value", "MINVAL");
144 for (n
= 0; n
< rank
; n
++)
147 dstride
[n
] = GFC_DESCRIPTOR_STRIDE(retarray
,n
) * string_len
;
152 base
= array
->base_addr
;
153 dest
= retarray
->base_addr
;
156 while (continue_loop
)
158 const GFC_UINTEGER_4
* restrict src
;
162 const GFC_UINTEGER_4
*retval
;
165 memset (dest
, 255, sizeof (*dest
) * string_len
);
168 for (n
= 0; n
< len
; n
++, src
+= delta
)
171 if (compare_fcn (src
, retval
, string_len
) < 0)
177 memcpy (dest
, retval
, sizeof (*dest
) * string_len
);
180 /* Advance to the next element. */
185 while (count
[n
] == extent
[n
])
187 /* When we get to the end of a dimension, reset it and increment
188 the next dimension. */
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
];
197 /* Break out of the loop. */
212 extern void mminval1_s4 (gfc_array_s4
* const restrict
,
213 gfc_charlen_type
, gfc_array_s4
* const restrict
,
214 const index_type
* const restrict
,
215 gfc_array_l1
* const restrict
, gfc_charlen_type
);
216 export_proto(mminval1_s4
);
219 mminval1_s4 (gfc_array_s4
* const restrict retarray
,
220 gfc_charlen_type xlen
, gfc_array_s4
* const restrict array
,
221 const index_type
* const restrict pdim
,
222 gfc_array_l1
* const restrict mask
,
223 gfc_charlen_type string_len
)
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_4
* restrict dest
;
232 const GFC_UINTEGER_4
* restrict base
;
233 const GFC_LOGICAL_1
* restrict mbase
;
244 minval1_s4 (retarray
, xlen
, array
, pdim
, string_len
);
248 assert (xlen
== string_len
);
251 rank
= GFC_DESCRIPTOR_RANK (array
) - 1;
253 if (unlikely (dim
< 0 || dim
> rank
))
255 runtime_error ("Dim argument incorrect in MINVAL intrinsic: "
256 "is %ld, should be between 1 and %ld",
257 (long int) dim
+ 1, (long int) rank
+ 1);
260 len
= GFC_DESCRIPTOR_EXTENT(array
,dim
);
264 mbase
= mask
->base_addr
;
266 mask_kind
= GFC_DESCRIPTOR_SIZE (mask
);
268 if (mask_kind
== 1 || mask_kind
== 2 || mask_kind
== 4 || mask_kind
== 8
269 #ifdef HAVE_GFC_LOGICAL_16
273 mbase
= GFOR_POINTER_TO_L1 (mbase
, mask_kind
);
275 runtime_error ("Funny sized logical array");
277 delta
= GFC_DESCRIPTOR_STRIDE(array
,dim
) * string_len
;
278 mdelta
= GFC_DESCRIPTOR_STRIDE_BYTES(mask
,dim
);
280 for (n
= 0; n
< dim
; n
++)
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
);
290 for (n
= dim
; n
< rank
; n
++)
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);
300 if (retarray
->base_addr
== NULL
)
302 size_t alloc_size
, str
;
304 for (n
= 0; n
< rank
; n
++)
309 str
= GFC_DESCRIPTOR_STRIDE(retarray
,n
-1) * extent
[n
-1];
311 GFC_DIMENSION_SET(retarray
->dim
[n
], 0, extent
[n
] - 1, str
);
315 alloc_size
= GFC_DESCRIPTOR_STRIDE(retarray
,rank
-1) * extent
[rank
-1]
318 retarray
->offset
= 0;
319 retarray
->dtype
.rank
= rank
;
323 /* Make sure we have a zero-sized array. */
324 GFC_DIMENSION_SET(retarray
->dim
[0], 0, -1, 1);
328 retarray
->base_addr
= xmallocarray (alloc_size
, sizeof (GFC_UINTEGER_4
));
333 if (rank
!= GFC_DESCRIPTOR_RANK (retarray
))
334 runtime_error ("rank of return array incorrect in MINVAL intrinsic");
336 if (unlikely (compile_options
.bounds_check
))
338 bounds_ifunction_return ((array_t
*) retarray
, extent
,
339 "return value", "MINVAL");
340 bounds_equal_extents ((array_t
*) mask
, (array_t
*) array
,
341 "MASK argument", "MINVAL");
345 for (n
= 0; n
< rank
; n
++)
348 dstride
[n
] = GFC_DESCRIPTOR_STRIDE(retarray
,n
) * string_len
;
353 dest
= retarray
->base_addr
;
354 base
= array
->base_addr
;
358 const GFC_UINTEGER_4
* restrict src
;
359 const GFC_LOGICAL_1
* restrict msrc
;
365 const GFC_UINTEGER_4
*retval
;
366 memset (dest
, 255, sizeof (*dest
) * string_len
);
368 for (n
= 0; n
< len
; n
++, src
+= delta
, msrc
+= mdelta
)
377 for (; n
< len
; n
++, src
+= delta
, msrc
+= mdelta
)
379 if (*msrc
&& compare_fcn (src
, retval
, string_len
) < 0)
385 memcpy (dest
, retval
, sizeof (*dest
) * string_len
);
387 /* Advance to the next element. */
393 while (count
[n
] == extent
[n
])
395 /* When we get to the end of a dimension, reset it and increment
396 the next dimension. */
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
];
406 /* Break out of the loop. */
422 void sminval1_s4 (gfc_array_s4
* const restrict
,
423 gfc_charlen_type
, gfc_array_s4
* const restrict
,
424 const index_type
* const restrict
,
425 GFC_LOGICAL_4
*, gfc_charlen_type
);
427 export_proto(sminval1_s4
);
430 sminval1_s4 (gfc_array_s4
* const restrict retarray
,
431 gfc_charlen_type xlen
, gfc_array_s4
* const restrict array
,
432 const index_type
* const restrict pdim
,
433 GFC_LOGICAL_4
*mask
, gfc_charlen_type string_len
)
436 index_type count
[GFC_MAX_DIMENSIONS
];
437 index_type extent
[GFC_MAX_DIMENSIONS
];
438 index_type dstride
[GFC_MAX_DIMENSIONS
];
439 GFC_UINTEGER_4
* restrict dest
;
445 if (mask
== NULL
|| *mask
)
447 minval1_s4 (retarray
, xlen
, array
, pdim
, string_len
);
450 /* Make dim zero based to avoid confusion. */
452 rank
= GFC_DESCRIPTOR_RANK (array
) - 1;
454 if (unlikely (dim
< 0 || dim
> rank
))
456 runtime_error ("Dim argument incorrect in MINVAL intrinsic: "
457 "is %ld, should be between 1 and %ld",
458 (long int) dim
+ 1, (long int) rank
+ 1);
461 for (n
= 0; n
< dim
; n
++)
463 extent
[n
] = GFC_DESCRIPTOR_EXTENT(array
,n
);
469 for (n
= dim
; n
< rank
; n
++)
472 GFC_DESCRIPTOR_EXTENT(array
,n
+ 1);
478 if (retarray
->base_addr
== NULL
)
480 size_t alloc_size
, str
;
482 for (n
= 0; n
< rank
; n
++)
487 str
= GFC_DESCRIPTOR_STRIDE(retarray
,n
-1) * extent
[n
-1];
489 GFC_DIMENSION_SET(retarray
->dim
[n
], 0, extent
[n
] - 1, str
);
493 retarray
->offset
= 0;
494 retarray
->dtype
.rank
= rank
;
496 alloc_size
= GFC_DESCRIPTOR_STRIDE(retarray
,rank
-1) * extent
[rank
-1]
501 /* Make sure we have a zero-sized array. */
502 GFC_DIMENSION_SET(retarray
->dim
[0], 0, -1, 1);
506 retarray
->base_addr
= xmallocarray (alloc_size
, sizeof (GFC_UINTEGER_4
));
510 if (rank
!= GFC_DESCRIPTOR_RANK (retarray
))
511 runtime_error ("rank of return array incorrect in"
512 " MINVAL intrinsic: is %ld, should be %ld",
513 (long int) (GFC_DESCRIPTOR_RANK (retarray
)),
516 if (unlikely (compile_options
.bounds_check
))
518 for (n
=0; n
< rank
; n
++)
520 index_type ret_extent
;
522 ret_extent
= GFC_DESCRIPTOR_EXTENT(retarray
,n
);
523 if (extent
[n
] != ret_extent
)
524 runtime_error ("Incorrect extent in return value of"
525 " MINVAL intrinsic in dimension %ld:"
526 " is %ld, should be %ld", (long int) n
+ 1,
527 (long int) ret_extent
, (long int) extent
[n
]);
532 for (n
= 0; n
< rank
; n
++)
535 dstride
[n
] = GFC_DESCRIPTOR_STRIDE(retarray
,n
) * string_len
;
538 dest
= retarray
->base_addr
;
542 memset (dest
, 255, sizeof (*dest
) * string_len
);
546 while (count
[n
] == extent
[n
])
548 /* When we get to the end of a dimension, reset it and increment
549 the next dimension. */
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
];