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