llvm-project
756 строк · 28.8 Кб
1//===-- runtime/extrema.cpp -----------------------------------------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
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.
12
13#include "reduction-templates.h"14#include "flang/Common/float128.h"15#include "flang/Runtime/character.h"16#include "flang/Runtime/reduction.h"17#include <algorithm>18#include <cfloat>19#include <cinttypes>20#include <cmath>21#include <type_traits>22
23namespace Fortran::runtime {24
25// MAXLOC & MINLOC
26
27template <typename T, bool IS_MAX, bool BACK> struct NumericCompare {28using Type = T;29explicit RT_API_ATTRS NumericCompare(std::size_t /*elemLen; ignored*/) {}30RT_API_ATTRS bool operator()(const T &value, const T &previous) const {31if (std::is_floating_point_v<T> && previous != previous) {32return BACK || value == value; // replace NaN33} else if (value == previous) {34return BACK;35} else if constexpr (IS_MAX) {36return value > previous;37} else {38return value < previous;39}40}41};42
43template <typename T, bool IS_MAX, bool BACK> class CharacterCompare {44public:45using Type = T;46explicit RT_API_ATTRS CharacterCompare(std::size_t elemLen)47: chars_{elemLen / sizeof(T)} {}48RT_API_ATTRS bool operator()(const T &value, const T &previous) const {49int cmp{CharacterScalarCompare<T>(&value, &previous, chars_, chars_)};50if (cmp == 0) {51return BACK;52} else if constexpr (IS_MAX) {53return cmp > 0;54} else {55return cmp < 0;56}57}58
59private:60std::size_t chars_;61};62
63template <typename COMPARE> class ExtremumLocAccumulator {64public:65using Type = typename COMPARE::Type;66RT_API_ATTRS ExtremumLocAccumulator(const Descriptor &array)67: array_{array}, argRank_{array.rank()}, compare_{array.ElementBytes()} {68Reinitialize();69}70RT_API_ATTRS void Reinitialize() {71// per standard: result indices are all zero if no data72for (int j{0}; j < argRank_; ++j) {73extremumLoc_[j] = 0;74}75previous_ = nullptr;76}77RT_API_ATTRS int argRank() const { return argRank_; }78template <typename A>79RT_API_ATTRS void GetResult(A *p, int zeroBasedDim = -1) {80if (zeroBasedDim >= 0) {81*p = extremumLoc_[zeroBasedDim];82} else {83for (int j{0}; j < argRank_; ++j) {84p[j] = extremumLoc_[j];85}86}87}88template <typename IGNORED>89RT_API_ATTRS bool AccumulateAt(const SubscriptValue at[]) {90const auto &value{*array_.Element<Type>(at)};91if (!previous_ || compare_(value, *previous_)) {92previous_ = &value;93for (int j{0}; j < argRank_; ++j) {94extremumLoc_[j] = at[j] - array_.GetDimension(j).LowerBound() + 1;95}96}97return true;98}99
100private:101const Descriptor &array_;102int argRank_;103SubscriptValue extremumLoc_[maxRank];104const Type *previous_{nullptr};105COMPARE compare_;106};107
108template <typename ACCUMULATOR, typename CPPTYPE>109static RT_API_ATTRS void LocationHelper(const char *intrinsic,110Descriptor &result, const Descriptor &x, int kind, const Descriptor *mask,111Terminator &terminator) {112ACCUMULATOR accumulator{x};113DoTotalReduction<CPPTYPE>(x, 0, mask, accumulator, intrinsic, terminator);114ApplyIntegerKind<LocationResultHelper<ACCUMULATOR>::template Functor, void>(115kind, terminator, accumulator, result);116}
117
118template <TypeCategory CAT, int KIND, bool IS_MAX,119template <typename, bool, bool> class COMPARE>120inline RT_API_ATTRS void DoMaxOrMinLoc(const char *intrinsic,121Descriptor &result, const Descriptor &x, int kind, const char *source,122int line, const Descriptor *mask, bool back) {123using CppType = CppTypeFor<CAT, KIND>;124Terminator terminator{source, line};125if (back) {126LocationHelper<ExtremumLocAccumulator<COMPARE<CppType, IS_MAX, true>>,127CppType>(intrinsic, result, x, kind, mask, terminator);128} else {129LocationHelper<ExtremumLocAccumulator<COMPARE<CppType, IS_MAX, false>>,130CppType>(intrinsic, result, x, kind, mask, terminator);131}132}
133
134template <bool IS_MAX> struct CharacterMaxOrMinLocHelper {135template <int KIND> struct Functor {136RT_API_ATTRS void operator()(const char *intrinsic, Descriptor &result,137const Descriptor &x, int kind, const char *source, int line,138const Descriptor *mask, bool back) const {139DoMaxOrMinLoc<TypeCategory::Character, KIND, IS_MAX, CharacterCompare>(140intrinsic, result, x, kind, source, line, mask, back);141}142};143};144
145template <bool IS_MAX>146inline RT_API_ATTRS void CharacterMaxOrMinLoc(const char *intrinsic,147Descriptor &result, const Descriptor &x, int kind, const char *source,148int line, const Descriptor *mask, bool back) {149int rank{x.rank()};150SubscriptValue extent[1]{rank};151result.Establish(TypeCategory::Integer, kind, nullptr, 1, extent,152CFI_attribute_allocatable);153result.GetDimension(0).SetBounds(1, extent[0]);154Terminator terminator{source, line};155if (int stat{result.Allocate()}) {156terminator.Crash(157"%s: could not allocate memory for result; STAT=%d", intrinsic, stat);158}159CheckIntegerKind(terminator, kind, intrinsic);160auto catKind{x.type().GetCategoryAndKind()};161RUNTIME_CHECK(terminator, catKind.has_value());162switch (catKind->first) {163case TypeCategory::Character:164ApplyCharacterKind<CharacterMaxOrMinLocHelper<IS_MAX>::template Functor,165void>(catKind->second, terminator, intrinsic, result, x, kind, source,166line, mask, back);167break;168default:169terminator.Crash(170"%s: bad data type code (%d) for array", intrinsic, x.type().raw());171}172}
173
174template <TypeCategory CAT, int KIND, bool IS_MAXVAL>175inline RT_API_ATTRS void TotalNumericMaxOrMinLoc(const char *intrinsic,176Descriptor &result, const Descriptor &x, int kind, const char *source,177int line, const Descriptor *mask, bool back) {178int rank{x.rank()};179SubscriptValue extent[1]{rank};180result.Establish(TypeCategory::Integer, kind, nullptr, 1, extent,181CFI_attribute_allocatable);182result.GetDimension(0).SetBounds(1, extent[0]);183Terminator terminator{source, line};184if (int stat{result.Allocate()}) {185terminator.Crash(186"%s: could not allocate memory for result; STAT=%d", intrinsic, stat);187}188CheckIntegerKind(terminator, kind, intrinsic);189RUNTIME_CHECK(terminator, TypeCode(CAT, KIND) == x.type());190DoMaxOrMinLoc<CAT, KIND, IS_MAXVAL, NumericCompare>(191intrinsic, result, x, kind, source, line, mask, back);192}
193
194extern "C" {195RT_EXT_API_GROUP_BEGIN
196
197void RTDEF(MaxlocCharacter)(Descriptor &result, const Descriptor &x, int kind,198const char *source, int line, const Descriptor *mask, bool back) {199CharacterMaxOrMinLoc<true>(200"MAXLOC", result, x, kind, source, line, mask, back);201}
202void RTDEF(MaxlocInteger1)(Descriptor &result, const Descriptor &x, int kind,203const char *source, int line, const Descriptor *mask, bool back) {204TotalNumericMaxOrMinLoc<TypeCategory::Integer, 1, true>(205"MAXLOC", result, x, kind, source, line, mask, back);206}
207void RTDEF(MaxlocInteger2)(Descriptor &result, const Descriptor &x, int kind,208const char *source, int line, const Descriptor *mask, bool back) {209TotalNumericMaxOrMinLoc<TypeCategory::Integer, 2, true>(210"MAXLOC", result, x, kind, source, line, mask, back);211}
212void RTDEF(MaxlocInteger4)(Descriptor &result, const Descriptor &x, int kind,213const char *source, int line, const Descriptor *mask, bool back) {214TotalNumericMaxOrMinLoc<TypeCategory::Integer, 4, true>(215"MAXLOC", result, x, kind, source, line, mask, back);216}
217void RTDEF(MaxlocInteger8)(Descriptor &result, const Descriptor &x, int kind,218const char *source, int line, const Descriptor *mask, bool back) {219TotalNumericMaxOrMinLoc<TypeCategory::Integer, 8, true>(220"MAXLOC", result, x, kind, source, line, mask, back);221}
222#ifdef __SIZEOF_INT128__223void RTDEF(MaxlocInteger16)(Descriptor &result, const Descriptor &x, int kind,224const char *source, int line, const Descriptor *mask, bool back) {225TotalNumericMaxOrMinLoc<TypeCategory::Integer, 16, true>(226"MAXLOC", result, x, kind, source, line, mask, back);227}
228#endif229void RTDEF(MaxlocReal4)(Descriptor &result, const Descriptor &x, int kind,230const char *source, int line, const Descriptor *mask, bool back) {231TotalNumericMaxOrMinLoc<TypeCategory::Real, 4, true>(232"MAXLOC", result, x, kind, source, line, mask, back);233}
234void RTDEF(MaxlocReal8)(Descriptor &result, const Descriptor &x, int kind,235const char *source, int line, const Descriptor *mask, bool back) {236TotalNumericMaxOrMinLoc<TypeCategory::Real, 8, true>(237"MAXLOC", result, x, kind, source, line, mask, back);238}
239#if LDBL_MANT_DIG == 64240void RTDEF(MaxlocReal10)(Descriptor &result, const Descriptor &x, int kind,241const char *source, int line, const Descriptor *mask, bool back) {242TotalNumericMaxOrMinLoc<TypeCategory::Real, 10, true>(243"MAXLOC", result, x, kind, source, line, mask, back);244}
245#endif246#if LDBL_MANT_DIG == 113 || HAS_FLOAT128247void RTDEF(MaxlocReal16)(Descriptor &result, const Descriptor &x, int kind,248const char *source, int line, const Descriptor *mask, bool back) {249TotalNumericMaxOrMinLoc<TypeCategory::Real, 16, true>(250"MAXLOC", result, x, kind, source, line, mask, back);251}
252#endif253void RTDEF(MinlocCharacter)(Descriptor &result, const Descriptor &x, int kind,254const char *source, int line, const Descriptor *mask, bool back) {255CharacterMaxOrMinLoc<false>(256"MINLOC", result, x, kind, source, line, mask, back);257}
258void RTDEF(MinlocInteger1)(Descriptor &result, const Descriptor &x, int kind,259const char *source, int line, const Descriptor *mask, bool back) {260TotalNumericMaxOrMinLoc<TypeCategory::Integer, 1, false>(261"MINLOC", result, x, kind, source, line, mask, back);262}
263void RTDEF(MinlocInteger2)(Descriptor &result, const Descriptor &x, int kind,264const char *source, int line, const Descriptor *mask, bool back) {265TotalNumericMaxOrMinLoc<TypeCategory::Integer, 2, false>(266"MINLOC", result, x, kind, source, line, mask, back);267}
268void RTDEF(MinlocInteger4)(Descriptor &result, const Descriptor &x, int kind,269const char *source, int line, const Descriptor *mask, bool back) {270TotalNumericMaxOrMinLoc<TypeCategory::Integer, 4, false>(271"MINLOC", result, x, kind, source, line, mask, back);272}
273void RTDEF(MinlocInteger8)(Descriptor &result, const Descriptor &x, int kind,274const char *source, int line, const Descriptor *mask, bool back) {275TotalNumericMaxOrMinLoc<TypeCategory::Integer, 8, false>(276"MINLOC", result, x, kind, source, line, mask, back);277}
278#ifdef __SIZEOF_INT128__279void RTDEF(MinlocInteger16)(Descriptor &result, const Descriptor &x, int kind,280const char *source, int line, const Descriptor *mask, bool back) {281TotalNumericMaxOrMinLoc<TypeCategory::Integer, 16, false>(282"MINLOC", result, x, kind, source, line, mask, back);283}
284#endif285void RTDEF(MinlocReal4)(Descriptor &result, const Descriptor &x, int kind,286const char *source, int line, const Descriptor *mask, bool back) {287TotalNumericMaxOrMinLoc<TypeCategory::Real, 4, false>(288"MINLOC", result, x, kind, source, line, mask, back);289}
290void RTDEF(MinlocReal8)(Descriptor &result, const Descriptor &x, int kind,291const char *source, int line, const Descriptor *mask, bool back) {292TotalNumericMaxOrMinLoc<TypeCategory::Real, 8, false>(293"MINLOC", result, x, kind, source, line, mask, back);294}
295#if LDBL_MANT_DIG == 64296void RTDEF(MinlocReal10)(Descriptor &result, const Descriptor &x, int kind,297const char *source, int line, const Descriptor *mask, bool back) {298TotalNumericMaxOrMinLoc<TypeCategory::Real, 10, false>(299"MINLOC", result, x, kind, source, line, mask, back);300}
301#endif302#if LDBL_MANT_DIG == 113 || HAS_FLOAT128303void RTDEF(MinlocReal16)(Descriptor &result, const Descriptor &x, int kind,304const char *source, int line, const Descriptor *mask, bool back) {305TotalNumericMaxOrMinLoc<TypeCategory::Real, 16, false>(306"MINLOC", result, x, kind, source, line, mask, back);307}
308#endif309
310RT_EXT_API_GROUP_END
311} // extern "C"312
313// MAXLOC/MINLOC with DIM=
314
315template <TypeCategory CAT, int KIND, bool IS_MAX,316template <typename, bool, bool> class COMPARE, bool BACK>317static RT_API_ATTRS void DoPartialMaxOrMinLocDirection(const char *intrinsic,318Descriptor &result, const Descriptor &x, int kind, int dim,319const Descriptor *mask, Terminator &terminator) {320using CppType = CppTypeFor<CAT, KIND>;321using Accumulator = ExtremumLocAccumulator<COMPARE<CppType, IS_MAX, BACK>>;322Accumulator accumulator{x};323ApplyIntegerKind<PartialLocationHelper<Accumulator>::template Functor, void>(324kind, terminator, result, x, dim, mask, terminator, intrinsic,325accumulator);326}
327
328template <TypeCategory CAT, int KIND, bool IS_MAX,329template <typename, bool, bool> class COMPARE>330inline RT_API_ATTRS void DoPartialMaxOrMinLoc(const char *intrinsic,331Descriptor &result, const Descriptor &x, int kind, int dim,332const Descriptor *mask, bool back, Terminator &terminator) {333if (back) {334DoPartialMaxOrMinLocDirection<CAT, KIND, IS_MAX, COMPARE, true>(335intrinsic, result, x, kind, dim, mask, terminator);336} else {337DoPartialMaxOrMinLocDirection<CAT, KIND, IS_MAX, COMPARE, false>(338intrinsic, result, x, kind, dim, mask, terminator);339}340}
341
342template <TypeCategory CAT, bool IS_MAX,343template <typename, bool, bool> class COMPARE>344struct DoPartialMaxOrMinLocHelper {345template <int KIND> struct Functor {346RT_API_ATTRS void operator()(const char *intrinsic, Descriptor &result,347const Descriptor &x, int kind, int dim, const Descriptor *mask,348bool back, Terminator &terminator) const {349DoPartialMaxOrMinLoc<CAT, KIND, IS_MAX, COMPARE>(350intrinsic, result, x, kind, dim, mask, back, terminator);351}352};353};354
355template <bool IS_MAX>356inline RT_API_ATTRS void TypedPartialMaxOrMinLoc(const char *intrinsic,357Descriptor &result, const Descriptor &x, int kind, int dim,358const char *source, int line, const Descriptor *mask, bool back) {359Terminator terminator{source, line};360CheckIntegerKind(terminator, kind, intrinsic);361auto catKind{x.type().GetCategoryAndKind()};362RUNTIME_CHECK(terminator, catKind.has_value());363const Descriptor *maskToUse{mask};364SubscriptValue maskAt[maxRank]; // contents unused365if (mask && mask->rank() == 0) {366if (IsLogicalElementTrue(*mask, maskAt)) {367// A scalar MASK that's .TRUE. In this case, just get rid of the MASK.368maskToUse = nullptr;369} else {370// For scalar MASK arguments that are .FALSE., return all zeroes371
372// Element size of the destination descriptor is the size373// of {TypeCategory::Integer, kind}.374CreatePartialReductionResult(result, x,375Descriptor::BytesFor(TypeCategory::Integer, kind), dim, terminator,376intrinsic, TypeCode{TypeCategory::Integer, kind});377std::memset(378result.OffsetElement(), 0, result.Elements() * result.ElementBytes());379return;380}381}382switch (catKind->first) {383case TypeCategory::Integer:384ApplyIntegerKind<DoPartialMaxOrMinLocHelper<TypeCategory::Integer, IS_MAX,385NumericCompare>::template Functor,386void>(catKind->second, terminator, intrinsic, result, x, kind, dim,387maskToUse, back, terminator);388break;389case TypeCategory::Real:390ApplyFloatingPointKind<DoPartialMaxOrMinLocHelper<TypeCategory::Real,391IS_MAX, NumericCompare>::template Functor,392void>(catKind->second, terminator, intrinsic, result, x, kind, dim,393maskToUse, back, terminator);394break;395case TypeCategory::Character:396ApplyCharacterKind<DoPartialMaxOrMinLocHelper<TypeCategory::Character,397IS_MAX, CharacterCompare>::template Functor,398void>(catKind->second, terminator, intrinsic, result, x, kind, dim,399maskToUse, back, terminator);400break;401default:402terminator.Crash(403"%s: bad data type code (%d) for array", intrinsic, x.type().raw());404}405}
406
407extern "C" {408RT_EXT_API_GROUP_BEGIN
409
410void RTDEF(MaxlocDim)(Descriptor &result, const Descriptor &x, int kind,411int dim, const char *source, int line, const Descriptor *mask, bool back) {412TypedPartialMaxOrMinLoc<true>(413"MAXLOC", result, x, kind, dim, source, line, mask, back);414}
415void RTDEF(MinlocDim)(Descriptor &result, const Descriptor &x, int kind,416int dim, const char *source, int line, const Descriptor *mask, bool back) {417TypedPartialMaxOrMinLoc<false>(418"MINLOC", result, x, kind, dim, source, line, mask, back);419}
420
421RT_EXT_API_GROUP_END
422} // extern "C"423
424// MAXVAL and MINVAL
425
426template <TypeCategory CAT, int KIND, bool IS_MAXVAL>427class NumericExtremumAccumulator {428public:429using Type = CppTypeFor<CAT, KIND>;430explicit RT_API_ATTRS NumericExtremumAccumulator(const Descriptor &array)431: array_{array} {}432RT_API_ATTRS void Reinitialize() {433any_ = false;434extremum_ = MaxOrMinIdentity<CAT, KIND, IS_MAXVAL>::Value();435}436template <typename A>437RT_API_ATTRS void GetResult(A *p, int /*zeroBasedDim*/ = -1) const {438*p = extremum_;439}440RT_API_ATTRS bool Accumulate(Type x) {441if (!any_) {442extremum_ = x;443any_ = true;444} else if (CAT == TypeCategory::Real && extremum_ != extremum_) {445extremum_ = x; // replace NaN446} else if constexpr (IS_MAXVAL) {447if (x > extremum_) {448extremum_ = x;449}450} else if (x < extremum_) {451extremum_ = x;452}453return true;454}455template <typename A>456RT_API_ATTRS bool AccumulateAt(const SubscriptValue at[]) {457return Accumulate(*array_.Element<A>(at));458}459
460private:461const Descriptor &array_;462bool any_{false};463Type extremum_{MaxOrMinIdentity<CAT, KIND, IS_MAXVAL>::Value()};464};465
466template <TypeCategory CAT, int KIND, bool IS_MAXVAL>467inline RT_API_ATTRS CppTypeFor<CAT, KIND> TotalNumericMaxOrMin(468const Descriptor &x, const char *source, int line, int dim,469const Descriptor *mask, const char *intrinsic) {470return GetTotalReduction<CAT, KIND>(x, source, line, dim, mask,471NumericExtremumAccumulator<CAT, KIND, IS_MAXVAL>{x}, intrinsic);472}
473
474template <TypeCategory CAT, bool IS_MAXVAL> struct MaxOrMinHelper {475template <int KIND> struct Functor {476RT_API_ATTRS void operator()(Descriptor &result, const Descriptor &x,477int dim, const Descriptor *mask, const char *intrinsic,478Terminator &terminator) const {479DoMaxMinNorm2<CAT, KIND,480NumericExtremumAccumulator<CAT, KIND, IS_MAXVAL>>(481result, x, dim, mask, intrinsic, terminator);482}483};484};485
486template <bool IS_MAXVAL>487inline RT_API_ATTRS void NumericMaxOrMin(Descriptor &result,488const Descriptor &x, int dim, const char *source, int line,489const Descriptor *mask, const char *intrinsic) {490Terminator terminator{source, line};491auto type{x.type().GetCategoryAndKind()};492RUNTIME_CHECK(terminator, type);493switch (type->first) {494case TypeCategory::Integer:495ApplyIntegerKind<496MaxOrMinHelper<TypeCategory::Integer, IS_MAXVAL>::template Functor,497void>(498type->second, terminator, result, x, dim, mask, intrinsic, terminator);499break;500case TypeCategory::Real:501ApplyFloatingPointKind<502MaxOrMinHelper<TypeCategory::Real, IS_MAXVAL>::template Functor, void>(503type->second, terminator, result, x, dim, mask, intrinsic, terminator);504break;505default:506terminator.Crash("%s: bad type code %d", intrinsic, x.type().raw());507}508}
509
510template <int KIND, bool IS_MAXVAL> class CharacterExtremumAccumulator {511public:512using Type = CppTypeFor<TypeCategory::Character, KIND>;513explicit RT_API_ATTRS CharacterExtremumAccumulator(const Descriptor &array)514: array_{array}, charLen_{array_.ElementBytes() / KIND} {}515RT_API_ATTRS void Reinitialize() { extremum_ = nullptr; }516template <typename A>517RT_API_ATTRS void GetResult(A *p, int /*zeroBasedDim*/ = -1) const {518static_assert(std::is_same_v<A, Type>);519std::size_t byteSize{array_.ElementBytes()};520if (extremum_) {521std::memcpy(p, extremum_, byteSize);522} else {523// Empty array; fill with character 0 for MAXVAL.524// For MINVAL, set all of the bits.525std::memset(p, IS_MAXVAL ? 0 : 255, byteSize);526}527}528RT_API_ATTRS bool Accumulate(const Type *x) {529if (!extremum_) {530extremum_ = x;531} else {532int cmp{CharacterScalarCompare(x, extremum_, charLen_, charLen_)};533if (IS_MAXVAL == (cmp > 0)) {534extremum_ = x;535}536}537return true;538}539template <typename A>540RT_API_ATTRS bool AccumulateAt(const SubscriptValue at[]) {541return Accumulate(array_.Element<A>(at));542}543
544private:545const Descriptor &array_;546std::size_t charLen_;547const Type *extremum_{nullptr};548};549
550template <bool IS_MAXVAL> struct CharacterMaxOrMinHelper {551template <int KIND> struct Functor {552RT_API_ATTRS void operator()(Descriptor &result, const Descriptor &x,553int dim, const Descriptor *mask, const char *intrinsic,554Terminator &terminator) const {555DoMaxMinNorm2<TypeCategory::Character, KIND,556CharacterExtremumAccumulator<KIND, IS_MAXVAL>>(557result, x, dim, mask, intrinsic, terminator);558}559};560};561
562template <bool IS_MAXVAL>563inline RT_API_ATTRS void CharacterMaxOrMin(Descriptor &result,564const Descriptor &x, int dim, const char *source, int line,565const Descriptor *mask, const char *intrinsic) {566Terminator terminator{source, line};567auto type{x.type().GetCategoryAndKind()};568RUNTIME_CHECK(terminator, type && type->first == TypeCategory::Character);569ApplyCharacterKind<CharacterMaxOrMinHelper<IS_MAXVAL>::template Functor,570void>(571type->second, terminator, result, x, dim, mask, intrinsic, terminator);572}
573
574extern "C" {575RT_EXT_API_GROUP_BEGIN
576
577CppTypeFor<TypeCategory::Integer, 1> RTDEF(MaxvalInteger1)(const Descriptor &x,578const char *source, int line, int dim, const Descriptor *mask) {579return TotalNumericMaxOrMin<TypeCategory::Integer, 1, true>(580x, source, line, dim, mask, "MAXVAL");581}
582CppTypeFor<TypeCategory::Integer, 2> RTDEF(MaxvalInteger2)(const Descriptor &x,583const char *source, int line, int dim, const Descriptor *mask) {584return TotalNumericMaxOrMin<TypeCategory::Integer, 2, true>(585x, source, line, dim, mask, "MAXVAL");586}
587CppTypeFor<TypeCategory::Integer, 4> RTDEF(MaxvalInteger4)(const Descriptor &x,588const char *source, int line, int dim, const Descriptor *mask) {589return TotalNumericMaxOrMin<TypeCategory::Integer, 4, true>(590x, source, line, dim, mask, "MAXVAL");591}
592CppTypeFor<TypeCategory::Integer, 8> RTDEF(MaxvalInteger8)(const Descriptor &x,593const char *source, int line, int dim, const Descriptor *mask) {594return TotalNumericMaxOrMin<TypeCategory::Integer, 8, true>(595x, source, line, dim, mask, "MAXVAL");596}
597#ifdef __SIZEOF_INT128__598CppTypeFor<TypeCategory::Integer, 16> RTDEF(MaxvalInteger16)(599const Descriptor &x, const char *source, int line, int dim,600const Descriptor *mask) {601return TotalNumericMaxOrMin<TypeCategory::Integer, 16, true>(602x, source, line, dim, mask, "MAXVAL");603}
604#endif605
606// TODO: REAL(2 & 3)
607CppTypeFor<TypeCategory::Real, 4> RTDEF(MaxvalReal4)(const Descriptor &x,608const char *source, int line, int dim, const Descriptor *mask) {609return TotalNumericMaxOrMin<TypeCategory::Real, 4, true>(610x, source, line, dim, mask, "MAXVAL");611}
612CppTypeFor<TypeCategory::Real, 8> RTDEF(MaxvalReal8)(const Descriptor &x,613const char *source, int line, int dim, const Descriptor *mask) {614return TotalNumericMaxOrMin<TypeCategory::Real, 8, true>(615x, source, line, dim, mask, "MAXVAL");616}
617#if LDBL_MANT_DIG == 64618CppTypeFor<TypeCategory::Real, 10> RTDEF(MaxvalReal10)(const Descriptor &x,619const char *source, int line, int dim, const Descriptor *mask) {620return TotalNumericMaxOrMin<TypeCategory::Real, 10, true>(621x, source, line, dim, mask, "MAXVAL");622}
623#endif624#if LDBL_MANT_DIG == 113 || HAS_FLOAT128625CppTypeFor<TypeCategory::Real, 16> RTDEF(MaxvalReal16)(const Descriptor &x,626const char *source, int line, int dim, const Descriptor *mask) {627return TotalNumericMaxOrMin<TypeCategory::Real, 16, true>(628x, source, line, dim, mask, "MAXVAL");629}
630#endif631
632void RTDEF(MaxvalCharacter)(Descriptor &result, const Descriptor &x,633const char *source, int line, const Descriptor *mask) {634CharacterMaxOrMin<true>(result, x, 0, source, line, mask, "MAXVAL");635}
636
637CppTypeFor<TypeCategory::Integer, 1> RTDEF(MinvalInteger1)(const Descriptor &x,638const char *source, int line, int dim, const Descriptor *mask) {639return TotalNumericMaxOrMin<TypeCategory::Integer, 1, false>(640x, source, line, dim, mask, "MINVAL");641}
642CppTypeFor<TypeCategory::Integer, 2> RTDEF(MinvalInteger2)(const Descriptor &x,643const char *source, int line, int dim, const Descriptor *mask) {644return TotalNumericMaxOrMin<TypeCategory::Integer, 2, false>(645x, source, line, dim, mask, "MINVAL");646}
647CppTypeFor<TypeCategory::Integer, 4> RTDEF(MinvalInteger4)(const Descriptor &x,648const char *source, int line, int dim, const Descriptor *mask) {649return TotalNumericMaxOrMin<TypeCategory::Integer, 4, false>(650x, source, line, dim, mask, "MINVAL");651}
652CppTypeFor<TypeCategory::Integer, 8> RTDEF(MinvalInteger8)(const Descriptor &x,653const char *source, int line, int dim, const Descriptor *mask) {654return TotalNumericMaxOrMin<TypeCategory::Integer, 8, false>(655x, source, line, dim, mask, "MINVAL");656}
657#ifdef __SIZEOF_INT128__658CppTypeFor<TypeCategory::Integer, 16> RTDEF(MinvalInteger16)(659const Descriptor &x, const char *source, int line, int dim,660const Descriptor *mask) {661return TotalNumericMaxOrMin<TypeCategory::Integer, 16, false>(662x, source, line, dim, mask, "MINVAL");663}
664#endif665
666// TODO: REAL(2 & 3)
667CppTypeFor<TypeCategory::Real, 4> RTDEF(MinvalReal4)(const Descriptor &x,668const char *source, int line, int dim, const Descriptor *mask) {669return TotalNumericMaxOrMin<TypeCategory::Real, 4, false>(670x, source, line, dim, mask, "MINVAL");671}
672CppTypeFor<TypeCategory::Real, 8> RTDEF(MinvalReal8)(const Descriptor &x,673const char *source, int line, int dim, const Descriptor *mask) {674return TotalNumericMaxOrMin<TypeCategory::Real, 8, false>(675x, source, line, dim, mask, "MINVAL");676}
677#if LDBL_MANT_DIG == 64678CppTypeFor<TypeCategory::Real, 10> RTDEF(MinvalReal10)(const Descriptor &x,679const char *source, int line, int dim, const Descriptor *mask) {680return TotalNumericMaxOrMin<TypeCategory::Real, 10, false>(681x, source, line, dim, mask, "MINVAL");682}
683#endif684#if LDBL_MANT_DIG == 113 || HAS_FLOAT128685CppTypeFor<TypeCategory::Real, 16> RTDEF(MinvalReal16)(const Descriptor &x,686const char *source, int line, int dim, const Descriptor *mask) {687return TotalNumericMaxOrMin<TypeCategory::Real, 16, false>(688x, source, line, dim, mask, "MINVAL");689}
690#endif691
692void RTDEF(MinvalCharacter)(Descriptor &result, const Descriptor &x,693const char *source, int line, const Descriptor *mask) {694CharacterMaxOrMin<false>(result, x, 0, source, line, mask, "MINVAL");695}
696
697void RTDEF(MaxvalDim)(Descriptor &result, const Descriptor &x, int dim,698const char *source, int line, const Descriptor *mask) {699if (x.type().IsCharacter()) {700CharacterMaxOrMin<true>(result, x, dim, source, line, mask, "MAXVAL");701} else {702NumericMaxOrMin<true>(result, x, dim, source, line, mask, "MAXVAL");703}704}
705void RTDEF(MinvalDim)(Descriptor &result, const Descriptor &x, int dim,706const char *source, int line, const Descriptor *mask) {707if (x.type().IsCharacter()) {708CharacterMaxOrMin<false>(result, x, dim, source, line, mask, "MINVAL");709} else {710NumericMaxOrMin<false>(result, x, dim, source, line, mask, "MINVAL");711}712}
713
714RT_EXT_API_GROUP_END
715} // extern "C"716
717// NORM2
718
719extern "C" {720RT_EXT_API_GROUP_BEGIN
721
722// TODO: REAL(2 & 3)
723CppTypeFor<TypeCategory::Real, 4> RTDEF(Norm2_4)(724const Descriptor &x, const char *source, int line, int dim) {725return GetTotalReduction<TypeCategory::Real, 4>(726x, source, line, dim, nullptr, Norm2Accumulator<4>{x}, "NORM2");727}
728CppTypeFor<TypeCategory::Real, 8> RTDEF(Norm2_8)(729const Descriptor &x, const char *source, int line, int dim) {730return GetTotalReduction<TypeCategory::Real, 8>(731x, source, line, dim, nullptr, Norm2Accumulator<8>{x}, "NORM2");732}
733#if LDBL_MANT_DIG == 64734CppTypeFor<TypeCategory::Real, 10> RTDEF(Norm2_10)(735const Descriptor &x, const char *source, int line, int dim) {736return GetTotalReduction<TypeCategory::Real, 10>(737x, source, line, dim, nullptr, Norm2Accumulator<10>{x}, "NORM2");738}
739#endif740
741void RTDEF(Norm2Dim)(Descriptor &result, const Descriptor &x, int dim,742const char *source, int line) {743Terminator terminator{source, line};744auto type{x.type().GetCategoryAndKind()};745RUNTIME_CHECK(terminator, type);746if (type->first == TypeCategory::Real) {747ApplyFloatingPointKind<Norm2Helper, void, true>(748type->second, terminator, result, x, dim, nullptr, terminator);749} else {750terminator.Crash("NORM2: bad type code %d", x.type().raw());751}752}
753
754RT_EXT_API_GROUP_END
755} // extern "C"756} // namespace Fortran::runtime757