1 /* Implementation of the MINLOC intrinsic
2 Copyright (C) 2017-2024 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_1) && defined (HAVE_GFC_INTEGER_16)
31 #define HAVE_BACK_ARG 1
37 compare_fcn (const GFC_UINTEGER_1
*a
, const GFC_UINTEGER_1
*b
, gfc_charlen_type n
)
39 if (sizeof (GFC_UINTEGER_1
) == 1)
40 return memcmp (a
, b
, n
);
42 return memcmp_char4 (a
, b
, n
);
45 extern void minloc1_16_s1 (gfc_array_i16
* const restrict
,
46 gfc_array_s1
* const restrict
, const index_type
* const restrict
, GFC_LOGICAL_4 back
,
48 export_proto(minloc1_16_s1
);
51 minloc1_16_s1 (gfc_array_i16
* const restrict retarray
,
52 gfc_array_s1
* const restrict array
,
53 const index_type
* const restrict pdim
, GFC_LOGICAL_4 back
,
54 gfc_charlen_type string_len
)
56 index_type count
[GFC_MAX_DIMENSIONS
];
57 index_type extent
[GFC_MAX_DIMENSIONS
];
58 index_type sstride
[GFC_MAX_DIMENSIONS
];
59 index_type dstride
[GFC_MAX_DIMENSIONS
];
60 const GFC_UINTEGER_1
* restrict base
;
61 GFC_INTEGER_16
* restrict dest
;
69 /* Make dim zero based to avoid confusion. */
70 rank
= GFC_DESCRIPTOR_RANK (array
) - 1;
73 if (unlikely (dim
< 0 || dim
> rank
))
75 runtime_error ("Dim argument incorrect in MINLOC intrinsic: "
76 "is %ld, should be between 1 and %ld",
77 (long int) dim
+ 1, (long int) rank
+ 1);
80 len
= GFC_DESCRIPTOR_EXTENT(array
,dim
);
83 delta
= GFC_DESCRIPTOR_STRIDE(array
,dim
) * string_len
;
85 for (n
= 0; n
< dim
; n
++)
87 sstride
[n
] = GFC_DESCRIPTOR_STRIDE(array
,n
) * string_len
;
88 extent
[n
] = GFC_DESCRIPTOR_EXTENT(array
,n
);
93 for (n
= dim
; n
< rank
; n
++)
95 sstride
[n
] = GFC_DESCRIPTOR_STRIDE(array
, n
+ 1) * string_len
;
96 extent
[n
] = GFC_DESCRIPTOR_EXTENT(array
, n
+ 1);
102 if (retarray
->base_addr
== NULL
)
104 size_t alloc_size
, str
;
106 for (n
= 0; n
< rank
; n
++)
111 str
= GFC_DESCRIPTOR_STRIDE(retarray
,n
-1) * extent
[n
-1];
113 GFC_DIMENSION_SET(retarray
->dim
[n
], 0, extent
[n
] - 1, str
);
117 retarray
->offset
= 0;
118 retarray
->dtype
.rank
= rank
;
120 alloc_size
= GFC_DESCRIPTOR_STRIDE(retarray
,rank
-1) * extent
[rank
-1];
122 retarray
->base_addr
= xmallocarray (alloc_size
, sizeof (GFC_INTEGER_16
));
128 if (rank
!= GFC_DESCRIPTOR_RANK (retarray
))
129 runtime_error ("rank of return array incorrect in"
130 " MINLOC intrinsic: is %ld, should be %ld",
131 (long int) (GFC_DESCRIPTOR_RANK (retarray
)),
134 if (unlikely (compile_options
.bounds_check
))
135 bounds_ifunction_return ((array_t
*) retarray
, extent
,
136 "return value", "MINLOC");
139 for (n
= 0; n
< rank
; n
++)
142 dstride
[n
] = GFC_DESCRIPTOR_STRIDE(retarray
,n
);
147 base
= array
->base_addr
;
148 dest
= retarray
->base_addr
;
151 while (continue_loop
)
153 const GFC_UINTEGER_1
* restrict src
;
154 GFC_INTEGER_16 result
;
158 const GFC_UINTEGER_1
*minval
;
165 for (n
= 0; n
< len
; n
++, src
+= delta
)
168 if (minval
== NULL
|| (back
? compare_fcn (src
, minval
, string_len
) <= 0 :
169 compare_fcn (src
, minval
, string_len
) < 0))
172 result
= (GFC_INTEGER_16
)n
+ 1;
179 /* Advance to the next element. */
184 while (count
[n
] == extent
[n
])
186 /* When we get to the end of a dimension, reset it and increment
187 the next dimension. */
189 /* We could precalculate these products, but this is a less
190 frequently used path so probably not worth it. */
191 base
-= sstride
[n
] * extent
[n
];
192 dest
-= dstride
[n
] * extent
[n
];
196 /* Break out of the loop. */
211 extern void mminloc1_16_s1 (gfc_array_i16
* const restrict
,
212 gfc_array_s1
* const restrict
, const index_type
* const restrict
,
213 gfc_array_l1
* const restrict
, GFC_LOGICAL_4 back
, gfc_charlen_type
);
214 export_proto(mminloc1_16_s1
);
217 mminloc1_16_s1 (gfc_array_i16
* const restrict retarray
,
218 gfc_array_s1
* const restrict array
,
219 const index_type
* const restrict pdim
,
220 gfc_array_l1
* const restrict mask
, GFC_LOGICAL_4 back
,
221 gfc_charlen_type string_len
)
223 index_type count
[GFC_MAX_DIMENSIONS
];
224 index_type extent
[GFC_MAX_DIMENSIONS
];
225 index_type sstride
[GFC_MAX_DIMENSIONS
];
226 index_type dstride
[GFC_MAX_DIMENSIONS
];
227 index_type mstride
[GFC_MAX_DIMENSIONS
];
228 GFC_INTEGER_16
* restrict dest
;
229 const GFC_UINTEGER_1
* restrict base
;
230 const GFC_LOGICAL_1
* restrict mbase
;
242 minloc1_16_s1 (retarray
, array
, pdim
, back
, string_len
);
244 minloc1_16_s1 (retarray
, array
, pdim
, string_len
);
250 rank
= GFC_DESCRIPTOR_RANK (array
) - 1;
253 if (unlikely (dim
< 0 || dim
> rank
))
255 runtime_error ("Dim argument incorrect in MINLOC 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];
317 retarray
->offset
= 0;
318 retarray
->dtype
.rank
= rank
;
320 retarray
->base_addr
= xmallocarray (alloc_size
, sizeof (GFC_INTEGER_16
));
326 if (rank
!= GFC_DESCRIPTOR_RANK (retarray
))
327 runtime_error ("rank of return array incorrect in MINLOC intrinsic");
329 if (unlikely (compile_options
.bounds_check
))
331 bounds_ifunction_return ((array_t
*) retarray
, extent
,
332 "return value", "MINLOC");
333 bounds_equal_extents ((array_t
*) mask
, (array_t
*) array
,
334 "MASK argument", "MINLOC");
338 for (n
= 0; n
< rank
; n
++)
341 dstride
[n
] = GFC_DESCRIPTOR_STRIDE(retarray
,n
);
346 dest
= retarray
->base_addr
;
347 base
= array
->base_addr
;
351 const GFC_UINTEGER_1
* restrict src
;
352 const GFC_LOGICAL_1
* restrict msrc
;
353 GFC_INTEGER_16 result
;
358 const GFC_UINTEGER_1
*minval
;
361 for (n
= 0; n
< len
; n
++, src
+= delta
, msrc
+= mdelta
)
367 result
= (GFC_INTEGER_16
)n
+ 1;
371 for (; n
< len
; n
++, src
+= delta
, msrc
+= mdelta
)
373 if (*msrc
&& (back
? compare_fcn (src
, minval
, string_len
) <= 0 :
374 compare_fcn (src
, minval
, string_len
) < 0))
377 result
= (GFC_INTEGER_16
)n
+ 1;
383 /* Advance to the next element. */
389 while (count
[n
] == extent
[n
])
391 /* When we get to the end of a dimension, reset it and increment
392 the next dimension. */
394 /* We could precalculate these products, but this is a less
395 frequently used path so probably not worth it. */
396 base
-= sstride
[n
] * extent
[n
];
397 mbase
-= mstride
[n
] * extent
[n
];
398 dest
-= dstride
[n
] * extent
[n
];
402 /* Break out of the loop. */
418 extern void sminloc1_16_s1 (gfc_array_i16
* const restrict
,
419 gfc_array_s1
* const restrict
, const index_type
* const restrict
,
420 GFC_LOGICAL_4
*, GFC_LOGICAL_4 back
, gfc_charlen_type
);
421 export_proto(sminloc1_16_s1
);
424 sminloc1_16_s1 (gfc_array_i16
* const restrict retarray
,
425 gfc_array_s1
* const restrict array
,
426 const index_type
* const restrict pdim
,
427 GFC_LOGICAL_4
* mask
, GFC_LOGICAL_4 back
, gfc_charlen_type string_len
)
429 index_type count
[GFC_MAX_DIMENSIONS
];
430 index_type extent
[GFC_MAX_DIMENSIONS
];
431 index_type dstride
[GFC_MAX_DIMENSIONS
];
432 GFC_INTEGER_16
* restrict dest
;
438 if (mask
== NULL
|| *mask
)
441 minloc1_16_s1 (retarray
, array
, pdim
, back
, string_len
);
443 minloc1_16_s1 (retarray
, array
, pdim
, string_len
);
447 /* Make dim zero based to avoid confusion. */
449 rank
= GFC_DESCRIPTOR_RANK (array
) - 1;
451 if (unlikely (dim
< 0 || dim
> rank
))
453 runtime_error ("Dim argument incorrect in MINLOC intrinsic: "
454 "is %ld, should be between 1 and %ld",
455 (long int) dim
+ 1, (long int) rank
+ 1);
458 for (n
= 0; n
< dim
; n
++)
460 extent
[n
] = GFC_DESCRIPTOR_EXTENT(array
,n
) * string_len
;
466 for (n
= dim
; n
< rank
; n
++)
469 GFC_DESCRIPTOR_EXTENT(array
,n
+ 1) * string_len
;
475 if (retarray
->base_addr
== NULL
)
477 size_t alloc_size
, str
;
479 for (n
= 0; n
< rank
; n
++)
484 str
= GFC_DESCRIPTOR_STRIDE(retarray
,n
-1) * extent
[n
-1];
486 GFC_DIMENSION_SET(retarray
->dim
[n
], 0, extent
[n
] - 1, str
);
490 retarray
->offset
= 0;
491 retarray
->dtype
.rank
= rank
;
493 alloc_size
= GFC_DESCRIPTOR_STRIDE(retarray
,rank
-1) * extent
[rank
-1];
495 retarray
->base_addr
= xmallocarray (alloc_size
, sizeof (GFC_INTEGER_16
));
501 if (rank
!= GFC_DESCRIPTOR_RANK (retarray
))
502 runtime_error ("rank of return array incorrect in"
503 " MINLOC intrinsic: is %ld, should be %ld",
504 (long int) (GFC_DESCRIPTOR_RANK (retarray
)),
507 if (unlikely (compile_options
.bounds_check
))
509 for (n
=0; n
< rank
; n
++)
511 index_type ret_extent
;
513 ret_extent
= GFC_DESCRIPTOR_EXTENT(retarray
,n
);
514 if (extent
[n
] != ret_extent
)
515 runtime_error ("Incorrect extent in return value of"
516 " MINLOC intrinsic in dimension %ld:"
517 " is %ld, should be %ld", (long int) n
+ 1,
518 (long int) ret_extent
, (long int) extent
[n
]);
523 for (n
= 0; n
< rank
; n
++)
526 dstride
[n
] = GFC_DESCRIPTOR_STRIDE(retarray
,n
);
529 dest
= retarray
->base_addr
;
537 while (count
[n
] == extent
[n
])
539 /* When we get to the end of a dimension, reset it and increment
540 the next dimension. */
542 /* We could precalculate these products, but this is a less
543 frequently used path so probably not worth it. */
544 dest
-= dstride
[n
] * extent
[n
];