1 /* Implementation of the MAXVAL intrinsic
2 Copyright (C) 2017-2018 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_INTEGER_1) && defined (HAVE_GFC_INTEGER_1)
35 compare_fcn (const GFC_INTEGER_1
*a
, const GFC_INTEGER_1
*b
, gfc_charlen_type n
)
37 if (sizeof (GFC_INTEGER_1
) == 1)
38 return memcmp (a
, b
, n
);
40 return memcmp_char4 (a
, b
, n
);
43 extern void minval1_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(minval1_s1
);
49 minval1_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
)
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
;
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 GFC_DTYPE_COPY_SETRANK(retarray
,array
,rank
);
119 alloc_size
= GFC_DESCRIPTOR_STRIDE(retarray
,rank
-1) * extent
[rank
-1]
122 retarray
->base_addr
= xmallocarray (alloc_size
, sizeof (GFC_INTEGER_1
));
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_INTEGER_1
* restrict src
;
162 const GFC_INTEGER_1
*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_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(mminval1_s1
);
219 mminval1_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
)
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
;
242 assert (xlen
== string_len
);
245 rank
= GFC_DESCRIPTOR_RANK (array
) - 1;
247 if (unlikely (dim
< 0 || dim
> rank
))
249 runtime_error ("Dim argument incorrect in MINVAL intrinsic: "
250 "is %ld, should be between 1 and %ld",
251 (long int) dim
+ 1, (long int) rank
+ 1);
254 len
= GFC_DESCRIPTOR_EXTENT(array
,dim
);
258 mbase
= mask
->base_addr
;
260 mask_kind
= GFC_DESCRIPTOR_SIZE (mask
);
262 if (mask_kind
== 1 || mask_kind
== 2 || mask_kind
== 4 || mask_kind
== 8
263 #ifdef HAVE_GFC_LOGICAL_16
267 mbase
= GFOR_POINTER_TO_L1 (mbase
, mask_kind
);
269 runtime_error ("Funny sized logical array");
271 delta
= GFC_DESCRIPTOR_STRIDE(array
,dim
) * string_len
;
272 mdelta
= GFC_DESCRIPTOR_STRIDE_BYTES(mask
,dim
);
274 for (n
= 0; n
< dim
; n
++)
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
);
284 for (n
= dim
; n
< rank
; n
++)
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);
294 if (retarray
->base_addr
== NULL
)
296 size_t alloc_size
, str
;
298 for (n
= 0; n
< rank
; n
++)
303 str
= GFC_DESCRIPTOR_STRIDE(retarray
,n
-1) * extent
[n
-1];
305 GFC_DIMENSION_SET(retarray
->dim
[n
], 0, extent
[n
] - 1, str
);
309 alloc_size
= GFC_DESCRIPTOR_STRIDE(retarray
,rank
-1) * extent
[rank
-1]
312 retarray
->offset
= 0;
313 GFC_DTYPE_COPY_SETRANK(retarray
,array
,rank
);
317 /* Make sure we have a zero-sized array. */
318 GFC_DIMENSION_SET(retarray
->dim
[0], 0, -1, 1);
322 retarray
->base_addr
= xmallocarray (alloc_size
, sizeof (GFC_INTEGER_1
));
327 if (rank
!= GFC_DESCRIPTOR_RANK (retarray
))
328 runtime_error ("rank of return array incorrect in MINVAL intrinsic");
330 if (unlikely (compile_options
.bounds_check
))
332 bounds_ifunction_return ((array_t
*) retarray
, extent
,
333 "return value", "MINVAL");
334 bounds_equal_extents ((array_t
*) mask
, (array_t
*) array
,
335 "MASK argument", "MINVAL");
339 for (n
= 0; n
< rank
; n
++)
342 dstride
[n
] = GFC_DESCRIPTOR_STRIDE(retarray
,n
) * string_len
;
347 dest
= retarray
->base_addr
;
348 base
= array
->base_addr
;
352 const GFC_INTEGER_1
* restrict src
;
353 const GFC_LOGICAL_1
* restrict msrc
;
359 const GFC_INTEGER_1
*retval
;
360 memset (dest
, 255, sizeof (*dest
) * string_len
);
362 for (n
= 0; n
< len
; n
++, src
+= delta
, msrc
+= mdelta
)
371 for (; n
< len
; n
++, src
+= delta
, msrc
+= mdelta
)
373 if (*msrc
&& compare_fcn (src
, retval
, string_len
) < 0)
379 memcpy (dest
, retval
, sizeof (*dest
) * string_len
);
381 /* Advance to the next element. */
387 while (count
[n
] == extent
[n
])
389 /* When we get to the end of a dimension, reset it and increment
390 the next dimension. */
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
];
400 /* Break out of the loop. */
416 void sminval1_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
);
421 export_proto(sminval1_s1
);
424 sminval1_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
)
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
;
441 minval1_s1 (retarray
, xlen
, array
, pdim
, string_len
);
444 /* Make dim zero based to avoid confusion. */
446 rank
= GFC_DESCRIPTOR_RANK (array
) - 1;
448 if (unlikely (dim
< 0 || dim
> rank
))
450 runtime_error ("Dim argument incorrect in MINVAL intrinsic: "
451 "is %ld, should be between 1 and %ld",
452 (long int) dim
+ 1, (long int) rank
+ 1);
455 for (n
= 0; n
< dim
; n
++)
457 extent
[n
] = GFC_DESCRIPTOR_EXTENT(array
,n
);
463 for (n
= dim
; n
< rank
; n
++)
466 GFC_DESCRIPTOR_EXTENT(array
,n
+ 1);
472 if (retarray
->base_addr
== NULL
)
474 size_t alloc_size
, str
;
476 for (n
= 0; n
< rank
; n
++)
481 str
= GFC_DESCRIPTOR_STRIDE(retarray
,n
-1) * extent
[n
-1];
483 GFC_DIMENSION_SET(retarray
->dim
[n
], 0, extent
[n
] - 1, str
);
487 retarray
->offset
= 0;
488 GFC_DTYPE_COPY_SETRANK(retarray
,array
,rank
);
490 alloc_size
= GFC_DESCRIPTOR_STRIDE(retarray
,rank
-1) * extent
[rank
-1]
495 /* Make sure we have a zero-sized array. */
496 GFC_DIMENSION_SET(retarray
->dim
[0], 0, -1, 1);
500 retarray
->base_addr
= xmallocarray (alloc_size
, sizeof (GFC_INTEGER_1
));
504 if (rank
!= GFC_DESCRIPTOR_RANK (retarray
))
505 runtime_error ("rank of return array incorrect in"
506 " MINVAL intrinsic: is %ld, should be %ld",
507 (long int) (GFC_DESCRIPTOR_RANK (retarray
)),
510 if (unlikely (compile_options
.bounds_check
))
512 for (n
=0; n
< rank
; n
++)
514 index_type ret_extent
;
516 ret_extent
= GFC_DESCRIPTOR_EXTENT(retarray
,n
);
517 if (extent
[n
] != ret_extent
)
518 runtime_error ("Incorrect extent in return value of"
519 " MINVAL intrinsic in dimension %ld:"
520 " is %ld, should be %ld", (long int) n
+ 1,
521 (long int) ret_extent
, (long int) extent
[n
]);
526 for (n
= 0; n
< rank
; n
++)
529 dstride
[n
] = GFC_DESCRIPTOR_STRIDE(retarray
,n
) * string_len
;
532 dest
= retarray
->base_addr
;
536 memset (dest
, 255, sizeof (*dest
) * string_len
);
540 while (count
[n
] == extent
[n
])
542 /* When we get to the end of a dimension, reset it and increment
543 the next dimension. */
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
];