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:
IntegerAndAccumulator(const Descriptor & array)27fdf33771Speter klausler   explicit IntegerAndAccumulator(const Descriptor &array) : array_{array} {}
Reinitialize()28fdf33771Speter klausler   void Reinitialize() { and_ = ~INTERMEDIATE{0}; }
GetResult(A * p,int=-1) const29fdf33771Speter klausler   template <typename A> void GetResult(A *p, int /*zeroBasedDim*/ = -1) const {
30fdf33771Speter klausler     *p = static_cast<A>(and_);
31fdf33771Speter klausler   }
AccumulateAt(const SubscriptValue at[])32fdf33771Speter klausler   template <typename A> bool AccumulateAt(const SubscriptValue at[]) {
33fdf33771Speter klausler     and_ &= *array_.Element<A>(at);
34fdf33771Speter klausler     return true;
35fdf33771Speter klausler   }
36fdf33771Speter klausler 
37fdf33771Speter klausler private:
38fdf33771Speter klausler   const Descriptor &array_;
39fdf33771Speter klausler   INTERMEDIATE and_{~INTERMEDIATE{0}};
40fdf33771Speter klausler };
41fdf33771Speter klausler 
42fdf33771Speter klausler template <typename INTERMEDIATE> class IntegerOrAccumulator {
43fdf33771Speter klausler public:
IntegerOrAccumulator(const Descriptor & array)44fdf33771Speter klausler   explicit IntegerOrAccumulator(const Descriptor &array) : array_{array} {}
Reinitialize()45fdf33771Speter klausler   void Reinitialize() { or_ = 0; }
GetResult(A * p,int=-1) const46fdf33771Speter klausler   template <typename A> void GetResult(A *p, int /*zeroBasedDim*/ = -1) const {
47fdf33771Speter klausler     *p = static_cast<A>(or_);
48fdf33771Speter klausler   }
AccumulateAt(const SubscriptValue at[])49fdf33771Speter klausler   template <typename A> bool AccumulateAt(const SubscriptValue at[]) {
50fdf33771Speter klausler     or_ |= *array_.Element<A>(at);
51fdf33771Speter klausler     return true;
52fdf33771Speter klausler   }
53fdf33771Speter klausler 
54fdf33771Speter klausler private:
55fdf33771Speter klausler   const Descriptor &array_;
56fdf33771Speter klausler   INTERMEDIATE or_{0};
57fdf33771Speter klausler };
588d672c0bSpeter klausler 
598d672c0bSpeter klausler template <typename INTERMEDIATE> class IntegerXorAccumulator {
608d672c0bSpeter klausler public:
IntegerXorAccumulator(const Descriptor & array)618d672c0bSpeter klausler   explicit IntegerXorAccumulator(const Descriptor &array) : array_{array} {}
Reinitialize()628d672c0bSpeter klausler   void Reinitialize() { xor_ = 0; }
GetResult(A * p,int=-1) const638d672c0bSpeter klausler   template <typename A> void GetResult(A *p, int /*zeroBasedDim*/ = -1) const {
648d672c0bSpeter klausler     *p = static_cast<A>(xor_);
658d672c0bSpeter klausler   }
AccumulateAt(const SubscriptValue at[])668d672c0bSpeter klausler   template <typename A> bool AccumulateAt(const SubscriptValue at[]) {
678d672c0bSpeter klausler     xor_ ^= *array_.Element<A>(at);
688d672c0bSpeter klausler     return true;
698d672c0bSpeter klausler   }
708d672c0bSpeter klausler 
718d672c0bSpeter klausler private:
728d672c0bSpeter klausler   const Descriptor &array_;
738d672c0bSpeter klausler   INTERMEDIATE xor_{0};
748d672c0bSpeter klausler };
758d672c0bSpeter klausler 
768d672c0bSpeter klausler extern "C" {
RTNAME(IAll1)77fdf33771Speter klausler CppTypeFor<TypeCategory::Integer, 1> RTNAME(IAll1)(const Descriptor &x,
78fdf33771Speter klausler     const char *source, int line, int dim, const Descriptor *mask) {
79fdf33771Speter klausler   return GetTotalReduction<TypeCategory::Integer, 1>(x, source, line, dim, mask,
80fdf33771Speter klausler       IntegerAndAccumulator<CppTypeFor<TypeCategory::Integer, 4>>{x}, "IALL");
81fdf33771Speter klausler }
RTNAME(IAll2)82fdf33771Speter klausler CppTypeFor<TypeCategory::Integer, 2> RTNAME(IAll2)(const Descriptor &x,
83fdf33771Speter klausler     const char *source, int line, int dim, const Descriptor *mask) {
84fdf33771Speter klausler   return GetTotalReduction<TypeCategory::Integer, 2>(x, source, line, dim, mask,
85fdf33771Speter klausler       IntegerAndAccumulator<CppTypeFor<TypeCategory::Integer, 4>>{x}, "IALL");
86fdf33771Speter klausler }
RTNAME(IAll4)87fdf33771Speter klausler CppTypeFor<TypeCategory::Integer, 4> RTNAME(IAll4)(const Descriptor &x,
88fdf33771Speter klausler     const char *source, int line, int dim, const Descriptor *mask) {
89fdf33771Speter klausler   return GetTotalReduction<TypeCategory::Integer, 4>(x, source, line, dim, mask,
90fdf33771Speter klausler       IntegerAndAccumulator<CppTypeFor<TypeCategory::Integer, 4>>{x}, "IALL");
91fdf33771Speter klausler }
RTNAME(IAll8)92fdf33771Speter klausler CppTypeFor<TypeCategory::Integer, 8> RTNAME(IAll8)(const Descriptor &x,
93fdf33771Speter klausler     const char *source, int line, int dim, const Descriptor *mask) {
94fdf33771Speter klausler   return GetTotalReduction<TypeCategory::Integer, 8>(x, source, line, dim, mask,
95fdf33771Speter klausler       IntegerAndAccumulator<CppTypeFor<TypeCategory::Integer, 8>>{x}, "IALL");
96fdf33771Speter klausler }
97fdf33771Speter klausler #ifdef __SIZEOF_INT128__
RTNAME(IAll16)98fdf33771Speter klausler CppTypeFor<TypeCategory::Integer, 16> RTNAME(IAll16)(const Descriptor &x,
99fdf33771Speter klausler     const char *source, int line, int dim, const Descriptor *mask) {
100fdf33771Speter klausler   return GetTotalReduction<TypeCategory::Integer, 16>(x, source, line, dim,
101fdf33771Speter klausler       mask, IntegerAndAccumulator<CppTypeFor<TypeCategory::Integer, 16>>{x},
102fdf33771Speter klausler       "IALL");
103fdf33771Speter klausler }
104fdf33771Speter klausler #endif
RTNAME(IAllDim)105fdf33771Speter klausler void RTNAME(IAllDim)(Descriptor &result, const Descriptor &x, int dim,
106fdf33771Speter klausler     const char *source, int line, const Descriptor *mask) {
107fdf33771Speter klausler   Terminator terminator{source, line};
108fdf33771Speter klausler   auto catKind{x.type().GetCategoryAndKind()};
109fdf33771Speter klausler   RUNTIME_CHECK(terminator,
110fdf33771Speter klausler       catKind.has_value() && catKind->first == TypeCategory::Integer);
111fdf33771Speter klausler   PartialIntegerReduction<IntegerAndAccumulator>(
112fdf33771Speter klausler       result, x, dim, catKind->second, mask, "IALL", terminator);
113fdf33771Speter klausler }
114fdf33771Speter klausler 
RTNAME(IAny1)115fdf33771Speter klausler CppTypeFor<TypeCategory::Integer, 1> RTNAME(IAny1)(const Descriptor &x,
116fdf33771Speter klausler     const char *source, int line, int dim, const Descriptor *mask) {
117fdf33771Speter klausler   return GetTotalReduction<TypeCategory::Integer, 1>(x, source, line, dim, mask,
118fdf33771Speter klausler       IntegerOrAccumulator<CppTypeFor<TypeCategory::Integer, 4>>{x}, "IANY");
119fdf33771Speter klausler }
RTNAME(IAny2)120fdf33771Speter klausler CppTypeFor<TypeCategory::Integer, 2> RTNAME(IAny2)(const Descriptor &x,
121fdf33771Speter klausler     const char *source, int line, int dim, const Descriptor *mask) {
122fdf33771Speter klausler   return GetTotalReduction<TypeCategory::Integer, 2>(x, source, line, dim, mask,
123fdf33771Speter klausler       IntegerOrAccumulator<CppTypeFor<TypeCategory::Integer, 4>>{x}, "IANY");
124fdf33771Speter klausler }
RTNAME(IAny4)125fdf33771Speter klausler CppTypeFor<TypeCategory::Integer, 4> RTNAME(IAny4)(const Descriptor &x,
126fdf33771Speter klausler     const char *source, int line, int dim, const Descriptor *mask) {
127fdf33771Speter klausler   return GetTotalReduction<TypeCategory::Integer, 4>(x, source, line, dim, mask,
128fdf33771Speter klausler       IntegerOrAccumulator<CppTypeFor<TypeCategory::Integer, 4>>{x}, "IANY");
129fdf33771Speter klausler }
RTNAME(IAny8)130fdf33771Speter klausler CppTypeFor<TypeCategory::Integer, 8> RTNAME(IAny8)(const Descriptor &x,
131fdf33771Speter klausler     const char *source, int line, int dim, const Descriptor *mask) {
132fdf33771Speter klausler   return GetTotalReduction<TypeCategory::Integer, 8>(x, source, line, dim, mask,
133fdf33771Speter klausler       IntegerOrAccumulator<CppTypeFor<TypeCategory::Integer, 8>>{x}, "IANY");
134fdf33771Speter klausler }
135fdf33771Speter klausler #ifdef __SIZEOF_INT128__
RTNAME(IAny16)136fdf33771Speter klausler CppTypeFor<TypeCategory::Integer, 16> RTNAME(IAny16)(const Descriptor &x,
137fdf33771Speter klausler     const char *source, int line, int dim, const Descriptor *mask) {
138fdf33771Speter klausler   return GetTotalReduction<TypeCategory::Integer, 16>(x, source, line, dim,
139fdf33771Speter klausler       mask, IntegerOrAccumulator<CppTypeFor<TypeCategory::Integer, 16>>{x},
140fdf33771Speter klausler       "IANY");
141fdf33771Speter klausler }
142fdf33771Speter klausler #endif
RTNAME(IAnyDim)143fdf33771Speter klausler void RTNAME(IAnyDim)(Descriptor &result, const Descriptor &x, int dim,
144fdf33771Speter klausler     const char *source, int line, const Descriptor *mask) {
145fdf33771Speter klausler   Terminator terminator{source, line};
146fdf33771Speter klausler   auto catKind{x.type().GetCategoryAndKind()};
147fdf33771Speter klausler   RUNTIME_CHECK(terminator,
148fdf33771Speter klausler       catKind.has_value() && catKind->first == TypeCategory::Integer);
149fdf33771Speter klausler   PartialIntegerReduction<IntegerOrAccumulator>(
150fdf33771Speter klausler       result, x, dim, catKind->second, mask, "IANY", terminator);
151fdf33771Speter klausler }
152fdf33771Speter klausler 
RTNAME(IParity1)1538d672c0bSpeter klausler CppTypeFor<TypeCategory::Integer, 1> RTNAME(IParity1)(const Descriptor &x,
1548d672c0bSpeter klausler     const char *source, int line, int dim, const Descriptor *mask) {
1558d672c0bSpeter klausler   return GetTotalReduction<TypeCategory::Integer, 1>(x, source, line, dim, mask,
1568d672c0bSpeter klausler       IntegerXorAccumulator<CppTypeFor<TypeCategory::Integer, 4>>{x},
1578d672c0bSpeter klausler       "IPARITY");
1588d672c0bSpeter klausler }
RTNAME(IParity2)1598d672c0bSpeter klausler CppTypeFor<TypeCategory::Integer, 2> RTNAME(IParity2)(const Descriptor &x,
1608d672c0bSpeter klausler     const char *source, int line, int dim, const Descriptor *mask) {
1618d672c0bSpeter klausler   return GetTotalReduction<TypeCategory::Integer, 2>(x, source, line, dim, mask,
1628d672c0bSpeter klausler       IntegerXorAccumulator<CppTypeFor<TypeCategory::Integer, 4>>{x},
1638d672c0bSpeter klausler       "IPARITY");
1648d672c0bSpeter klausler }
RTNAME(IParity4)1658d672c0bSpeter klausler CppTypeFor<TypeCategory::Integer, 4> RTNAME(IParity4)(const Descriptor &x,
1668d672c0bSpeter klausler     const char *source, int line, int dim, const Descriptor *mask) {
1678d672c0bSpeter klausler   return GetTotalReduction<TypeCategory::Integer, 4>(x, source, line, dim, mask,
1688d672c0bSpeter klausler       IntegerXorAccumulator<CppTypeFor<TypeCategory::Integer, 4>>{x},
1698d672c0bSpeter klausler       "IPARITY");
1708d672c0bSpeter klausler }
RTNAME(IParity8)1718d672c0bSpeter klausler CppTypeFor<TypeCategory::Integer, 8> RTNAME(IParity8)(const Descriptor &x,
1728d672c0bSpeter klausler     const char *source, int line, int dim, const Descriptor *mask) {
1738d672c0bSpeter klausler   return GetTotalReduction<TypeCategory::Integer, 8>(x, source, line, dim, mask,
1748d672c0bSpeter klausler       IntegerXorAccumulator<CppTypeFor<TypeCategory::Integer, 8>>{x},
1758d672c0bSpeter klausler       "IPARITY");
1768d672c0bSpeter klausler }
1778d672c0bSpeter klausler #ifdef __SIZEOF_INT128__
RTNAME(IParity16)1788d672c0bSpeter klausler CppTypeFor<TypeCategory::Integer, 16> RTNAME(IParity16)(const Descriptor &x,
1798d672c0bSpeter klausler     const char *source, int line, int dim, const Descriptor *mask) {
1808d672c0bSpeter klausler   return GetTotalReduction<TypeCategory::Integer, 16>(x, source, line, dim,
1818d672c0bSpeter klausler       mask, IntegerXorAccumulator<CppTypeFor<TypeCategory::Integer, 16>>{x},
1828d672c0bSpeter klausler       "IPARITY");
1838d672c0bSpeter klausler }
1848d672c0bSpeter klausler #endif
RTNAME(IParityDim)1858d672c0bSpeter klausler void RTNAME(IParityDim)(Descriptor &result, const Descriptor &x, int dim,
1868d672c0bSpeter klausler     const char *source, int line, const Descriptor *mask) {
1878d672c0bSpeter klausler   Terminator terminator{source, line};
1888d672c0bSpeter klausler   auto catKind{x.type().GetCategoryAndKind()};
1898d672c0bSpeter klausler   RUNTIME_CHECK(terminator,
1908d672c0bSpeter klausler       catKind.has_value() && catKind->first == TypeCategory::Integer);
1918d672c0bSpeter klausler   PartialIntegerReduction<IntegerXorAccumulator>(
1928d672c0bSpeter klausler       result, x, dim, catKind->second, mask, "IPARITY", terminator);
1938d672c0bSpeter klausler }
1948d672c0bSpeter klausler }
1958d672c0bSpeter klausler 
1968d672c0bSpeter klausler // ALL, ANY, COUNT, & PARITY
197e372e0f9Speter klausler 
1988d672c0bSpeter klausler enum class LogicalReduction { All, Any, Parity };
1998d672c0bSpeter klausler 
2008d672c0bSpeter klausler template <LogicalReduction REDUCTION> class LogicalAccumulator {
201e372e0f9Speter klausler public:
202e372e0f9Speter klausler   using Type = bool;
LogicalAccumulator(const Descriptor & array)203e372e0f9Speter klausler   explicit LogicalAccumulator(const Descriptor &array) : array_{array} {}
Reinitialize()2048d672c0bSpeter klausler   void Reinitialize() { result_ = REDUCTION == LogicalReduction::All; }
Result() const205e372e0f9Speter klausler   bool Result() const { return result_; }
Accumulate(bool x)206e372e0f9Speter klausler   bool Accumulate(bool x) {
2078d672c0bSpeter klausler     if constexpr (REDUCTION == LogicalReduction::Parity) {
2088d672c0bSpeter klausler       result_ = result_ != x;
2098d672c0bSpeter klausler     } else if (x != (REDUCTION == LogicalReduction::All)) {
210e372e0f9Speter klausler       result_ = x;
211e372e0f9Speter klausler       return false;
212e372e0f9Speter klausler     }
2138d672c0bSpeter klausler     return true;
214e372e0f9Speter klausler   }
215e372e0f9Speter klausler   template <typename IGNORED = void>
AccumulateAt(const SubscriptValue at[])216e372e0f9Speter klausler   bool AccumulateAt(const SubscriptValue at[]) {
217e372e0f9Speter klausler     return Accumulate(IsLogicalElementTrue(array_, at));
218e372e0f9Speter klausler   }
219e372e0f9Speter klausler 
220e372e0f9Speter klausler private:
221e372e0f9Speter klausler   const Descriptor &array_;
2228d672c0bSpeter klausler   bool result_{REDUCTION == LogicalReduction::All};
223e372e0f9Speter klausler };
224e372e0f9Speter klausler 
225e372e0f9Speter klausler template <typename ACCUMULATOR>
GetTotalLogicalReduction(const Descriptor & x,const char * source,int line,int dim,ACCUMULATOR && accumulator,const char * intrinsic)226e372e0f9Speter klausler inline auto GetTotalLogicalReduction(const Descriptor &x, const char *source,
227e372e0f9Speter klausler     int line, int dim, ACCUMULATOR &&accumulator, const char *intrinsic) ->
228e372e0f9Speter klausler     typename ACCUMULATOR::Type {
229e372e0f9Speter klausler   Terminator terminator{source, line};
230e372e0f9Speter klausler   if (dim < 0 || dim > 1) {
231*e3550f19SPeter Steinfeld     terminator.Crash("%s: bad DIM=%d for ARRAY with rank=1", intrinsic, dim);
232e372e0f9Speter klausler   }
233e372e0f9Speter klausler   SubscriptValue xAt[maxRank];
234e372e0f9Speter klausler   x.GetLowerBounds(xAt);
235e372e0f9Speter klausler   for (auto elements{x.Elements()}; elements--; x.IncrementSubscripts(xAt)) {
236e372e0f9Speter klausler     if (!accumulator.AccumulateAt(xAt)) {
237e372e0f9Speter klausler       break; // cut short, result is known
238e372e0f9Speter klausler     }
239e372e0f9Speter klausler   }
240e372e0f9Speter klausler   return accumulator.Result();
241e372e0f9Speter klausler }
242e372e0f9Speter klausler 
243e372e0f9Speter klausler template <typename ACCUMULATOR>
ReduceLogicalDimToScalar(const Descriptor & x,int zeroBasedDim,SubscriptValue subscripts[])244e372e0f9Speter klausler inline auto ReduceLogicalDimToScalar(const Descriptor &x, int zeroBasedDim,
245e372e0f9Speter klausler     SubscriptValue subscripts[]) -> typename ACCUMULATOR::Type {
246e372e0f9Speter klausler   ACCUMULATOR accumulator{x};
247e372e0f9Speter klausler   SubscriptValue xAt[maxRank];
248e372e0f9Speter klausler   GetExpandedSubscripts(xAt, x, zeroBasedDim, subscripts);
249e372e0f9Speter klausler   const auto &dim{x.GetDimension(zeroBasedDim)};
250e372e0f9Speter klausler   SubscriptValue at{dim.LowerBound()};
251e372e0f9Speter klausler   for (auto n{dim.Extent()}; n-- > 0; ++at) {
252e372e0f9Speter klausler     xAt[zeroBasedDim] = at;
253e372e0f9Speter klausler     if (!accumulator.AccumulateAt(xAt)) {
254e372e0f9Speter klausler       break;
255e372e0f9Speter klausler     }
256e372e0f9Speter klausler   }
257e372e0f9Speter klausler   return accumulator.Result();
258e372e0f9Speter klausler }
259e372e0f9Speter klausler 
2608d672c0bSpeter klausler template <LogicalReduction REDUCTION> struct LogicalReduceHelper {
2618d672c0bSpeter klausler   template <int KIND> struct Functor {
operator ()Fortran::runtime::LogicalReduceHelper::Functor2628d672c0bSpeter klausler     void operator()(Descriptor &result, const Descriptor &x, int dim,
2638d672c0bSpeter klausler         Terminator &terminator, const char *intrinsic) const {
264e372e0f9Speter klausler       // Standard requires result to have same LOGICAL kind as argument.
2658d672c0bSpeter klausler       CreatePartialReductionResult(
2668d672c0bSpeter klausler           result, x, dim, terminator, intrinsic, x.type());
267e372e0f9Speter klausler       SubscriptValue at[maxRank];
268e372e0f9Speter klausler       result.GetLowerBounds(at);
2691dbc9b53SMark Leair       INTERNAL_CHECK(result.rank() == 0 || at[0] == 1);
270e372e0f9Speter klausler       using CppType = CppTypeFor<TypeCategory::Logical, KIND>;
271e372e0f9Speter klausler       for (auto n{result.Elements()}; n-- > 0; result.IncrementSubscripts(at)) {
272e372e0f9Speter klausler         *result.Element<CppType>(at) =
2738d672c0bSpeter klausler             ReduceLogicalDimToScalar<LogicalAccumulator<REDUCTION>>(
2748d672c0bSpeter klausler                 x, dim - 1, at);
275e372e0f9Speter klausler       }
276e372e0f9Speter klausler     }
2778d672c0bSpeter klausler   };
2788d672c0bSpeter klausler };
279e372e0f9Speter klausler 
2808d672c0bSpeter klausler template <LogicalReduction REDUCTION>
DoReduceLogicalDimension(Descriptor & result,const Descriptor & x,int dim,Terminator & terminator,const char * intrinsic)281e372e0f9Speter klausler inline void DoReduceLogicalDimension(Descriptor &result, const Descriptor &x,
282e372e0f9Speter klausler     int dim, Terminator &terminator, const char *intrinsic) {
283e372e0f9Speter klausler   auto catKind{x.type().GetCategoryAndKind()};
284e372e0f9Speter klausler   RUNTIME_CHECK(terminator, catKind && catKind->first == TypeCategory::Logical);
2858d672c0bSpeter klausler   ApplyLogicalKind<LogicalReduceHelper<REDUCTION>::template Functor, void>(
2868d672c0bSpeter klausler       catKind->second, terminator, result, x, dim, terminator, intrinsic);
287e372e0f9Speter klausler }
288e372e0f9Speter klausler 
289e372e0f9Speter klausler // COUNT
290e372e0f9Speter klausler 
291e372e0f9Speter klausler class CountAccumulator {
292e372e0f9Speter klausler public:
293e372e0f9Speter klausler   using Type = std::int64_t;
CountAccumulator(const Descriptor & array)294e372e0f9Speter klausler   explicit CountAccumulator(const Descriptor &array) : array_{array} {}
Reinitialize()2958d672c0bSpeter klausler   void Reinitialize() { result_ = 0; }
Result() const296e372e0f9Speter klausler   Type Result() const { return result_; }
297e372e0f9Speter klausler   template <typename IGNORED = void>
AccumulateAt(const SubscriptValue at[])298e372e0f9Speter klausler   bool AccumulateAt(const SubscriptValue at[]) {
299e372e0f9Speter klausler     if (IsLogicalElementTrue(array_, at)) {
300e372e0f9Speter klausler       ++result_;
301e372e0f9Speter klausler     }
302e372e0f9Speter klausler     return true;
303e372e0f9Speter klausler   }
304e372e0f9Speter klausler 
305e372e0f9Speter klausler private:
306e372e0f9Speter klausler   const Descriptor &array_;
307e372e0f9Speter klausler   Type result_{0};
308e372e0f9Speter klausler };
309e372e0f9Speter klausler 
3108d672c0bSpeter klausler template <int KIND> struct CountDimension {
operator ()Fortran::runtime::CountDimension3118d672c0bSpeter klausler   void operator()(Descriptor &result, const Descriptor &x, int dim,
3128d672c0bSpeter klausler       Terminator &terminator) const {
313e372e0f9Speter klausler     CreatePartialReductionResult(result, x, dim, terminator, "COUNT",
314e372e0f9Speter klausler         TypeCode{TypeCategory::Integer, KIND});
315e372e0f9Speter klausler     SubscriptValue at[maxRank];
316e372e0f9Speter klausler     result.GetLowerBounds(at);
3171dbc9b53SMark Leair     INTERNAL_CHECK(result.rank() == 0 || at[0] == 1);
318e372e0f9Speter klausler     using CppType = CppTypeFor<TypeCategory::Integer, KIND>;
319e372e0f9Speter klausler     for (auto n{result.Elements()}; n-- > 0; result.IncrementSubscripts(at)) {
320e372e0f9Speter klausler       *result.Element<CppType>(at) =
321e372e0f9Speter klausler           ReduceLogicalDimToScalar<CountAccumulator>(x, dim - 1, at);
322e372e0f9Speter klausler     }
323e372e0f9Speter klausler   }
3248d672c0bSpeter klausler };
325e372e0f9Speter klausler 
326e372e0f9Speter klausler extern "C" {
327e372e0f9Speter klausler 
RTNAME(All)328e372e0f9Speter klausler bool RTNAME(All)(const Descriptor &x, const char *source, int line, int dim) {
3298d672c0bSpeter klausler   return GetTotalLogicalReduction(x, source, line, dim,
3308d672c0bSpeter klausler       LogicalAccumulator<LogicalReduction::All>{x}, "ALL");
331e372e0f9Speter klausler }
RTNAME(AllDim)332e372e0f9Speter klausler void RTNAME(AllDim)(Descriptor &result, const Descriptor &x, int dim,
333e372e0f9Speter klausler     const char *source, int line) {
334e372e0f9Speter klausler   Terminator terminator{source, line};
3358d672c0bSpeter klausler   DoReduceLogicalDimension<LogicalReduction::All>(
3368d672c0bSpeter klausler       result, x, dim, terminator, "ALL");
337e372e0f9Speter klausler }
338e372e0f9Speter klausler 
RTNAME(Any)339e372e0f9Speter klausler bool RTNAME(Any)(const Descriptor &x, const char *source, int line, int dim) {
3408d672c0bSpeter klausler   return GetTotalLogicalReduction(x, source, line, dim,
3418d672c0bSpeter klausler       LogicalAccumulator<LogicalReduction::Any>{x}, "ANY");
342e372e0f9Speter klausler }
RTNAME(AnyDim)343e372e0f9Speter klausler void RTNAME(AnyDim)(Descriptor &result, const Descriptor &x, int dim,
344e372e0f9Speter klausler     const char *source, int line) {
345e372e0f9Speter klausler   Terminator terminator{source, line};
3468d672c0bSpeter klausler   DoReduceLogicalDimension<LogicalReduction::Any>(
3478d672c0bSpeter klausler       result, x, dim, terminator, "ANY");
348e372e0f9Speter klausler }
349e372e0f9Speter klausler 
RTNAME(Count)350e372e0f9Speter klausler std::int64_t RTNAME(Count)(
351e372e0f9Speter klausler     const Descriptor &x, const char *source, int line, int dim) {
352e372e0f9Speter klausler   return GetTotalLogicalReduction(
353e372e0f9Speter klausler       x, source, line, dim, CountAccumulator{x}, "COUNT");
354e372e0f9Speter klausler }
3558d672c0bSpeter klausler 
RTNAME(CountDim)356e372e0f9Speter klausler void RTNAME(CountDim)(Descriptor &result, const Descriptor &x, int dim,
357e372e0f9Speter klausler     int kind, const char *source, int line) {
358e372e0f9Speter klausler   Terminator terminator{source, line};
3598d672c0bSpeter klausler   ApplyIntegerKind<CountDimension, void>(
3608d672c0bSpeter klausler       kind, terminator, result, x, dim, terminator);
361e372e0f9Speter klausler }
3628d672c0bSpeter klausler 
RTNAME(Parity)3638d672c0bSpeter klausler bool RTNAME(Parity)(
3648d672c0bSpeter klausler     const Descriptor &x, const char *source, int line, int dim) {
3658d672c0bSpeter klausler   return GetTotalLogicalReduction(x, source, line, dim,
3668d672c0bSpeter klausler       LogicalAccumulator<LogicalReduction::Parity>{x}, "PARITY");
3678d672c0bSpeter klausler }
RTNAME(ParityDim)3688d672c0bSpeter klausler void RTNAME(ParityDim)(Descriptor &result, const Descriptor &x, int dim,
3698d672c0bSpeter klausler     const char *source, int line) {
3708d672c0bSpeter klausler   Terminator terminator{source, line};
3718d672c0bSpeter klausler   DoReduceLogicalDimension<LogicalReduction::Parity>(
3728d672c0bSpeter klausler       result, x, dim, terminator, "PARITY");
373e372e0f9Speter klausler }
374e372e0f9Speter klausler 
375e372e0f9Speter klausler } // extern "C"
376e372e0f9Speter klausler } // namespace Fortran::runtime
377