xref: /llvm-project/flang/runtime/reduction.cpp (revision fc97d2e68b03bc2979395e84b645e5b3ba35aecd)
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