1 /* Implementation of the MINLOC 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"
33 #if defined (HAVE_GFC_INTEGER_4) && defined (HAVE_GFC_INTEGER_4)
36 compare_fcn (const GFC_INTEGER_4
*a
, const GFC_INTEGER_4
*b
, gfc_charlen_type n
)
38 if (sizeof (GFC_INTEGER_4
) == 1)
39 return memcmp (a
, b
, n
);
41 return memcmp_char4 (a
, b
, n
);
45 extern void minloc0_4_s4 (gfc_array_i4
* const restrict retarray
,
46 gfc_array_s4
* const restrict array
, gfc_charlen_type len
);
47 export_proto(minloc0_4_s4
);
50 minloc0_4_s4 (gfc_array_i4
* const restrict retarray
,
51 gfc_array_s4
* const restrict array
, gfc_charlen_type len
)
53 index_type count
[GFC_MAX_DIMENSIONS
];
54 index_type extent
[GFC_MAX_DIMENSIONS
];
55 index_type sstride
[GFC_MAX_DIMENSIONS
];
57 const GFC_INTEGER_4
*base
;
58 GFC_INTEGER_4
* restrict dest
;
62 rank
= GFC_DESCRIPTOR_RANK (array
);
64 runtime_error ("Rank of array needs to be > 0");
66 if (retarray
->base_addr
== NULL
)
68 GFC_DIMENSION_SET(retarray
->dim
[0], 0, rank
-1, 1);
69 retarray
->dtype
= (retarray
->dtype
& ~GFC_DTYPE_RANK_MASK
) | 1;
71 retarray
->base_addr
= xmallocarray (rank
, sizeof (GFC_INTEGER_4
));
75 if (unlikely (compile_options
.bounds_check
))
76 bounds_iforeach_return ((array_t
*) retarray
, (array_t
*) array
,
80 dstride
= GFC_DESCRIPTOR_STRIDE(retarray
,0);
81 dest
= retarray
->base_addr
;
82 for (n
= 0; n
< rank
; n
++)
84 sstride
[n
] = GFC_DESCRIPTOR_STRIDE(array
,n
) * len
;
85 extent
[n
] = GFC_DESCRIPTOR_EXTENT(array
,n
);
89 /* Set the return value. */
90 for (n
= 0; n
< rank
; n
++)
91 dest
[n
* dstride
] = 0;
96 base
= array
->base_addr
;
98 /* Initialize the return value. */
99 for (n
= 0; n
< rank
; n
++)
100 dest
[n
* dstride
] = 1;
103 const GFC_INTEGER_4
*minval
;
110 /* Implementation start. */
112 if (compare_fcn (base
, minval
, len
) < 0)
115 for (n
= 0; n
< rank
; n
++)
116 dest
[n
* dstride
] = count
[n
] + 1;
118 /* Implementation end. */
119 /* Advance to the next element. */
122 while (++count
[0] != extent
[0]);
126 /* When we get to the end of a dimension, reset it and increment
127 the next dimension. */
129 /* We could precalculate these products, but this is a less
130 frequently used path so probably not worth it. */
131 base
-= sstride
[n
] * extent
[n
];
135 /* Break out of the loop. */
145 while (count
[n
] == extent
[n
]);
151 extern void mminloc0_4_s4 (gfc_array_i4
* const restrict
,
152 gfc_array_s4
* const restrict
, gfc_array_l1
* const restrict
, gfc_charlen_type len
);
153 export_proto(mminloc0_4_s4
);
156 mminloc0_4_s4 (gfc_array_i4
* const restrict retarray
,
157 gfc_array_s4
* const restrict array
,
158 gfc_array_l1
* const restrict mask
, gfc_charlen_type len
)
160 index_type count
[GFC_MAX_DIMENSIONS
];
161 index_type extent
[GFC_MAX_DIMENSIONS
];
162 index_type sstride
[GFC_MAX_DIMENSIONS
];
163 index_type mstride
[GFC_MAX_DIMENSIONS
];
166 const GFC_INTEGER_4
*base
;
167 GFC_LOGICAL_1
*mbase
;
172 rank
= GFC_DESCRIPTOR_RANK (array
);
174 runtime_error ("Rank of array needs to be > 0");
176 if (retarray
->base_addr
== NULL
)
178 GFC_DIMENSION_SET(retarray
->dim
[0], 0, rank
- 1, 1);
179 retarray
->dtype
= (retarray
->dtype
& ~GFC_DTYPE_RANK_MASK
) | 1;
180 retarray
->offset
= 0;
181 retarray
->base_addr
= xmallocarray (rank
, sizeof (GFC_INTEGER_4
));
185 if (unlikely (compile_options
.bounds_check
))
188 bounds_iforeach_return ((array_t
*) retarray
, (array_t
*) array
,
190 bounds_equal_extents ((array_t
*) mask
, (array_t
*) array
,
191 "MASK argument", "MINLOC");
195 mask_kind
= GFC_DESCRIPTOR_SIZE (mask
);
197 mbase
= mask
->base_addr
;
199 if (mask_kind
== 1 || mask_kind
== 2 || mask_kind
== 4 || mask_kind
== 8
200 #ifdef HAVE_GFC_LOGICAL_16
204 mbase
= GFOR_POINTER_TO_L1 (mbase
, mask_kind
);
206 runtime_error ("Funny sized logical array");
208 dstride
= GFC_DESCRIPTOR_STRIDE(retarray
,0);
209 dest
= retarray
->base_addr
;
210 for (n
= 0; n
< rank
; n
++)
212 sstride
[n
] = GFC_DESCRIPTOR_STRIDE(array
,n
) * len
;
213 mstride
[n
] = GFC_DESCRIPTOR_STRIDE_BYTES(mask
,n
);
214 extent
[n
] = GFC_DESCRIPTOR_EXTENT(array
,n
);
218 /* Set the return value. */
219 for (n
= 0; n
< rank
; n
++)
220 dest
[n
* dstride
] = 0;
225 base
= array
->base_addr
;
227 /* Initialize the return value. */
228 for (n
= 0; n
< rank
; n
++)
229 dest
[n
* dstride
] = 0;
232 const GFC_INTEGER_4
*minval
;
240 /* Implementation start. */
242 if (*mbase
&& (minval
== NULL
|| compare_fcn (base
, minval
, len
) < 0))
245 for (n
= 0; n
< rank
; n
++)
246 dest
[n
* dstride
] = count
[n
] + 1;
248 /* Implementation end. */
249 /* Advance to the next element. */
253 while (++count
[0] != extent
[0]);
257 /* When we get to the end of a dimension, reset it and increment
258 the next dimension. */
260 /* We could precalculate these products, but this is a less
261 frequently used path so probably not worth it. */
262 base
-= sstride
[n
] * extent
[n
];
263 mbase
-= mstride
[n
] * extent
[n
];
267 /* Break out of the loop. */
278 while (count
[n
] == extent
[n
]);
284 extern void sminloc0_4_s4 (gfc_array_i4
* const restrict
,
285 gfc_array_s4
* const restrict
, GFC_LOGICAL_4
*, gfc_charlen_type len
);
286 export_proto(sminloc0_4_s4
);
289 sminloc0_4_s4 (gfc_array_i4
* const restrict retarray
,
290 gfc_array_s4
* const restrict array
,
291 GFC_LOGICAL_4
* mask
, gfc_charlen_type len
)
300 minloc0_4_s4 (retarray
, array
, len
);
304 rank
= GFC_DESCRIPTOR_RANK (array
);
307 runtime_error ("Rank of array needs to be > 0");
309 if (retarray
->base_addr
== NULL
)
311 GFC_DIMENSION_SET(retarray
->dim
[0], 0, rank
-1, 1);
312 retarray
->dtype
= (retarray
->dtype
& ~GFC_DTYPE_RANK_MASK
) | 1;
313 retarray
->offset
= 0;
314 retarray
->base_addr
= xmallocarray (rank
, sizeof (GFC_INTEGER_4
));
316 else if (unlikely (compile_options
.bounds_check
))
318 bounds_iforeach_return ((array_t
*) retarray
, (array_t
*) array
,
322 dstride
= GFC_DESCRIPTOR_STRIDE(retarray
,0);
323 dest
= retarray
->base_addr
;
324 for (n
= 0; n
<rank
; n
++)
325 dest
[n
* dstride
] = 0 ;