1 //===-- runtime/extrema.cpp -----------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // Implements MAXLOC, MINLOC, MAXVAL, & MINVAL for all required operand types
10 // and shapes and (for MAXLOC & MINLOC) result integer kinds. Also implements
11 // NORM2 using common infrastructure.
13 #include "reduction-templates.h"
14 #include "flang/Common/float128.h"
15 #include "flang/Runtime/character.h"
16 #include "flang/Runtime/reduction.h"
21 #include <type_traits>
23 namespace Fortran::runtime
{
27 template <typename T
, bool IS_MAX
, bool BACK
> struct NumericCompare
{
29 explicit RT_API_ATTRS
NumericCompare(std::size_t /*elemLen; ignored*/) {}
30 RT_API_ATTRS
bool operator()(const T
&value
, const T
&previous
) const {
31 if (std::is_floating_point_v
<T
> && previous
!= previous
) {
32 return BACK
|| value
== value
; // replace NaN
33 } else if (value
== previous
) {
35 } else if constexpr (IS_MAX
) {
36 return value
> previous
;
38 return value
< previous
;
43 template <typename T
, bool IS_MAX
, bool BACK
> class CharacterCompare
{
46 explicit RT_API_ATTRS
CharacterCompare(std::size_t elemLen
)
47 : chars_
{elemLen
/ sizeof(T
)} {}
48 RT_API_ATTRS
bool operator()(const T
&value
, const T
&previous
) const {
49 int cmp
{CharacterScalarCompare
<T
>(&value
, &previous
, chars_
, chars_
)};
52 } else if constexpr (IS_MAX
) {
63 template <typename COMPARE
> class ExtremumLocAccumulator
{
65 using Type
= typename
COMPARE::Type
;
66 RT_API_ATTRS
ExtremumLocAccumulator(const Descriptor
&array
)
67 : array_
{array
}, argRank_
{array
.rank()}, compare_
{array
.ElementBytes()} {
70 RT_API_ATTRS
void Reinitialize() {
71 // per standard: result indices are all zero if no data
72 for (int j
{0}; j
< argRank_
; ++j
) {
77 RT_API_ATTRS
int argRank() const { return argRank_
; }
79 RT_API_ATTRS
void GetResult(A
*p
, int zeroBasedDim
= -1) {
80 if (zeroBasedDim
>= 0) {
81 *p
= extremumLoc_
[zeroBasedDim
];
83 for (int j
{0}; j
< argRank_
; ++j
) {
84 p
[j
] = extremumLoc_
[j
];
88 template <typename IGNORED
>
89 RT_API_ATTRS
bool AccumulateAt(const SubscriptValue at
[]) {
90 const auto &value
{*array_
.Element
<Type
>(at
)};
91 if (!previous_
|| compare_(value
, *previous_
)) {
93 for (int j
{0}; j
< argRank_
; ++j
) {
94 extremumLoc_
[j
] = at
[j
] - array_
.GetDimension(j
).LowerBound() + 1;
101 const Descriptor
&array_
;
103 SubscriptValue extremumLoc_
[maxRank
];
104 const Type
*previous_
{nullptr};
108 template <typename ACCUMULATOR
, typename CPPTYPE
>
109 static RT_API_ATTRS
void LocationHelper(const char *intrinsic
,
110 Descriptor
&result
, const Descriptor
&x
, int kind
, const Descriptor
*mask
,
111 Terminator
&terminator
) {
112 ACCUMULATOR accumulator
{x
};
113 DoTotalReduction
<CPPTYPE
>(x
, 0, mask
, accumulator
, intrinsic
, terminator
);
114 ApplyIntegerKind
<LocationResultHelper
<ACCUMULATOR
>::template Functor
, void>(
115 kind
, terminator
, accumulator
, result
);
118 template <TypeCategory CAT
, int KIND
, bool IS_MAX
,
119 template <typename
, bool, bool> class COMPARE
>
120 inline RT_API_ATTRS
void DoMaxOrMinLoc(const char *intrinsic
,
121 Descriptor
&result
, const Descriptor
&x
, int kind
, const char *source
,
122 int line
, const Descriptor
*mask
, bool back
) {
123 using CppType
= CppTypeFor
<CAT
, KIND
>;
124 Terminator terminator
{source
, line
};
126 LocationHelper
<ExtremumLocAccumulator
<COMPARE
<CppType
, IS_MAX
, true>>,
127 CppType
>(intrinsic
, result
, x
, kind
, mask
, terminator
);
129 LocationHelper
<ExtremumLocAccumulator
<COMPARE
<CppType
, IS_MAX
, false>>,
130 CppType
>(intrinsic
, result
, x
, kind
, mask
, terminator
);
134 template <bool IS_MAX
> struct CharacterMaxOrMinLocHelper
{
135 template <int KIND
> struct Functor
{
136 RT_API_ATTRS
void operator()(const char *intrinsic
, Descriptor
&result
,
137 const Descriptor
&x
, int kind
, const char *source
, int line
,
138 const Descriptor
*mask
, bool back
) const {
139 DoMaxOrMinLoc
<TypeCategory::Character
, KIND
, IS_MAX
, CharacterCompare
>(
140 intrinsic
, result
, x
, kind
, source
, line
, mask
, back
);
145 template <bool IS_MAX
>
146 inline RT_API_ATTRS
void CharacterMaxOrMinLoc(const char *intrinsic
,
147 Descriptor
&result
, const Descriptor
&x
, int kind
, const char *source
,
148 int line
, const Descriptor
*mask
, bool back
) {
150 SubscriptValue extent
[1]{rank
};
151 result
.Establish(TypeCategory::Integer
, kind
, nullptr, 1, extent
,
152 CFI_attribute_allocatable
);
153 result
.GetDimension(0).SetBounds(1, extent
[0]);
154 Terminator terminator
{source
, line
};
155 if (int stat
{result
.Allocate()}) {
157 "%s: could not allocate memory for result; STAT=%d", intrinsic
, stat
);
159 CheckIntegerKind(terminator
, kind
, intrinsic
);
160 auto catKind
{x
.type().GetCategoryAndKind()};
161 RUNTIME_CHECK(terminator
, catKind
.has_value());
162 switch (catKind
->first
) {
163 case TypeCategory::Character
:
164 ApplyCharacterKind
<CharacterMaxOrMinLocHelper
<IS_MAX
>::template Functor
,
165 void>(catKind
->second
, terminator
, intrinsic
, result
, x
, kind
, source
,
170 "%s: bad data type code (%d) for array", intrinsic
, x
.type().raw());
174 template <TypeCategory CAT
, int KIND
, bool IS_MAXVAL
>
175 inline RT_API_ATTRS
void TotalNumericMaxOrMinLoc(const char *intrinsic
,
176 Descriptor
&result
, const Descriptor
&x
, int kind
, const char *source
,
177 int line
, const Descriptor
*mask
, bool back
) {
179 SubscriptValue extent
[1]{rank
};
180 result
.Establish(TypeCategory::Integer
, kind
, nullptr, 1, extent
,
181 CFI_attribute_allocatable
);
182 result
.GetDimension(0).SetBounds(1, extent
[0]);
183 Terminator terminator
{source
, line
};
184 if (int stat
{result
.Allocate()}) {
186 "%s: could not allocate memory for result; STAT=%d", intrinsic
, stat
);
188 CheckIntegerKind(terminator
, kind
, intrinsic
);
189 RUNTIME_CHECK(terminator
, TypeCode(CAT
, KIND
) == x
.type());
190 DoMaxOrMinLoc
<CAT
, KIND
, IS_MAXVAL
, NumericCompare
>(
191 intrinsic
, result
, x
, kind
, source
, line
, mask
, back
);
195 RT_EXT_API_GROUP_BEGIN
197 void RTDEF(MaxlocCharacter
)(Descriptor
&result
, const Descriptor
&x
, int kind
,
198 const char *source
, int line
, const Descriptor
*mask
, bool back
) {
199 CharacterMaxOrMinLoc
<true>(
200 "MAXLOC", result
, x
, kind
, source
, line
, mask
, back
);
202 void RTDEF(MaxlocInteger1
)(Descriptor
&result
, const Descriptor
&x
, int kind
,
203 const char *source
, int line
, const Descriptor
*mask
, bool back
) {
204 TotalNumericMaxOrMinLoc
<TypeCategory::Integer
, 1, true>(
205 "MAXLOC", result
, x
, kind
, source
, line
, mask
, back
);
207 void RTDEF(MaxlocInteger2
)(Descriptor
&result
, const Descriptor
&x
, int kind
,
208 const char *source
, int line
, const Descriptor
*mask
, bool back
) {
209 TotalNumericMaxOrMinLoc
<TypeCategory::Integer
, 2, true>(
210 "MAXLOC", result
, x
, kind
, source
, line
, mask
, back
);
212 void RTDEF(MaxlocInteger4
)(Descriptor
&result
, const Descriptor
&x
, int kind
,
213 const char *source
, int line
, const Descriptor
*mask
, bool back
) {
214 TotalNumericMaxOrMinLoc
<TypeCategory::Integer
, 4, true>(
215 "MAXLOC", result
, x
, kind
, source
, line
, mask
, back
);
217 void RTDEF(MaxlocInteger8
)(Descriptor
&result
, const Descriptor
&x
, int kind
,
218 const char *source
, int line
, const Descriptor
*mask
, bool back
) {
219 TotalNumericMaxOrMinLoc
<TypeCategory::Integer
, 8, true>(
220 "MAXLOC", result
, x
, kind
, source
, line
, mask
, back
);
222 #ifdef __SIZEOF_INT128__
223 void RTDEF(MaxlocInteger16
)(Descriptor
&result
, const Descriptor
&x
, int kind
,
224 const char *source
, int line
, const Descriptor
*mask
, bool back
) {
225 TotalNumericMaxOrMinLoc
<TypeCategory::Integer
, 16, true>(
226 "MAXLOC", result
, x
, kind
, source
, line
, mask
, back
);
229 void RTDEF(MaxlocReal4
)(Descriptor
&result
, const Descriptor
&x
, int kind
,
230 const char *source
, int line
, const Descriptor
*mask
, bool back
) {
231 TotalNumericMaxOrMinLoc
<TypeCategory::Real
, 4, true>(
232 "MAXLOC", result
, x
, kind
, source
, line
, mask
, back
);
234 void RTDEF(MaxlocReal8
)(Descriptor
&result
, const Descriptor
&x
, int kind
,
235 const char *source
, int line
, const Descriptor
*mask
, bool back
) {
236 TotalNumericMaxOrMinLoc
<TypeCategory::Real
, 8, true>(
237 "MAXLOC", result
, x
, kind
, source
, line
, mask
, back
);
240 void RTDEF(MaxlocReal10
)(Descriptor
&result
, const Descriptor
&x
, int kind
,
241 const char *source
, int line
, const Descriptor
*mask
, bool back
) {
242 TotalNumericMaxOrMinLoc
<TypeCategory::Real
, 10, true>(
243 "MAXLOC", result
, x
, kind
, source
, line
, mask
, back
);
246 #if HAS_LDBL128 || HAS_FLOAT128
247 void RTDEF(MaxlocReal16
)(Descriptor
&result
, const Descriptor
&x
, int kind
,
248 const char *source
, int line
, const Descriptor
*mask
, bool back
) {
249 TotalNumericMaxOrMinLoc
<TypeCategory::Real
, 16, true>(
250 "MAXLOC", result
, x
, kind
, source
, line
, mask
, back
);
253 void RTDEF(MinlocCharacter
)(Descriptor
&result
, const Descriptor
&x
, int kind
,
254 const char *source
, int line
, const Descriptor
*mask
, bool back
) {
255 CharacterMaxOrMinLoc
<false>(
256 "MINLOC", result
, x
, kind
, source
, line
, mask
, back
);
258 void RTDEF(MinlocInteger1
)(Descriptor
&result
, const Descriptor
&x
, int kind
,
259 const char *source
, int line
, const Descriptor
*mask
, bool back
) {
260 TotalNumericMaxOrMinLoc
<TypeCategory::Integer
, 1, false>(
261 "MINLOC", result
, x
, kind
, source
, line
, mask
, back
);
263 void RTDEF(MinlocInteger2
)(Descriptor
&result
, const Descriptor
&x
, int kind
,
264 const char *source
, int line
, const Descriptor
*mask
, bool back
) {
265 TotalNumericMaxOrMinLoc
<TypeCategory::Integer
, 2, false>(
266 "MINLOC", result
, x
, kind
, source
, line
, mask
, back
);
268 void RTDEF(MinlocInteger4
)(Descriptor
&result
, const Descriptor
&x
, int kind
,
269 const char *source
, int line
, const Descriptor
*mask
, bool back
) {
270 TotalNumericMaxOrMinLoc
<TypeCategory::Integer
, 4, false>(
271 "MINLOC", result
, x
, kind
, source
, line
, mask
, back
);
273 void RTDEF(MinlocInteger8
)(Descriptor
&result
, const Descriptor
&x
, int kind
,
274 const char *source
, int line
, const Descriptor
*mask
, bool back
) {
275 TotalNumericMaxOrMinLoc
<TypeCategory::Integer
, 8, false>(
276 "MINLOC", result
, x
, kind
, source
, line
, mask
, back
);
278 #ifdef __SIZEOF_INT128__
279 void RTDEF(MinlocInteger16
)(Descriptor
&result
, const Descriptor
&x
, int kind
,
280 const char *source
, int line
, const Descriptor
*mask
, bool back
) {
281 TotalNumericMaxOrMinLoc
<TypeCategory::Integer
, 16, false>(
282 "MINLOC", result
, x
, kind
, source
, line
, mask
, back
);
285 void RTDEF(MinlocReal4
)(Descriptor
&result
, const Descriptor
&x
, int kind
,
286 const char *source
, int line
, const Descriptor
*mask
, bool back
) {
287 TotalNumericMaxOrMinLoc
<TypeCategory::Real
, 4, false>(
288 "MINLOC", result
, x
, kind
, source
, line
, mask
, back
);
290 void RTDEF(MinlocReal8
)(Descriptor
&result
, const Descriptor
&x
, int kind
,
291 const char *source
, int line
, const Descriptor
*mask
, bool back
) {
292 TotalNumericMaxOrMinLoc
<TypeCategory::Real
, 8, false>(
293 "MINLOC", result
, x
, kind
, source
, line
, mask
, back
);
296 void RTDEF(MinlocReal10
)(Descriptor
&result
, const Descriptor
&x
, int kind
,
297 const char *source
, int line
, const Descriptor
*mask
, bool back
) {
298 TotalNumericMaxOrMinLoc
<TypeCategory::Real
, 10, false>(
299 "MINLOC", result
, x
, kind
, source
, line
, mask
, back
);
302 #if HAS_LDBL128 || HAS_FLOAT128
303 void RTDEF(MinlocReal16
)(Descriptor
&result
, const Descriptor
&x
, int kind
,
304 const char *source
, int line
, const Descriptor
*mask
, bool back
) {
305 TotalNumericMaxOrMinLoc
<TypeCategory::Real
, 16, false>(
306 "MINLOC", result
, x
, kind
, source
, line
, mask
, back
);
313 // MAXLOC/MINLOC with DIM=
315 template <TypeCategory CAT
, int KIND
, bool IS_MAX
,
316 template <typename
, bool, bool> class COMPARE
, bool BACK
>
317 static RT_API_ATTRS
void DoPartialMaxOrMinLocDirection(const char *intrinsic
,
318 Descriptor
&result
, const Descriptor
&x
, int kind
, int dim
,
319 const Descriptor
*mask
, Terminator
&terminator
) {
320 using CppType
= CppTypeFor
<CAT
, KIND
>;
321 using Accumulator
= ExtremumLocAccumulator
<COMPARE
<CppType
, IS_MAX
, BACK
>>;
322 Accumulator accumulator
{x
};
323 ApplyIntegerKind
<PartialLocationHelper
<Accumulator
>::template Functor
, void>(
324 kind
, terminator
, result
, x
, dim
, mask
, terminator
, intrinsic
,
328 template <TypeCategory CAT
, int KIND
, bool IS_MAX
,
329 template <typename
, bool, bool> class COMPARE
>
330 inline RT_API_ATTRS
void DoPartialMaxOrMinLoc(const char *intrinsic
,
331 Descriptor
&result
, const Descriptor
&x
, int kind
, int dim
,
332 const Descriptor
*mask
, bool back
, Terminator
&terminator
) {
334 DoPartialMaxOrMinLocDirection
<CAT
, KIND
, IS_MAX
, COMPARE
, true>(
335 intrinsic
, result
, x
, kind
, dim
, mask
, terminator
);
337 DoPartialMaxOrMinLocDirection
<CAT
, KIND
, IS_MAX
, COMPARE
, false>(
338 intrinsic
, result
, x
, kind
, dim
, mask
, terminator
);
342 template <TypeCategory CAT
, bool IS_MAX
,
343 template <typename
, bool, bool> class COMPARE
>
344 struct DoPartialMaxOrMinLocHelper
{
345 template <int KIND
> struct Functor
{
346 RT_API_ATTRS
void operator()(const char *intrinsic
, Descriptor
&result
,
347 const Descriptor
&x
, int kind
, int dim
, const Descriptor
*mask
,
348 bool back
, Terminator
&terminator
) const {
349 DoPartialMaxOrMinLoc
<CAT
, KIND
, IS_MAX
, COMPARE
>(
350 intrinsic
, result
, x
, kind
, dim
, mask
, back
, terminator
);
355 template <bool IS_MAX
>
356 inline RT_API_ATTRS
void TypedPartialMaxOrMinLoc(const char *intrinsic
,
357 Descriptor
&result
, const Descriptor
&x
, int kind
, int dim
,
358 const char *source
, int line
, const Descriptor
*mask
, bool back
) {
359 Terminator terminator
{source
, line
};
360 CheckIntegerKind(terminator
, kind
, intrinsic
);
361 auto catKind
{x
.type().GetCategoryAndKind()};
362 RUNTIME_CHECK(terminator
, catKind
.has_value());
363 const Descriptor
*maskToUse
{mask
};
364 SubscriptValue maskAt
[maxRank
]; // contents unused
365 if (mask
&& mask
->rank() == 0) {
366 if (IsLogicalElementTrue(*mask
, maskAt
)) {
367 // A scalar MASK that's .TRUE. In this case, just get rid of the MASK.
370 // For scalar MASK arguments that are .FALSE., return all zeroes
372 // Element size of the destination descriptor is the size
373 // of {TypeCategory::Integer, kind}.
374 CreatePartialReductionResult(result
, x
,
375 Descriptor::BytesFor(TypeCategory::Integer
, kind
), dim
, terminator
,
376 intrinsic
, TypeCode
{TypeCategory::Integer
, kind
});
378 result
.OffsetElement(), 0, result
.Elements() * result
.ElementBytes());
382 switch (catKind
->first
) {
383 case TypeCategory::Integer
:
384 ApplyIntegerKind
<DoPartialMaxOrMinLocHelper
<TypeCategory::Integer
, IS_MAX
,
385 NumericCompare
>::template Functor
,
386 void>(catKind
->second
, terminator
, intrinsic
, result
, x
, kind
, dim
,
387 maskToUse
, back
, terminator
);
389 case TypeCategory::Real
:
390 ApplyFloatingPointKind
<DoPartialMaxOrMinLocHelper
<TypeCategory::Real
,
391 IS_MAX
, NumericCompare
>::template Functor
,
392 void>(catKind
->second
, terminator
, intrinsic
, result
, x
, kind
, dim
,
393 maskToUse
, back
, terminator
);
395 case TypeCategory::Character
:
396 ApplyCharacterKind
<DoPartialMaxOrMinLocHelper
<TypeCategory::Character
,
397 IS_MAX
, CharacterCompare
>::template Functor
,
398 void>(catKind
->second
, terminator
, intrinsic
, result
, x
, kind
, dim
,
399 maskToUse
, back
, terminator
);
403 "%s: bad data type code (%d) for array", intrinsic
, x
.type().raw());
408 RT_EXT_API_GROUP_BEGIN
410 void RTDEF(MaxlocDim
)(Descriptor
&result
, const Descriptor
&x
, int kind
,
411 int dim
, const char *source
, int line
, const Descriptor
*mask
, bool back
) {
412 TypedPartialMaxOrMinLoc
<true>(
413 "MAXLOC", result
, x
, kind
, dim
, source
, line
, mask
, back
);
415 void RTDEF(MinlocDim
)(Descriptor
&result
, const Descriptor
&x
, int kind
,
416 int dim
, const char *source
, int line
, const Descriptor
*mask
, bool back
) {
417 TypedPartialMaxOrMinLoc
<false>(
418 "MINLOC", result
, x
, kind
, dim
, source
, line
, mask
, back
);
426 template <TypeCategory CAT
, int KIND
, bool IS_MAXVAL
>
427 class NumericExtremumAccumulator
{
429 using Type
= CppTypeFor
<CAT
, KIND
>;
430 explicit RT_API_ATTRS
NumericExtremumAccumulator(const Descriptor
&array
)
432 RT_API_ATTRS
void Reinitialize() {
434 extremum_
= MaxOrMinIdentity
<CAT
, KIND
, IS_MAXVAL
>::Value();
436 template <typename A
>
437 RT_API_ATTRS
void GetResult(A
*p
, int /*zeroBasedDim*/ = -1) const {
440 RT_API_ATTRS
bool Accumulate(Type x
) {
444 } else if (CAT
== TypeCategory::Real
&& extremum_
!= extremum_
) {
445 extremum_
= x
; // replace NaN
446 } else if constexpr (IS_MAXVAL
) {
450 } else if (x
< extremum_
) {
455 template <typename A
>
456 RT_API_ATTRS
bool AccumulateAt(const SubscriptValue at
[]) {
457 return Accumulate(*array_
.Element
<A
>(at
));
461 const Descriptor
&array_
;
463 Type extremum_
{MaxOrMinIdentity
<CAT
, KIND
, IS_MAXVAL
>::Value()};
466 template <TypeCategory CAT
, int KIND
, bool IS_MAXVAL
>
467 inline RT_API_ATTRS CppTypeFor
<CAT
, KIND
> TotalNumericMaxOrMin(
468 const Descriptor
&x
, const char *source
, int line
, int dim
,
469 const Descriptor
*mask
, const char *intrinsic
) {
470 return GetTotalReduction
<CAT
, KIND
>(x
, source
, line
, dim
, mask
,
471 NumericExtremumAccumulator
<CAT
, KIND
, IS_MAXVAL
>{x
}, intrinsic
);
474 template <TypeCategory CAT
, bool IS_MAXVAL
> struct MaxOrMinHelper
{
475 template <int KIND
> struct Functor
{
476 RT_API_ATTRS
void operator()(Descriptor
&result
, const Descriptor
&x
,
477 int dim
, const Descriptor
*mask
, const char *intrinsic
,
478 Terminator
&terminator
) const {
479 DoMaxMinNorm2
<CAT
, KIND
,
480 NumericExtremumAccumulator
<CAT
, KIND
, IS_MAXVAL
>>(
481 result
, x
, dim
, mask
, intrinsic
, terminator
);
486 template <bool IS_MAXVAL
>
487 inline RT_API_ATTRS
void NumericMaxOrMin(Descriptor
&result
,
488 const Descriptor
&x
, int dim
, const char *source
, int line
,
489 const Descriptor
*mask
, const char *intrinsic
) {
490 Terminator terminator
{source
, line
};
491 auto type
{x
.type().GetCategoryAndKind()};
492 RUNTIME_CHECK(terminator
, type
);
493 switch (type
->first
) {
494 case TypeCategory::Integer
:
496 MaxOrMinHelper
<TypeCategory::Integer
, IS_MAXVAL
>::template Functor
,
498 type
->second
, terminator
, result
, x
, dim
, mask
, intrinsic
, terminator
);
500 case TypeCategory::Real
:
501 ApplyFloatingPointKind
<
502 MaxOrMinHelper
<TypeCategory::Real
, IS_MAXVAL
>::template Functor
, void>(
503 type
->second
, terminator
, result
, x
, dim
, mask
, intrinsic
, terminator
);
506 terminator
.Crash("%s: bad type code %d", intrinsic
, x
.type().raw());
510 template <int KIND
, bool IS_MAXVAL
> class CharacterExtremumAccumulator
{
512 using Type
= CppTypeFor
<TypeCategory::Character
, KIND
>;
513 explicit RT_API_ATTRS
CharacterExtremumAccumulator(const Descriptor
&array
)
514 : array_
{array
}, charLen_
{array_
.ElementBytes() / KIND
} {}
515 RT_API_ATTRS
void Reinitialize() { extremum_
= nullptr; }
516 template <typename A
>
517 RT_API_ATTRS
void GetResult(A
*p
, int /*zeroBasedDim*/ = -1) const {
518 static_assert(std::is_same_v
<A
, Type
>);
519 std::size_t byteSize
{array_
.ElementBytes()};
521 std::memcpy(p
, extremum_
, byteSize
);
523 // Empty array; fill with character 0 for MAXVAL.
524 // For MINVAL, set all of the bits.
525 std::memset(p
, IS_MAXVAL
? 0 : 255, byteSize
);
528 RT_API_ATTRS
bool Accumulate(const Type
*x
) {
532 int cmp
{CharacterScalarCompare(x
, extremum_
, charLen_
, charLen_
)};
533 if (IS_MAXVAL
== (cmp
> 0)) {
539 template <typename A
>
540 RT_API_ATTRS
bool AccumulateAt(const SubscriptValue at
[]) {
541 return Accumulate(array_
.Element
<A
>(at
));
545 const Descriptor
&array_
;
546 std::size_t charLen_
;
547 const Type
*extremum_
{nullptr};
550 template <bool IS_MAXVAL
> struct CharacterMaxOrMinHelper
{
551 template <int KIND
> struct Functor
{
552 RT_API_ATTRS
void operator()(Descriptor
&result
, const Descriptor
&x
,
553 int dim
, const Descriptor
*mask
, const char *intrinsic
,
554 Terminator
&terminator
) const {
555 DoMaxMinNorm2
<TypeCategory::Character
, KIND
,
556 CharacterExtremumAccumulator
<KIND
, IS_MAXVAL
>>(
557 result
, x
, dim
, mask
, intrinsic
, terminator
);
562 template <bool IS_MAXVAL
>
563 inline RT_API_ATTRS
void CharacterMaxOrMin(Descriptor
&result
,
564 const Descriptor
&x
, int dim
, const char *source
, int line
,
565 const Descriptor
*mask
, const char *intrinsic
) {
566 Terminator terminator
{source
, line
};
567 auto type
{x
.type().GetCategoryAndKind()};
568 RUNTIME_CHECK(terminator
, type
&& type
->first
== TypeCategory::Character
);
569 ApplyCharacterKind
<CharacterMaxOrMinHelper
<IS_MAXVAL
>::template Functor
,
571 type
->second
, terminator
, result
, x
, dim
, mask
, intrinsic
, terminator
);
575 RT_EXT_API_GROUP_BEGIN
577 CppTypeFor
<TypeCategory::Integer
, 1> RTDEF(MaxvalInteger1
)(const Descriptor
&x
,
578 const char *source
, int line
, int dim
, const Descriptor
*mask
) {
579 return TotalNumericMaxOrMin
<TypeCategory::Integer
, 1, true>(
580 x
, source
, line
, dim
, mask
, "MAXVAL");
582 CppTypeFor
<TypeCategory::Integer
, 2> RTDEF(MaxvalInteger2
)(const Descriptor
&x
,
583 const char *source
, int line
, int dim
, const Descriptor
*mask
) {
584 return TotalNumericMaxOrMin
<TypeCategory::Integer
, 2, true>(
585 x
, source
, line
, dim
, mask
, "MAXVAL");
587 CppTypeFor
<TypeCategory::Integer
, 4> RTDEF(MaxvalInteger4
)(const Descriptor
&x
,
588 const char *source
, int line
, int dim
, const Descriptor
*mask
) {
589 return TotalNumericMaxOrMin
<TypeCategory::Integer
, 4, true>(
590 x
, source
, line
, dim
, mask
, "MAXVAL");
592 CppTypeFor
<TypeCategory::Integer
, 8> RTDEF(MaxvalInteger8
)(const Descriptor
&x
,
593 const char *source
, int line
, int dim
, const Descriptor
*mask
) {
594 return TotalNumericMaxOrMin
<TypeCategory::Integer
, 8, true>(
595 x
, source
, line
, dim
, mask
, "MAXVAL");
597 #ifdef __SIZEOF_INT128__
598 CppTypeFor
<TypeCategory::Integer
, 16> RTDEF(MaxvalInteger16
)(
599 const Descriptor
&x
, const char *source
, int line
, int dim
,
600 const Descriptor
*mask
) {
601 return TotalNumericMaxOrMin
<TypeCategory::Integer
, 16, true>(
602 x
, source
, line
, dim
, mask
, "MAXVAL");
607 CppTypeFor
<TypeCategory::Real
, 4> RTDEF(MaxvalReal4
)(const Descriptor
&x
,
608 const char *source
, int line
, int dim
, const Descriptor
*mask
) {
609 return TotalNumericMaxOrMin
<TypeCategory::Real
, 4, true>(
610 x
, source
, line
, dim
, mask
, "MAXVAL");
612 CppTypeFor
<TypeCategory::Real
, 8> RTDEF(MaxvalReal8
)(const Descriptor
&x
,
613 const char *source
, int line
, int dim
, const Descriptor
*mask
) {
614 return TotalNumericMaxOrMin
<TypeCategory::Real
, 8, true>(
615 x
, source
, line
, dim
, mask
, "MAXVAL");
618 CppTypeFor
<TypeCategory::Real
, 10> RTDEF(MaxvalReal10
)(const Descriptor
&x
,
619 const char *source
, int line
, int dim
, const Descriptor
*mask
) {
620 return TotalNumericMaxOrMin
<TypeCategory::Real
, 10, true>(
621 x
, source
, line
, dim
, mask
, "MAXVAL");
624 #if HAS_LDBL128 || HAS_FLOAT128
625 CppTypeFor
<TypeCategory::Real
, 16> RTDEF(MaxvalReal16
)(const Descriptor
&x
,
626 const char *source
, int line
, int dim
, const Descriptor
*mask
) {
627 return TotalNumericMaxOrMin
<TypeCategory::Real
, 16, true>(
628 x
, source
, line
, dim
, mask
, "MAXVAL");
632 void RTDEF(MaxvalCharacter
)(Descriptor
&result
, const Descriptor
&x
,
633 const char *source
, int line
, const Descriptor
*mask
) {
634 CharacterMaxOrMin
<true>(result
, x
, 0, source
, line
, mask
, "MAXVAL");
637 CppTypeFor
<TypeCategory::Integer
, 1> RTDEF(MinvalInteger1
)(const Descriptor
&x
,
638 const char *source
, int line
, int dim
, const Descriptor
*mask
) {
639 return TotalNumericMaxOrMin
<TypeCategory::Integer
, 1, false>(
640 x
, source
, line
, dim
, mask
, "MINVAL");
642 CppTypeFor
<TypeCategory::Integer
, 2> RTDEF(MinvalInteger2
)(const Descriptor
&x
,
643 const char *source
, int line
, int dim
, const Descriptor
*mask
) {
644 return TotalNumericMaxOrMin
<TypeCategory::Integer
, 2, false>(
645 x
, source
, line
, dim
, mask
, "MINVAL");
647 CppTypeFor
<TypeCategory::Integer
, 4> RTDEF(MinvalInteger4
)(const Descriptor
&x
,
648 const char *source
, int line
, int dim
, const Descriptor
*mask
) {
649 return TotalNumericMaxOrMin
<TypeCategory::Integer
, 4, false>(
650 x
, source
, line
, dim
, mask
, "MINVAL");
652 CppTypeFor
<TypeCategory::Integer
, 8> RTDEF(MinvalInteger8
)(const Descriptor
&x
,
653 const char *source
, int line
, int dim
, const Descriptor
*mask
) {
654 return TotalNumericMaxOrMin
<TypeCategory::Integer
, 8, false>(
655 x
, source
, line
, dim
, mask
, "MINVAL");
657 #ifdef __SIZEOF_INT128__
658 CppTypeFor
<TypeCategory::Integer
, 16> RTDEF(MinvalInteger16
)(
659 const Descriptor
&x
, const char *source
, int line
, int dim
,
660 const Descriptor
*mask
) {
661 return TotalNumericMaxOrMin
<TypeCategory::Integer
, 16, false>(
662 x
, source
, line
, dim
, mask
, "MINVAL");
667 CppTypeFor
<TypeCategory::Real
, 4> RTDEF(MinvalReal4
)(const Descriptor
&x
,
668 const char *source
, int line
, int dim
, const Descriptor
*mask
) {
669 return TotalNumericMaxOrMin
<TypeCategory::Real
, 4, false>(
670 x
, source
, line
, dim
, mask
, "MINVAL");
672 CppTypeFor
<TypeCategory::Real
, 8> RTDEF(MinvalReal8
)(const Descriptor
&x
,
673 const char *source
, int line
, int dim
, const Descriptor
*mask
) {
674 return TotalNumericMaxOrMin
<TypeCategory::Real
, 8, false>(
675 x
, source
, line
, dim
, mask
, "MINVAL");
678 CppTypeFor
<TypeCategory::Real
, 10> RTDEF(MinvalReal10
)(const Descriptor
&x
,
679 const char *source
, int line
, int dim
, const Descriptor
*mask
) {
680 return TotalNumericMaxOrMin
<TypeCategory::Real
, 10, false>(
681 x
, source
, line
, dim
, mask
, "MINVAL");
684 #if HAS_LDBL128 || HAS_FLOAT128
685 CppTypeFor
<TypeCategory::Real
, 16> RTDEF(MinvalReal16
)(const Descriptor
&x
,
686 const char *source
, int line
, int dim
, const Descriptor
*mask
) {
687 return TotalNumericMaxOrMin
<TypeCategory::Real
, 16, false>(
688 x
, source
, line
, dim
, mask
, "MINVAL");
692 void RTDEF(MinvalCharacter
)(Descriptor
&result
, const Descriptor
&x
,
693 const char *source
, int line
, const Descriptor
*mask
) {
694 CharacterMaxOrMin
<false>(result
, x
, 0, source
, line
, mask
, "MINVAL");
697 void RTDEF(MaxvalDim
)(Descriptor
&result
, const Descriptor
&x
, int dim
,
698 const char *source
, int line
, const Descriptor
*mask
) {
699 if (x
.type().IsCharacter()) {
700 CharacterMaxOrMin
<true>(result
, x
, dim
, source
, line
, mask
, "MAXVAL");
702 NumericMaxOrMin
<true>(result
, x
, dim
, source
, line
, mask
, "MAXVAL");
705 void RTDEF(MinvalDim
)(Descriptor
&result
, const Descriptor
&x
, int dim
,
706 const char *source
, int line
, const Descriptor
*mask
) {
707 if (x
.type().IsCharacter()) {
708 CharacterMaxOrMin
<false>(result
, x
, dim
, source
, line
, mask
, "MINVAL");
710 NumericMaxOrMin
<false>(result
, x
, dim
, source
, line
, mask
, "MINVAL");
720 RT_EXT_API_GROUP_BEGIN
723 CppTypeFor
<TypeCategory::Real
, 4> RTDEF(Norm2_4
)(
724 const Descriptor
&x
, const char *source
, int line
, int dim
) {
725 return GetTotalReduction
<TypeCategory::Real
, 4>(
726 x
, source
, line
, dim
, nullptr, Norm2Accumulator
<4>{x
}, "NORM2");
728 CppTypeFor
<TypeCategory::Real
, 8> RTDEF(Norm2_8
)(
729 const Descriptor
&x
, const char *source
, int line
, int dim
) {
730 return GetTotalReduction
<TypeCategory::Real
, 8>(
731 x
, source
, line
, dim
, nullptr, Norm2Accumulator
<8>{x
}, "NORM2");
734 CppTypeFor
<TypeCategory::Real
, 10> RTDEF(Norm2_10
)(
735 const Descriptor
&x
, const char *source
, int line
, int dim
) {
736 return GetTotalReduction
<TypeCategory::Real
, 10>(
737 x
, source
, line
, dim
, nullptr, Norm2Accumulator
<10>{x
}, "NORM2");
741 void RTDEF(Norm2Dim
)(Descriptor
&result
, const Descriptor
&x
, int dim
,
742 const char *source
, int line
) {
743 Terminator terminator
{source
, line
};
744 auto type
{x
.type().GetCategoryAndKind()};
745 RUNTIME_CHECK(terminator
, type
);
746 if (type
->first
== TypeCategory::Real
) {
747 ApplyFloatingPointKind
<Norm2Helper
, void, true>(
748 type
->second
, terminator
, result
, x
, dim
, nullptr, terminator
);
750 terminator
.Crash("NORM2: bad type code %d", x
.type().raw());
756 } // namespace Fortran::runtime