diff --git a/flang/runtime/reduction.h b/flang/runtime/reduction.h --- a/flang/runtime/reduction.h +++ b/flang/runtime/reduction.h @@ -141,7 +141,37 @@ void RTNAME(ProductDim)(Descriptor &result, const Descriptor &array, int dim, const char *source, int line, const Descriptor *mask = nullptr); -// IPARITY() +// IALL, IANY, IPARITY +std::int8_t RTNAME(IAll1)(const Descriptor &, const char *source, int line, + int dim = 0, const Descriptor *mask = nullptr); +std::int16_t RTNAME(IAll2)(const Descriptor &, const char *source, int line, + int dim = 0, const Descriptor *mask = nullptr); +std::int32_t RTNAME(IAll4)(const Descriptor &, const char *source, int line, + int dim = 0, const Descriptor *mask = nullptr); +std::int64_t RTNAME(IAll8)(const Descriptor &, const char *source, int line, + int dim = 0, const Descriptor *mask = nullptr); +#ifdef __SIZEOF_INT128__ +common::int128_t RTNAME(IAll16)(const Descriptor &, const char *source, + int line, int dim = 0, const Descriptor *mask = nullptr); +#endif +void RTNAME(IAllDim)(Descriptor &result, const Descriptor &array, int dim, + const char *source, int line, const Descriptor *mask = nullptr); + +std::int8_t RTNAME(IAny1)(const Descriptor &, const char *source, int line, + int dim = 0, const Descriptor *mask = nullptr); +std::int16_t RTNAME(IAny2)(const Descriptor &, const char *source, int line, + int dim = 0, const Descriptor *mask = nullptr); +std::int32_t RTNAME(IAny4)(const Descriptor &, const char *source, int line, + int dim = 0, const Descriptor *mask = nullptr); +std::int64_t RTNAME(IAny8)(const Descriptor &, const char *source, int line, + int dim = 0, const Descriptor *mask = nullptr); +#ifdef __SIZEOF_INT128__ +common::int128_t RTNAME(IAny16)(const Descriptor &, const char *source, + int line, int dim = 0, const Descriptor *mask = nullptr); +#endif +void RTNAME(IAnyDim)(Descriptor &result, const Descriptor &array, int dim, + const char *source, int line, const Descriptor *mask = nullptr); + std::int8_t RTNAME(IParity1)(const Descriptor &, const char *source, int line, int dim = 0, const Descriptor *mask = nullptr); std::int16_t RTNAME(IParity2)(const Descriptor &, const char *source, int line, diff --git a/flang/runtime/reduction.cpp b/flang/runtime/reduction.cpp --- a/flang/runtime/reduction.cpp +++ b/flang/runtime/reduction.cpp @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -// Implements ALL, ANY, COUNT, IPARITY, & PARITY for all required operand -// types and shapes. +// Implements ALL, ANY, COUNT, IALL, IANY, IPARITY, & PARITY for all required +// operand types and shapes. // // DOT_PRODUCT, FINDLOC, MATMUL, SUM, and PRODUCT are in their own eponymous // source files. @@ -21,7 +21,41 @@ namespace Fortran::runtime { -// IPARITY() +// IALL, IANY, IPARITY + +template class IntegerAndAccumulator { +public: + explicit IntegerAndAccumulator(const Descriptor &array) : array_{array} {} + void Reinitialize() { and_ = ~INTERMEDIATE{0}; } + template void GetResult(A *p, int /*zeroBasedDim*/ = -1) const { + *p = static_cast(and_); + } + template bool AccumulateAt(const SubscriptValue at[]) { + and_ &= *array_.Element(at); + return true; + } + +private: + const Descriptor &array_; + INTERMEDIATE and_{~INTERMEDIATE{0}}; +}; + +template class IntegerOrAccumulator { +public: + explicit IntegerOrAccumulator(const Descriptor &array) : array_{array} {} + void Reinitialize() { or_ = 0; } + template void GetResult(A *p, int /*zeroBasedDim*/ = -1) const { + *p = static_cast(or_); + } + template bool AccumulateAt(const SubscriptValue at[]) { + or_ |= *array_.Element(at); + return true; + } + +private: + const Descriptor &array_; + INTERMEDIATE or_{0}; +}; template class IntegerXorAccumulator { public: @@ -41,6 +75,82 @@ }; extern "C" { +CppTypeFor RTNAME(IAll1)(const Descriptor &x, + const char *source, int line, int dim, const Descriptor *mask) { + return GetTotalReduction(x, source, line, dim, mask, + IntegerAndAccumulator>{x}, "IALL"); +} +CppTypeFor RTNAME(IAll2)(const Descriptor &x, + const char *source, int line, int dim, const Descriptor *mask) { + return GetTotalReduction(x, source, line, dim, mask, + IntegerAndAccumulator>{x}, "IALL"); +} +CppTypeFor RTNAME(IAll4)(const Descriptor &x, + const char *source, int line, int dim, const Descriptor *mask) { + return GetTotalReduction(x, source, line, dim, mask, + IntegerAndAccumulator>{x}, "IALL"); +} +CppTypeFor RTNAME(IAll8)(const Descriptor &x, + const char *source, int line, int dim, const Descriptor *mask) { + return GetTotalReduction(x, source, line, dim, mask, + IntegerAndAccumulator>{x}, "IALL"); +} +#ifdef __SIZEOF_INT128__ +CppTypeFor RTNAME(IAll16)(const Descriptor &x, + const char *source, int line, int dim, const Descriptor *mask) { + return GetTotalReduction(x, source, line, dim, + mask, IntegerAndAccumulator>{x}, + "IALL"); +} +#endif +void RTNAME(IAllDim)(Descriptor &result, const Descriptor &x, int dim, + const char *source, int line, const Descriptor *mask) { + Terminator terminator{source, line}; + auto catKind{x.type().GetCategoryAndKind()}; + RUNTIME_CHECK(terminator, + catKind.has_value() && catKind->first == TypeCategory::Integer); + PartialIntegerReduction( + result, x, dim, catKind->second, mask, "IALL", terminator); +} + +CppTypeFor RTNAME(IAny1)(const Descriptor &x, + const char *source, int line, int dim, const Descriptor *mask) { + return GetTotalReduction(x, source, line, dim, mask, + IntegerOrAccumulator>{x}, "IANY"); +} +CppTypeFor RTNAME(IAny2)(const Descriptor &x, + const char *source, int line, int dim, const Descriptor *mask) { + return GetTotalReduction(x, source, line, dim, mask, + IntegerOrAccumulator>{x}, "IANY"); +} +CppTypeFor RTNAME(IAny4)(const Descriptor &x, + const char *source, int line, int dim, const Descriptor *mask) { + return GetTotalReduction(x, source, line, dim, mask, + IntegerOrAccumulator>{x}, "IANY"); +} +CppTypeFor RTNAME(IAny8)(const Descriptor &x, + const char *source, int line, int dim, const Descriptor *mask) { + return GetTotalReduction(x, source, line, dim, mask, + IntegerOrAccumulator>{x}, "IANY"); +} +#ifdef __SIZEOF_INT128__ +CppTypeFor RTNAME(IAny16)(const Descriptor &x, + const char *source, int line, int dim, const Descriptor *mask) { + return GetTotalReduction(x, source, line, dim, + mask, IntegerOrAccumulator>{x}, + "IANY"); +} +#endif +void RTNAME(IAnyDim)(Descriptor &result, const Descriptor &x, int dim, + const char *source, int line, const Descriptor *mask) { + Terminator terminator{source, line}; + auto catKind{x.type().GetCategoryAndKind()}; + RUNTIME_CHECK(terminator, + catKind.has_value() && catKind->first == TypeCategory::Integer); + PartialIntegerReduction( + result, x, dim, catKind->second, mask, "IANY", terminator); +} + CppTypeFor RTNAME(IParity1)(const Descriptor &x, const char *source, int line, int dim, const Descriptor *mask) { return GetTotalReduction(x, source, line, dim, mask, diff --git a/flang/unittests/RuntimeGTest/Reduction.cpp b/flang/unittests/RuntimeGTest/Reduction.cpp --- a/flang/unittests/RuntimeGTest/Reduction.cpp +++ b/flang/unittests/RuntimeGTest/Reduction.cpp @@ -21,11 +21,17 @@ using namespace Fortran::runtime; using Fortran::common::TypeCategory; -TEST(Reductions, SumInt4) { +TEST(Reductions, Int4Ops) { auto array{MakeArray( std::vector{2, 3}, std::vector{1, 2, 3, 4, 5, 6})}; std::int32_t sum{RTNAME(SumInteger4)(*array, __FILE__, __LINE__)}; EXPECT_EQ(sum, 21) << sum; + std::int32_t all{RTNAME(IAll4)(*array, __FILE__, __LINE__)}; + EXPECT_EQ(all, 0) << all; + std::int32_t any{RTNAME(IAny4)(*array, __FILE__, __LINE__)}; + EXPECT_EQ(any, 7) << any; + std::int32_t eor{RTNAME(IParity4)(*array, __FILE__, __LINE__)}; + EXPECT_EQ(eor, 7) << eor; } TEST(Reductions, DimMaskProductInt4) {