1 /* Implementation of the MAXLOC intrinsic
2 Copyright (C) 2002-2018 Free Software Foundation, Inc.
3 Contributed by Paul Brook <paul@nowt.org>
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"
30 #if defined (HAVE_GFC_REAL_4) && defined (HAVE_GFC_INTEGER_4)
32 #define HAVE_BACK_ARG 1
35 extern void maxloc1_4_r4 (gfc_array_i4
* const restrict
,
36 gfc_array_r4
* const restrict
, const index_type
* const restrict
, GFC_LOGICAL_4 back
);
37 export_proto(maxloc1_4_r4
);
40 maxloc1_4_r4 (gfc_array_i4
* const restrict retarray
,
41 gfc_array_r4
* const restrict array
,
42 const index_type
* const restrict pdim
, GFC_LOGICAL_4 back
)
44 index_type count
[GFC_MAX_DIMENSIONS
];
45 index_type extent
[GFC_MAX_DIMENSIONS
];
46 index_type sstride
[GFC_MAX_DIMENSIONS
];
47 index_type dstride
[GFC_MAX_DIMENSIONS
];
48 const GFC_REAL_4
* restrict base
;
49 GFC_INTEGER_4
* restrict dest
;
57 /* Make dim zero based to avoid confusion. */
58 rank
= GFC_DESCRIPTOR_RANK (array
) - 1;
61 if (unlikely (dim
< 0 || dim
> rank
))
63 runtime_error ("Dim argument incorrect in MAXLOC intrinsic: "
64 "is %ld, should be between 1 and %ld",
65 (long int) dim
+ 1, (long int) rank
+ 1);
68 len
= GFC_DESCRIPTOR_EXTENT(array
,dim
);
71 delta
= GFC_DESCRIPTOR_STRIDE(array
,dim
);
73 for (n
= 0; n
< dim
; n
++)
75 sstride
[n
] = GFC_DESCRIPTOR_STRIDE(array
,n
);
76 extent
[n
] = GFC_DESCRIPTOR_EXTENT(array
,n
);
81 for (n
= dim
; n
< rank
; n
++)
83 sstride
[n
] = GFC_DESCRIPTOR_STRIDE(array
, n
+ 1);
84 extent
[n
] = GFC_DESCRIPTOR_EXTENT(array
, n
+ 1);
90 if (retarray
->base_addr
== NULL
)
92 size_t alloc_size
, str
;
94 for (n
= 0; n
< rank
; n
++)
99 str
= GFC_DESCRIPTOR_STRIDE(retarray
,n
-1) * extent
[n
-1];
101 GFC_DIMENSION_SET(retarray
->dim
[n
], 0, extent
[n
] - 1, str
);
105 retarray
->offset
= 0;
106 GFC_DTYPE_COPY_SETRANK(retarray
,array
,rank
);
108 alloc_size
= GFC_DESCRIPTOR_STRIDE(retarray
,rank
-1) * extent
[rank
-1];
110 retarray
->base_addr
= xmallocarray (alloc_size
, sizeof (GFC_INTEGER_4
));
113 /* Make sure we have a zero-sized array. */
114 GFC_DIMENSION_SET(retarray
->dim
[0], 0, -1, 1);
121 if (rank
!= GFC_DESCRIPTOR_RANK (retarray
))
122 runtime_error ("rank of return array incorrect in"
123 " MAXLOC intrinsic: is %ld, should be %ld",
124 (long int) (GFC_DESCRIPTOR_RANK (retarray
)),
127 if (unlikely (compile_options
.bounds_check
))
128 bounds_ifunction_return ((array_t
*) retarray
, extent
,
129 "return value", "MAXLOC");
132 for (n
= 0; n
< rank
; n
++)
135 dstride
[n
] = GFC_DESCRIPTOR_STRIDE(retarray
,n
);
140 base
= array
->base_addr
;
141 dest
= retarray
->base_addr
;
144 while (continue_loop
)
146 const GFC_REAL_4
* restrict src
;
147 GFC_INTEGER_4 result
;
152 #if defined (GFC_REAL_4_INFINITY)
153 maxval
= -GFC_REAL_4_INFINITY
;
155 maxval
= -GFC_REAL_4_HUGE
;
162 #if ! defined HAVE_BACK_ARG
163 for (n
= 0; n
< len
; n
++, src
+= delta
)
167 #if defined (GFC_REAL_4_QUIET_NAN)
168 for (n
= 0; n
< len
; n
++, src
+= delta
)
173 result
= (GFC_INTEGER_4
)n
+ 1;
180 for (; n
< len
; n
++, src
+= delta
)
182 if (back
? *src
>= maxval
: *src
> maxval
)
185 result
= (GFC_INTEGER_4
)n
+ 1;
192 /* Advance to the next element. */
197 while (count
[n
] == extent
[n
])
199 /* When we get to the end of a dimension, reset it and increment
200 the next dimension. */
202 /* We could precalculate these products, but this is a less
203 frequently used path so probably not worth it. */
204 base
-= sstride
[n
] * extent
[n
];
205 dest
-= dstride
[n
] * extent
[n
];
209 /* Break out of the loop. */
224 extern void mmaxloc1_4_r4 (gfc_array_i4
* const restrict
,
225 gfc_array_r4
* const restrict
, const index_type
* const restrict
,
226 gfc_array_l1
* const restrict
, GFC_LOGICAL_4 back
);
227 export_proto(mmaxloc1_4_r4
);
230 mmaxloc1_4_r4 (gfc_array_i4
* const restrict retarray
,
231 gfc_array_r4
* const restrict array
,
232 const index_type
* const restrict pdim
,
233 gfc_array_l1
* const restrict mask
, GFC_LOGICAL_4 back
)
235 index_type count
[GFC_MAX_DIMENSIONS
];
236 index_type extent
[GFC_MAX_DIMENSIONS
];
237 index_type sstride
[GFC_MAX_DIMENSIONS
];
238 index_type dstride
[GFC_MAX_DIMENSIONS
];
239 index_type mstride
[GFC_MAX_DIMENSIONS
];
240 GFC_INTEGER_4
* restrict dest
;
241 const GFC_REAL_4
* restrict base
;
242 const GFC_LOGICAL_1
* restrict mbase
;
252 rank
= GFC_DESCRIPTOR_RANK (array
) - 1;
255 if (unlikely (dim
< 0 || dim
> rank
))
257 runtime_error ("Dim argument incorrect in MAXLOC intrinsic: "
258 "is %ld, should be between 1 and %ld",
259 (long int) dim
+ 1, (long int) rank
+ 1);
262 len
= GFC_DESCRIPTOR_EXTENT(array
,dim
);
266 mbase
= mask
->base_addr
;
268 mask_kind
= GFC_DESCRIPTOR_SIZE (mask
);
270 if (mask_kind
== 1 || mask_kind
== 2 || mask_kind
== 4 || mask_kind
== 8
271 #ifdef HAVE_GFC_LOGICAL_16
275 mbase
= GFOR_POINTER_TO_L1 (mbase
, mask_kind
);
277 runtime_error ("Funny sized logical array");
279 delta
= GFC_DESCRIPTOR_STRIDE(array
,dim
);
280 mdelta
= GFC_DESCRIPTOR_STRIDE_BYTES(mask
,dim
);
282 for (n
= 0; n
< dim
; n
++)
284 sstride
[n
] = GFC_DESCRIPTOR_STRIDE(array
,n
);
285 mstride
[n
] = GFC_DESCRIPTOR_STRIDE_BYTES(mask
,n
);
286 extent
[n
] = GFC_DESCRIPTOR_EXTENT(array
,n
);
292 for (n
= dim
; n
< rank
; n
++)
294 sstride
[n
] = GFC_DESCRIPTOR_STRIDE(array
,n
+ 1);
295 mstride
[n
] = GFC_DESCRIPTOR_STRIDE_BYTES(mask
, n
+ 1);
296 extent
[n
] = GFC_DESCRIPTOR_EXTENT(array
, n
+ 1);
302 if (retarray
->base_addr
== NULL
)
304 size_t alloc_size
, str
;
306 for (n
= 0; n
< rank
; n
++)
311 str
= GFC_DESCRIPTOR_STRIDE(retarray
,n
-1) * extent
[n
-1];
313 GFC_DIMENSION_SET(retarray
->dim
[n
], 0, extent
[n
] - 1, str
);
317 alloc_size
= GFC_DESCRIPTOR_STRIDE(retarray
,rank
-1) * extent
[rank
-1];
319 retarray
->offset
= 0;
320 GFC_DTYPE_COPY_SETRANK(retarray
,array
,rank
);
324 /* Make sure we have a zero-sized array. */
325 GFC_DIMENSION_SET(retarray
->dim
[0], 0, -1, 1);
329 retarray
->base_addr
= xmallocarray (alloc_size
, sizeof (GFC_INTEGER_4
));
334 if (rank
!= GFC_DESCRIPTOR_RANK (retarray
))
335 runtime_error ("rank of return array incorrect in MAXLOC intrinsic");
337 if (unlikely (compile_options
.bounds_check
))
339 bounds_ifunction_return ((array_t
*) retarray
, extent
,
340 "return value", "MAXLOC");
341 bounds_equal_extents ((array_t
*) mask
, (array_t
*) array
,
342 "MASK argument", "MAXLOC");
346 for (n
= 0; n
< rank
; n
++)
349 dstride
[n
] = GFC_DESCRIPTOR_STRIDE(retarray
,n
);
354 dest
= retarray
->base_addr
;
355 base
= array
->base_addr
;
359 const GFC_REAL_4
* restrict src
;
360 const GFC_LOGICAL_1
* restrict msrc
;
361 GFC_INTEGER_4 result
;
367 #if defined (GFC_REAL_4_INFINITY)
368 maxval
= -GFC_REAL_4_INFINITY
;
370 maxval
= -GFC_REAL_4_HUGE
;
372 #if defined (GFC_REAL_4_QUIET_NAN)
373 GFC_INTEGER_4 result2
= 0;
376 for (n
= 0; n
< len
; n
++, src
+= delta
, msrc
+= mdelta
)
381 #if defined (GFC_REAL_4_QUIET_NAN)
383 result2
= (GFC_INTEGER_4
)n
+ 1;
388 result
= (GFC_INTEGER_4
)n
+ 1;
393 #if defined (GFC_REAL_4_QUIET_NAN)
394 if (unlikely (n
>= len
))
399 for (; n
< len
; n
++, src
+= delta
, msrc
+= mdelta
)
401 if (*msrc
&& unlikely (*src
>= maxval
))
404 result
= (GFC_INTEGER_4
)n
+ 1;
408 for (; n
< len
; n
++, src
+= delta
, msrc
+= mdelta
)
410 if (*msrc
&& unlikely (*src
> maxval
))
413 result
= (GFC_INTEGER_4
)n
+ 1;
418 /* Advance to the next element. */
424 while (count
[n
] == extent
[n
])
426 /* When we get to the end of a dimension, reset it and increment
427 the next dimension. */
429 /* We could precalculate these products, but this is a less
430 frequently used path so probably not worth it. */
431 base
-= sstride
[n
] * extent
[n
];
432 mbase
-= mstride
[n
] * extent
[n
];
433 dest
-= dstride
[n
] * extent
[n
];
437 /* Break out of the loop. */
453 extern void smaxloc1_4_r4 (gfc_array_i4
* const restrict
,
454 gfc_array_r4
* const restrict
, const index_type
* const restrict
,
455 GFC_LOGICAL_4
*, GFC_LOGICAL_4 back
);
456 export_proto(smaxloc1_4_r4
);
459 smaxloc1_4_r4 (gfc_array_i4
* const restrict retarray
,
460 gfc_array_r4
* const restrict array
,
461 const index_type
* const restrict pdim
,
462 GFC_LOGICAL_4
* mask
, GFC_LOGICAL_4 back
)
464 index_type count
[GFC_MAX_DIMENSIONS
];
465 index_type extent
[GFC_MAX_DIMENSIONS
];
466 index_type dstride
[GFC_MAX_DIMENSIONS
];
467 GFC_INTEGER_4
* restrict dest
;
476 maxloc1_4_r4 (retarray
, array
, pdim
, back
);
478 maxloc1_4_r4 (retarray
, array
, pdim
);
482 /* Make dim zero based to avoid confusion. */
484 rank
= GFC_DESCRIPTOR_RANK (array
) - 1;
486 if (unlikely (dim
< 0 || dim
> rank
))
488 runtime_error ("Dim argument incorrect in MAXLOC intrinsic: "
489 "is %ld, should be between 1 and %ld",
490 (long int) dim
+ 1, (long int) rank
+ 1);
493 for (n
= 0; n
< dim
; n
++)
495 extent
[n
] = GFC_DESCRIPTOR_EXTENT(array
,n
);
501 for (n
= dim
; n
< rank
; n
++)
504 GFC_DESCRIPTOR_EXTENT(array
,n
+ 1);
510 if (retarray
->base_addr
== NULL
)
512 size_t alloc_size
, str
;
514 for (n
= 0; n
< rank
; n
++)
519 str
= GFC_DESCRIPTOR_STRIDE(retarray
,n
-1) * extent
[n
-1];
521 GFC_DIMENSION_SET(retarray
->dim
[n
], 0, extent
[n
] - 1, str
);
525 retarray
->offset
= 0;
526 GFC_DTYPE_COPY_SETRANK(retarray
,array
,rank
);
528 alloc_size
= GFC_DESCRIPTOR_STRIDE(retarray
,rank
-1) * extent
[rank
-1];
532 /* Make sure we have a zero-sized array. */
533 GFC_DIMENSION_SET(retarray
->dim
[0], 0, -1, 1);
537 retarray
->base_addr
= xmallocarray (alloc_size
, sizeof (GFC_INTEGER_4
));
541 if (rank
!= GFC_DESCRIPTOR_RANK (retarray
))
542 runtime_error ("rank of return array incorrect in"
543 " MAXLOC intrinsic: is %ld, should be %ld",
544 (long int) (GFC_DESCRIPTOR_RANK (retarray
)),
547 if (unlikely (compile_options
.bounds_check
))
549 for (n
=0; n
< rank
; n
++)
551 index_type ret_extent
;
553 ret_extent
= GFC_DESCRIPTOR_EXTENT(retarray
,n
);
554 if (extent
[n
] != ret_extent
)
555 runtime_error ("Incorrect extent in return value of"
556 " MAXLOC intrinsic in dimension %ld:"
557 " is %ld, should be %ld", (long int) n
+ 1,
558 (long int) ret_extent
, (long int) extent
[n
]);
563 for (n
= 0; n
< rank
; n
++)
566 dstride
[n
] = GFC_DESCRIPTOR_STRIDE(retarray
,n
);
569 dest
= retarray
->base_addr
;
577 while (count
[n
] == extent
[n
])
579 /* When we get to the end of a dimension, reset it and increment
580 the next dimension. */
582 /* We could precalculate these products, but this is a less
583 frequently used path so probably not worth it. */
584 dest
-= dstride
[n
] * extent
[n
];