1e372e0f9Speter klausler //===-- runtime/reduction.cpp ---------------------------------------------===// 2e372e0f9Speter klausler // 3e372e0f9Speter klausler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e372e0f9Speter klausler // See https://llvm.org/LICENSE.txt for license information. 5e372e0f9Speter klausler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e372e0f9Speter klausler // 7e372e0f9Speter klausler //===----------------------------------------------------------------------===// 8e372e0f9Speter klausler 9fdf33771Speter klausler // Implements ALL, ANY, COUNT, IALL, IANY, IPARITY, & PARITY for all required 10fdf33771Speter klausler // operand types and shapes. 11e372e0f9Speter klausler // 1247f18af5Speter klausler // DOT_PRODUCT, FINDLOC, MATMUL, SUM, and PRODUCT are in their own eponymous 1347f18af5Speter klausler // source files. 1447f18af5Speter klausler // NORM2, MAXLOC, MINLOC, MAXVAL, and MINVAL are in extrema.cpp. 15e372e0f9Speter klausler 16830c0b90SPeter Klausler #include "flang/Runtime/reduction.h" 17beb5ac8bSpeter klausler #include "reduction-templates.h" 1877ff6f7dSPeter Klausler #include "flang/Runtime/descriptor.h" 19e372e0f9Speter klausler #include <cinttypes> 20e372e0f9Speter klausler 21e372e0f9Speter klausler namespace Fortran::runtime { 22e372e0f9Speter klausler 23fdf33771Speter klausler // IALL, IANY, IPARITY 24fdf33771Speter klausler 25fdf33771Speter klausler template <typename INTERMEDIATE> class IntegerAndAccumulator { 26fdf33771Speter klausler public: 27b4b23ff7SSlava Zakharin explicit RT_API_ATTRS IntegerAndAccumulator(const Descriptor &array) 28b4b23ff7SSlava Zakharin : array_{array} {} 29b4b23ff7SSlava Zakharin RT_API_ATTRS void Reinitialize() { and_ = ~INTERMEDIATE{0}; } 30b4b23ff7SSlava Zakharin template <typename A> 31b4b23ff7SSlava Zakharin RT_API_ATTRS void GetResult(A *p, int /*zeroBasedDim*/ = -1) const { 32fdf33771Speter klausler *p = static_cast<A>(and_); 33fdf33771Speter klausler } 34b4b23ff7SSlava Zakharin template <typename A> 35b4b23ff7SSlava Zakharin RT_API_ATTRS bool AccumulateAt(const SubscriptValue at[]) { 36fdf33771Speter klausler and_ &= *array_.Element<A>(at); 37fdf33771Speter klausler return true; 38fdf33771Speter klausler } 39fdf33771Speter klausler 40fdf33771Speter klausler private: 41fdf33771Speter klausler const Descriptor &array_; 42fdf33771Speter klausler INTERMEDIATE and_{~INTERMEDIATE{0}}; 43fdf33771Speter klausler }; 44fdf33771Speter klausler 45fdf33771Speter klausler template <typename INTERMEDIATE> class IntegerOrAccumulator { 46fdf33771Speter klausler public: 47b4b23ff7SSlava Zakharin explicit RT_API_ATTRS IntegerOrAccumulator(const Descriptor &array) 48b4b23ff7SSlava Zakharin : array_{array} {} 49b4b23ff7SSlava Zakharin RT_API_ATTRS void Reinitialize() { or_ = 0; } 50b4b23ff7SSlava Zakharin template <typename A> 51b4b23ff7SSlava Zakharin RT_API_ATTRS void GetResult(A *p, int /*zeroBasedDim*/ = -1) const { 52fdf33771Speter klausler *p = static_cast<A>(or_); 53fdf33771Speter klausler } 54b4b23ff7SSlava Zakharin template <typename A> 55b4b23ff7SSlava Zakharin RT_API_ATTRS bool AccumulateAt(const SubscriptValue at[]) { 56fdf33771Speter klausler or_ |= *array_.Element<A>(at); 57fdf33771Speter klausler return true; 58fdf33771Speter klausler } 59fdf33771Speter klausler 60fdf33771Speter klausler private: 61fdf33771Speter klausler const Descriptor &array_; 62fdf33771Speter klausler INTERMEDIATE or_{0}; 63fdf33771Speter klausler }; 648d672c0bSpeter klausler 658d672c0bSpeter klausler template <typename INTERMEDIATE> class IntegerXorAccumulator { 668d672c0bSpeter klausler public: 67b4b23ff7SSlava Zakharin explicit RT_API_ATTRS IntegerXorAccumulator(const Descriptor &array) 68b4b23ff7SSlava Zakharin : array_{array} {} 69b4b23ff7SSlava Zakharin RT_API_ATTRS void Reinitialize() { xor_ = 0; } 70b4b23ff7SSlava Zakharin template <typename A> 71b4b23ff7SSlava Zakharin RT_API_ATTRS void GetResult(A *p, int /*zeroBasedDim*/ = -1) const { 728d672c0bSpeter klausler *p = static_cast<A>(xor_); 738d672c0bSpeter klausler } 74b4b23ff7SSlava Zakharin template <typename A> 75b4b23ff7SSlava Zakharin RT_API_ATTRS bool AccumulateAt(const SubscriptValue at[]) { 768d672c0bSpeter klausler xor_ ^= *array_.Element<A>(at); 778d672c0bSpeter klausler return true; 788d672c0bSpeter klausler } 798d672c0bSpeter klausler 808d672c0bSpeter klausler private: 818d672c0bSpeter klausler const Descriptor &array_; 828d672c0bSpeter klausler INTERMEDIATE xor_{0}; 838d672c0bSpeter klausler }; 848d672c0bSpeter klausler 858d672c0bSpeter klausler extern "C" { 86b4b23ff7SSlava Zakharin CppTypeFor<TypeCategory::Integer, 1> RTDEF(IAll1)(const Descriptor &x, 87fdf33771Speter klausler const char *source, int line, int dim, const Descriptor *mask) { 88fdf33771Speter klausler return GetTotalReduction<TypeCategory::Integer, 1>(x, source, line, dim, mask, 89*fc97d2e6SPeter Klausler IntegerAndAccumulator<CppTypeFor<TypeCategory::Integer, 4>>{x}, "IALL", 90*fc97d2e6SPeter Klausler /*allowUnsignedForInteger=*/true); 91fdf33771Speter klausler } 92b4b23ff7SSlava Zakharin CppTypeFor<TypeCategory::Integer, 2> RTDEF(IAll2)(const Descriptor &x, 93fdf33771Speter klausler const char *source, int line, int dim, const Descriptor *mask) { 94fdf33771Speter klausler return GetTotalReduction<TypeCategory::Integer, 2>(x, source, line, dim, mask, 95*fc97d2e6SPeter Klausler IntegerAndAccumulator<CppTypeFor<TypeCategory::Integer, 4>>{x}, "IALL", 96*fc97d2e6SPeter Klausler /*allowUnsignedForInteger=*/true); 97fdf33771Speter klausler } 98b4b23ff7SSlava Zakharin CppTypeFor<TypeCategory::Integer, 4> RTDEF(IAll4)(const Descriptor &x, 99fdf33771Speter klausler const char *source, int line, int dim, const Descriptor *mask) { 100fdf33771Speter klausler return GetTotalReduction<TypeCategory::Integer, 4>(x, source, line, dim, mask, 101*fc97d2e6SPeter Klausler IntegerAndAccumulator<CppTypeFor<TypeCategory::Integer, 4>>{x}, "IALL", 102*fc97d2e6SPeter Klausler /*allowUnsignedForInteger=*/true); 103fdf33771Speter klausler } 104b4b23ff7SSlava Zakharin CppTypeFor<TypeCategory::Integer, 8> RTDEF(IAll8)(const Descriptor &x, 105fdf33771Speter klausler const char *source, int line, int dim, const Descriptor *mask) { 106fdf33771Speter klausler return GetTotalReduction<TypeCategory::Integer, 8>(x, source, line, dim, mask, 107*fc97d2e6SPeter Klausler IntegerAndAccumulator<CppTypeFor<TypeCategory::Integer, 8>>{x}, "IALL", 108*fc97d2e6SPeter Klausler /*allowUnsignedForInteger=*/true); 109fdf33771Speter klausler } 110fdf33771Speter klausler #ifdef __SIZEOF_INT128__ 111b4b23ff7SSlava Zakharin CppTypeFor<TypeCategory::Integer, 16> RTDEF(IAll16)(const Descriptor &x, 112fdf33771Speter klausler const char *source, int line, int dim, const Descriptor *mask) { 113fdf33771Speter klausler return GetTotalReduction<TypeCategory::Integer, 16>(x, source, line, dim, 114fdf33771Speter klausler mask, IntegerAndAccumulator<CppTypeFor<TypeCategory::Integer, 16>>{x}, 115*fc97d2e6SPeter Klausler "IALL", /*allowUnsignedForInteger=*/true); 116fdf33771Speter klausler } 117fdf33771Speter klausler #endif 118b4b23ff7SSlava Zakharin void RTDEF(IAllDim)(Descriptor &result, const Descriptor &x, int dim, 119fdf33771Speter klausler const char *source, int line, const Descriptor *mask) { 120fdf33771Speter klausler Terminator terminator{source, line}; 121fdf33771Speter klausler auto catKind{x.type().GetCategoryAndKind()}; 122fdf33771Speter klausler RUNTIME_CHECK(terminator, 123*fc97d2e6SPeter Klausler catKind.has_value() && 124*fc97d2e6SPeter Klausler (catKind->first == TypeCategory::Integer || 125*fc97d2e6SPeter Klausler catKind->first == TypeCategory::Unsigned)); 126fdf33771Speter klausler PartialIntegerReduction<IntegerAndAccumulator>( 127fdf33771Speter klausler result, x, dim, catKind->second, mask, "IALL", terminator); 128fdf33771Speter klausler } 129fdf33771Speter klausler 130b4b23ff7SSlava Zakharin CppTypeFor<TypeCategory::Integer, 1> RTDEF(IAny1)(const Descriptor &x, 131fdf33771Speter klausler const char *source, int line, int dim, const Descriptor *mask) { 132fdf33771Speter klausler return GetTotalReduction<TypeCategory::Integer, 1>(x, source, line, dim, mask, 133*fc97d2e6SPeter Klausler IntegerOrAccumulator<CppTypeFor<TypeCategory::Integer, 4>>{x}, "IANY", 134*fc97d2e6SPeter Klausler /*allowUnsignedForInteger=*/true); 135fdf33771Speter klausler } 136b4b23ff7SSlava Zakharin CppTypeFor<TypeCategory::Integer, 2> RTDEF(IAny2)(const Descriptor &x, 137fdf33771Speter klausler const char *source, int line, int dim, const Descriptor *mask) { 138fdf33771Speter klausler return GetTotalReduction<TypeCategory::Integer, 2>(x, source, line, dim, mask, 139*fc97d2e6SPeter Klausler IntegerOrAccumulator<CppTypeFor<TypeCategory::Integer, 4>>{x}, "IANY", 140*fc97d2e6SPeter Klausler /*allowUnsignedForInteger=*/true); 141fdf33771Speter klausler } 142b4b23ff7SSlava Zakharin CppTypeFor<TypeCategory::Integer, 4> RTDEF(IAny4)(const Descriptor &x, 143fdf33771Speter klausler const char *source, int line, int dim, const Descriptor *mask) { 144fdf33771Speter klausler return GetTotalReduction<TypeCategory::Integer, 4>(x, source, line, dim, mask, 145*fc97d2e6SPeter Klausler IntegerOrAccumulator<CppTypeFor<TypeCategory::Integer, 4>>{x}, "IANY", 146*fc97d2e6SPeter Klausler /*allowUnsignedForInteger=*/true); 147fdf33771Speter klausler } 148b4b23ff7SSlava Zakharin CppTypeFor<TypeCategory::Integer, 8> RTDEF(IAny8)(const Descriptor &x, 149fdf33771Speter klausler const char *source, int line, int dim, const Descriptor *mask) { 150fdf33771Speter klausler return GetTotalReduction<TypeCategory::Integer, 8>(x, source, line, dim, mask, 151*fc97d2e6SPeter Klausler IntegerOrAccumulator<CppTypeFor<TypeCategory::Integer, 8>>{x}, "IANY", 152*fc97d2e6SPeter Klausler /*allowUnsignedForInteger=*/true); 153fdf33771Speter klausler } 154fdf33771Speter klausler #ifdef __SIZEOF_INT128__ 155b4b23ff7SSlava Zakharin CppTypeFor<TypeCategory::Integer, 16> RTDEF(IAny16)(const Descriptor &x, 156fdf33771Speter klausler const char *source, int line, int dim, const Descriptor *mask) { 157fdf33771Speter klausler return GetTotalReduction<TypeCategory::Integer, 16>(x, source, line, dim, 158fdf33771Speter klausler mask, IntegerOrAccumulator<CppTypeFor<TypeCategory::Integer, 16>>{x}, 159*fc97d2e6SPeter Klausler "IANY", /*allowUnsignedForInteger=*/true); 160fdf33771Speter klausler } 161fdf33771Speter klausler #endif 162b4b23ff7SSlava Zakharin void RTDEF(IAnyDim)(Descriptor &result, const Descriptor &x, int dim, 163fdf33771Speter klausler const char *source, int line, const Descriptor *mask) { 164fdf33771Speter klausler Terminator terminator{source, line}; 165fdf33771Speter klausler auto catKind{x.type().GetCategoryAndKind()}; 166fdf33771Speter klausler RUNTIME_CHECK(terminator, 167*fc97d2e6SPeter Klausler catKind.has_value() && 168*fc97d2e6SPeter Klausler (catKind->first == TypeCategory::Integer || 169*fc97d2e6SPeter Klausler catKind->first == TypeCategory::Unsigned)); 170fdf33771Speter klausler PartialIntegerReduction<IntegerOrAccumulator>( 171fdf33771Speter klausler result, x, dim, catKind->second, mask, "IANY", terminator); 172fdf33771Speter klausler } 173fdf33771Speter klausler 174b4b23ff7SSlava Zakharin CppTypeFor<TypeCategory::Integer, 1> RTDEF(IParity1)(const Descriptor &x, 1758d672c0bSpeter klausler const char *source, int line, int dim, const Descriptor *mask) { 1768d672c0bSpeter klausler return GetTotalReduction<TypeCategory::Integer, 1>(x, source, line, dim, mask, 177*fc97d2e6SPeter Klausler IntegerXorAccumulator<CppTypeFor<TypeCategory::Integer, 4>>{x}, "IPARITY", 178*fc97d2e6SPeter Klausler /*allowUnsignedForInteger=*/true); 1798d672c0bSpeter klausler } 180b4b23ff7SSlava Zakharin CppTypeFor<TypeCategory::Integer, 2> RTDEF(IParity2)(const Descriptor &x, 1818d672c0bSpeter klausler const char *source, int line, int dim, const Descriptor *mask) { 1828d672c0bSpeter klausler return GetTotalReduction<TypeCategory::Integer, 2>(x, source, line, dim, mask, 183*fc97d2e6SPeter Klausler IntegerXorAccumulator<CppTypeFor<TypeCategory::Integer, 4>>{x}, "IPARITY", 184*fc97d2e6SPeter Klausler /*allowUnsignedForInteger=*/true); 1858d672c0bSpeter klausler } 186b4b23ff7SSlava Zakharin CppTypeFor<TypeCategory::Integer, 4> RTDEF(IParity4)(const Descriptor &x, 1878d672c0bSpeter klausler const char *source, int line, int dim, const Descriptor *mask) { 1888d672c0bSpeter klausler return GetTotalReduction<TypeCategory::Integer, 4>(x, source, line, dim, mask, 189*fc97d2e6SPeter Klausler IntegerXorAccumulator<CppTypeFor<TypeCategory::Integer, 4>>{x}, "IPARITY", 190*fc97d2e6SPeter Klausler /*allowUnsignedForInteger=*/true); 1918d672c0bSpeter klausler } 192b4b23ff7SSlava Zakharin CppTypeFor<TypeCategory::Integer, 8> RTDEF(IParity8)(const Descriptor &x, 1938d672c0bSpeter klausler const char *source, int line, int dim, const Descriptor *mask) { 1948d672c0bSpeter klausler return GetTotalReduction<TypeCategory::Integer, 8>(x, source, line, dim, mask, 195*fc97d2e6SPeter Klausler IntegerXorAccumulator<CppTypeFor<TypeCategory::Integer, 8>>{x}, "IPARITY", 196*fc97d2e6SPeter Klausler /*allowUnsignedForInteger=*/true); 1978d672c0bSpeter klausler } 1988d672c0bSpeter klausler #ifdef __SIZEOF_INT128__ 199b4b23ff7SSlava Zakharin CppTypeFor<TypeCategory::Integer, 16> RTDEF(IParity16)(const Descriptor &x, 2008d672c0bSpeter klausler const char *source, int line, int dim, const Descriptor *mask) { 2018d672c0bSpeter klausler return GetTotalReduction<TypeCategory::Integer, 16>(x, source, line, dim, 2028d672c0bSpeter klausler mask, IntegerXorAccumulator<CppTypeFor<TypeCategory::Integer, 16>>{x}, 203*fc97d2e6SPeter Klausler "IPARITY", /*allowUnsignedForInteger=*/true); 2048d672c0bSpeter klausler } 2058d672c0bSpeter klausler #endif 206b4b23ff7SSlava Zakharin void RTDEF(IParityDim)(Descriptor &result, const Descriptor &x, int dim, 2078d672c0bSpeter klausler const char *source, int line, const Descriptor *mask) { 2088d672c0bSpeter klausler Terminator terminator{source, line}; 2098d672c0bSpeter klausler auto catKind{x.type().GetCategoryAndKind()}; 2108d672c0bSpeter klausler RUNTIME_CHECK(terminator, 211*fc97d2e6SPeter Klausler catKind.has_value() && 212*fc97d2e6SPeter Klausler (catKind->first == TypeCategory::Integer || 213*fc97d2e6SPeter Klausler catKind->first == TypeCategory::Unsigned)); 2148d672c0bSpeter klausler PartialIntegerReduction<IntegerXorAccumulator>( 2158d672c0bSpeter klausler result, x, dim, catKind->second, mask, "IPARITY", terminator); 2168d672c0bSpeter klausler } 2178d672c0bSpeter klausler } 2188d672c0bSpeter klausler 2198d672c0bSpeter klausler // ALL, ANY, COUNT, & PARITY 220e372e0f9Speter klausler 2218d672c0bSpeter klausler enum class LogicalReduction { All, Any, Parity }; 2228d672c0bSpeter klausler 2238d672c0bSpeter klausler template <LogicalReduction REDUCTION> class LogicalAccumulator { 224e372e0f9Speter klausler public: 225e372e0f9Speter klausler using Type = bool; 226e372e0f9Speter klausler explicit LogicalAccumulator(const Descriptor &array) : array_{array} {} 2278d672c0bSpeter klausler void Reinitialize() { result_ = REDUCTION == LogicalReduction::All; } 228e372e0f9Speter klausler bool Result() const { return result_; } 229e372e0f9Speter klausler bool Accumulate(bool x) { 2308d672c0bSpeter klausler if constexpr (REDUCTION == LogicalReduction::Parity) { 2318d672c0bSpeter klausler result_ = result_ != x; 2328d672c0bSpeter klausler } else if (x != (REDUCTION == LogicalReduction::All)) { 233e372e0f9Speter klausler result_ = x; 234e372e0f9Speter klausler return false; 235e372e0f9Speter klausler } 2368d672c0bSpeter klausler return true; 237e372e0f9Speter klausler } 238e372e0f9Speter klausler template <typename IGNORED = void> 239e372e0f9Speter klausler bool AccumulateAt(const SubscriptValue at[]) { 240e372e0f9Speter klausler return Accumulate(IsLogicalElementTrue(array_, at)); 241e372e0f9Speter klausler } 242e372e0f9Speter klausler 243e372e0f9Speter klausler private: 244e372e0f9Speter klausler const Descriptor &array_; 2458d672c0bSpeter klausler bool result_{REDUCTION == LogicalReduction::All}; 246e372e0f9Speter klausler }; 247e372e0f9Speter klausler 248e372e0f9Speter klausler template <typename ACCUMULATOR> 249e372e0f9Speter klausler inline auto GetTotalLogicalReduction(const Descriptor &x, const char *source, 250e372e0f9Speter klausler int line, int dim, ACCUMULATOR &&accumulator, const char *intrinsic) -> 251e372e0f9Speter klausler typename ACCUMULATOR::Type { 252e372e0f9Speter klausler Terminator terminator{source, line}; 253e372e0f9Speter klausler if (dim < 0 || dim > 1) { 254e3550f19SPeter Steinfeld terminator.Crash("%s: bad DIM=%d for ARRAY with rank=1", intrinsic, dim); 255e372e0f9Speter klausler } 256e372e0f9Speter klausler SubscriptValue xAt[maxRank]; 257e372e0f9Speter klausler x.GetLowerBounds(xAt); 258e372e0f9Speter klausler for (auto elements{x.Elements()}; elements--; x.IncrementSubscripts(xAt)) { 259e372e0f9Speter klausler if (!accumulator.AccumulateAt(xAt)) { 260e372e0f9Speter klausler break; // cut short, result is known 261e372e0f9Speter klausler } 262e372e0f9Speter klausler } 263e372e0f9Speter klausler return accumulator.Result(); 264e372e0f9Speter klausler } 265e372e0f9Speter klausler 266e372e0f9Speter klausler template <typename ACCUMULATOR> 267e372e0f9Speter klausler inline auto ReduceLogicalDimToScalar(const Descriptor &x, int zeroBasedDim, 268e372e0f9Speter klausler SubscriptValue subscripts[]) -> typename ACCUMULATOR::Type { 269e372e0f9Speter klausler ACCUMULATOR accumulator{x}; 270e372e0f9Speter klausler SubscriptValue xAt[maxRank]; 271e372e0f9Speter klausler GetExpandedSubscripts(xAt, x, zeroBasedDim, subscripts); 272e372e0f9Speter klausler const auto &dim{x.GetDimension(zeroBasedDim)}; 273e372e0f9Speter klausler SubscriptValue at{dim.LowerBound()}; 274e372e0f9Speter klausler for (auto n{dim.Extent()}; n-- > 0; ++at) { 275e372e0f9Speter klausler xAt[zeroBasedDim] = at; 276e372e0f9Speter klausler if (!accumulator.AccumulateAt(xAt)) { 277e372e0f9Speter klausler break; 278e372e0f9Speter klausler } 279e372e0f9Speter klausler } 280e372e0f9Speter klausler return accumulator.Result(); 281e372e0f9Speter klausler } 282e372e0f9Speter klausler 2838d672c0bSpeter klausler template <LogicalReduction REDUCTION> struct LogicalReduceHelper { 2848d672c0bSpeter klausler template <int KIND> struct Functor { 2858d672c0bSpeter klausler void operator()(Descriptor &result, const Descriptor &x, int dim, 2868d672c0bSpeter klausler Terminator &terminator, const char *intrinsic) const { 287e372e0f9Speter klausler // Standard requires result to have same LOGICAL kind as argument. 2888d672c0bSpeter klausler CreatePartialReductionResult( 289d37250c9SSlava Zakharin result, x, x.ElementBytes(), dim, terminator, intrinsic, x.type()); 290e372e0f9Speter klausler SubscriptValue at[maxRank]; 291e372e0f9Speter klausler result.GetLowerBounds(at); 2921dbc9b53SMark Leair INTERNAL_CHECK(result.rank() == 0 || at[0] == 1); 293e372e0f9Speter klausler using CppType = CppTypeFor<TypeCategory::Logical, KIND>; 294e372e0f9Speter klausler for (auto n{result.Elements()}; n-- > 0; result.IncrementSubscripts(at)) { 295e372e0f9Speter klausler *result.Element<CppType>(at) = 2968d672c0bSpeter klausler ReduceLogicalDimToScalar<LogicalAccumulator<REDUCTION>>( 2978d672c0bSpeter klausler x, dim - 1, at); 298e372e0f9Speter klausler } 299e372e0f9Speter klausler } 3008d672c0bSpeter klausler }; 3018d672c0bSpeter klausler }; 302e372e0f9Speter klausler 3038d672c0bSpeter klausler template <LogicalReduction REDUCTION> 304e372e0f9Speter klausler inline void DoReduceLogicalDimension(Descriptor &result, const Descriptor &x, 305e372e0f9Speter klausler int dim, Terminator &terminator, const char *intrinsic) { 306e372e0f9Speter klausler auto catKind{x.type().GetCategoryAndKind()}; 307e372e0f9Speter klausler RUNTIME_CHECK(terminator, catKind && catKind->first == TypeCategory::Logical); 3088d672c0bSpeter klausler ApplyLogicalKind<LogicalReduceHelper<REDUCTION>::template Functor, void>( 3098d672c0bSpeter klausler catKind->second, terminator, result, x, dim, terminator, intrinsic); 310e372e0f9Speter klausler } 311e372e0f9Speter klausler 312e372e0f9Speter klausler // COUNT 313e372e0f9Speter klausler 314e372e0f9Speter klausler class CountAccumulator { 315e372e0f9Speter klausler public: 316e372e0f9Speter klausler using Type = std::int64_t; 317e372e0f9Speter klausler explicit CountAccumulator(const Descriptor &array) : array_{array} {} 3188d672c0bSpeter klausler void Reinitialize() { result_ = 0; } 319e372e0f9Speter klausler Type Result() const { return result_; } 320e372e0f9Speter klausler template <typename IGNORED = void> 321e372e0f9Speter klausler bool AccumulateAt(const SubscriptValue at[]) { 322e372e0f9Speter klausler if (IsLogicalElementTrue(array_, at)) { 323e372e0f9Speter klausler ++result_; 324e372e0f9Speter klausler } 325e372e0f9Speter klausler return true; 326e372e0f9Speter klausler } 327e372e0f9Speter klausler 328e372e0f9Speter klausler private: 329e372e0f9Speter klausler const Descriptor &array_; 330e372e0f9Speter klausler Type result_{0}; 331e372e0f9Speter klausler }; 332e372e0f9Speter klausler 3338d672c0bSpeter klausler template <int KIND> struct CountDimension { 3348d672c0bSpeter klausler void operator()(Descriptor &result, const Descriptor &x, int dim, 3358d672c0bSpeter klausler Terminator &terminator) const { 336d37250c9SSlava Zakharin // Element size of the descriptor descriptor is the size 337d37250c9SSlava Zakharin // of {TypeCategory::Integer, KIND}. 338d37250c9SSlava Zakharin CreatePartialReductionResult(result, x, 339d37250c9SSlava Zakharin Descriptor::BytesFor(TypeCategory::Integer, KIND), dim, terminator, 340d37250c9SSlava Zakharin "COUNT", TypeCode{TypeCategory::Integer, KIND}); 341e372e0f9Speter klausler SubscriptValue at[maxRank]; 342e372e0f9Speter klausler result.GetLowerBounds(at); 3431dbc9b53SMark Leair INTERNAL_CHECK(result.rank() == 0 || at[0] == 1); 344e372e0f9Speter klausler using CppType = CppTypeFor<TypeCategory::Integer, KIND>; 345e372e0f9Speter klausler for (auto n{result.Elements()}; n-- > 0; result.IncrementSubscripts(at)) { 346e372e0f9Speter klausler *result.Element<CppType>(at) = 347e372e0f9Speter klausler ReduceLogicalDimToScalar<CountAccumulator>(x, dim - 1, at); 348e372e0f9Speter klausler } 349e372e0f9Speter klausler } 3508d672c0bSpeter klausler }; 351e372e0f9Speter klausler 352e372e0f9Speter klausler extern "C" { 35376facde3SSlava Zakharin RT_EXT_API_GROUP_BEGIN 354e372e0f9Speter klausler 355b4b23ff7SSlava Zakharin bool RTDEF(All)(const Descriptor &x, const char *source, int line, int dim) { 3568d672c0bSpeter klausler return GetTotalLogicalReduction(x, source, line, dim, 3578d672c0bSpeter klausler LogicalAccumulator<LogicalReduction::All>{x}, "ALL"); 358e372e0f9Speter klausler } 359b4b23ff7SSlava Zakharin void RTDEF(AllDim)(Descriptor &result, const Descriptor &x, int dim, 360e372e0f9Speter klausler const char *source, int line) { 361e372e0f9Speter klausler Terminator terminator{source, line}; 3628d672c0bSpeter klausler DoReduceLogicalDimension<LogicalReduction::All>( 3638d672c0bSpeter klausler result, x, dim, terminator, "ALL"); 364e372e0f9Speter klausler } 365e372e0f9Speter klausler 366b4b23ff7SSlava Zakharin bool RTDEF(Any)(const Descriptor &x, const char *source, int line, int dim) { 3678d672c0bSpeter klausler return GetTotalLogicalReduction(x, source, line, dim, 3688d672c0bSpeter klausler LogicalAccumulator<LogicalReduction::Any>{x}, "ANY"); 369e372e0f9Speter klausler } 370b4b23ff7SSlava Zakharin void RTDEF(AnyDim)(Descriptor &result, const Descriptor &x, int dim, 371e372e0f9Speter klausler const char *source, int line) { 372e372e0f9Speter klausler Terminator terminator{source, line}; 3738d672c0bSpeter klausler DoReduceLogicalDimension<LogicalReduction::Any>( 3748d672c0bSpeter klausler result, x, dim, terminator, "ANY"); 375e372e0f9Speter klausler } 376e372e0f9Speter klausler 377b4b23ff7SSlava Zakharin std::int64_t RTDEF(Count)( 378e372e0f9Speter klausler const Descriptor &x, const char *source, int line, int dim) { 379e372e0f9Speter klausler return GetTotalLogicalReduction( 380e372e0f9Speter klausler x, source, line, dim, CountAccumulator{x}, "COUNT"); 381e372e0f9Speter klausler } 3828d672c0bSpeter klausler 383b4b23ff7SSlava Zakharin void RTDEF(CountDim)(Descriptor &result, const Descriptor &x, int dim, int kind, 384b4b23ff7SSlava Zakharin const char *source, int line) { 385e372e0f9Speter klausler Terminator terminator{source, line}; 3868d672c0bSpeter klausler ApplyIntegerKind<CountDimension, void>( 3878d672c0bSpeter klausler kind, terminator, result, x, dim, terminator); 388e372e0f9Speter klausler } 3898d672c0bSpeter klausler 390b4b23ff7SSlava Zakharin bool RTDEF(Parity)(const Descriptor &x, const char *source, int line, int dim) { 3918d672c0bSpeter klausler return GetTotalLogicalReduction(x, source, line, dim, 3928d672c0bSpeter klausler LogicalAccumulator<LogicalReduction::Parity>{x}, "PARITY"); 3938d672c0bSpeter klausler } 394b4b23ff7SSlava Zakharin void RTDEF(ParityDim)(Descriptor &result, const Descriptor &x, int dim, 3958d672c0bSpeter klausler const char *source, int line) { 3968d672c0bSpeter klausler Terminator terminator{source, line}; 3978d672c0bSpeter klausler DoReduceLogicalDimension<LogicalReduction::Parity>( 3988d672c0bSpeter klausler result, x, dim, terminator, "PARITY"); 399e372e0f9Speter klausler } 400e372e0f9Speter klausler 40176facde3SSlava Zakharin RT_EXT_API_GROUP_END 402e372e0f9Speter klausler } // extern "C" 403e372e0f9Speter klausler } // namespace Fortran::runtime 404