[flang] Implement runtime for IALL & IANY

We had IPARITY (xor-reduction) but I missed IALL (and)
and IANY (or).

Differential Revision: https://reviews.llvm.org/D104339

GitOrigin-RevId: fdf33771feeb23ecab25b61d37f5ad575a641a10
diff --git a/runtime/reduction.cpp b/runtime/reduction.cpp
index 73fcfa8..f5f6abf 100644
--- a/runtime/reduction.cpp
+++ b/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 <typename INTERMEDIATE> class IntegerAndAccumulator {
+public:
+  explicit IntegerAndAccumulator(const Descriptor &array) : array_{array} {}
+  void Reinitialize() { and_ = ~INTERMEDIATE{0}; }
+  template <typename A> void GetResult(A *p, int /*zeroBasedDim*/ = -1) const {
+    *p = static_cast<A>(and_);
+  }
+  template <typename A> bool AccumulateAt(const SubscriptValue at[]) {
+    and_ &= *array_.Element<A>(at);
+    return true;
+  }
+
+private:
+  const Descriptor &array_;
+  INTERMEDIATE and_{~INTERMEDIATE{0}};
+};
+
+template <typename INTERMEDIATE> class IntegerOrAccumulator {
+public:
+  explicit IntegerOrAccumulator(const Descriptor &array) : array_{array} {}
+  void Reinitialize() { or_ = 0; }
+  template <typename A> void GetResult(A *p, int /*zeroBasedDim*/ = -1) const {
+    *p = static_cast<A>(or_);
+  }
+  template <typename A> bool AccumulateAt(const SubscriptValue at[]) {
+    or_ |= *array_.Element<A>(at);
+    return true;
+  }
+
+private:
+  const Descriptor &array_;
+  INTERMEDIATE or_{0};
+};
 
 template <typename INTERMEDIATE> class IntegerXorAccumulator {
 public:
@@ -41,6 +75,82 @@
 };
 
 extern "C" {
+CppTypeFor<TypeCategory::Integer, 1> RTNAME(IAll1)(const Descriptor &x,
+    const char *source, int line, int dim, const Descriptor *mask) {
+  return GetTotalReduction<TypeCategory::Integer, 1>(x, source, line, dim, mask,
+      IntegerAndAccumulator<CppTypeFor<TypeCategory::Integer, 4>>{x}, "IALL");
+}
+CppTypeFor<TypeCategory::Integer, 2> RTNAME(IAll2)(const Descriptor &x,
+    const char *source, int line, int dim, const Descriptor *mask) {
+  return GetTotalReduction<TypeCategory::Integer, 2>(x, source, line, dim, mask,
+      IntegerAndAccumulator<CppTypeFor<TypeCategory::Integer, 4>>{x}, "IALL");
+}
+CppTypeFor<TypeCategory::Integer, 4> RTNAME(IAll4)(const Descriptor &x,
+    const char *source, int line, int dim, const Descriptor *mask) {
+  return GetTotalReduction<TypeCategory::Integer, 4>(x, source, line, dim, mask,
+      IntegerAndAccumulator<CppTypeFor<TypeCategory::Integer, 4>>{x}, "IALL");
+}
+CppTypeFor<TypeCategory::Integer, 8> RTNAME(IAll8)(const Descriptor &x,
+    const char *source, int line, int dim, const Descriptor *mask) {
+  return GetTotalReduction<TypeCategory::Integer, 8>(x, source, line, dim, mask,
+      IntegerAndAccumulator<CppTypeFor<TypeCategory::Integer, 8>>{x}, "IALL");
+}
+#ifdef __SIZEOF_INT128__
+CppTypeFor<TypeCategory::Integer, 16> RTNAME(IAll16)(const Descriptor &x,
+    const char *source, int line, int dim, const Descriptor *mask) {
+  return GetTotalReduction<TypeCategory::Integer, 16>(x, source, line, dim,
+      mask, IntegerAndAccumulator<CppTypeFor<TypeCategory::Integer, 16>>{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<IntegerAndAccumulator>(
+      result, x, dim, catKind->second, mask, "IALL", terminator);
+}
+
+CppTypeFor<TypeCategory::Integer, 1> RTNAME(IAny1)(const Descriptor &x,
+    const char *source, int line, int dim, const Descriptor *mask) {
+  return GetTotalReduction<TypeCategory::Integer, 1>(x, source, line, dim, mask,
+      IntegerOrAccumulator<CppTypeFor<TypeCategory::Integer, 4>>{x}, "IANY");
+}
+CppTypeFor<TypeCategory::Integer, 2> RTNAME(IAny2)(const Descriptor &x,
+    const char *source, int line, int dim, const Descriptor *mask) {
+  return GetTotalReduction<TypeCategory::Integer, 2>(x, source, line, dim, mask,
+      IntegerOrAccumulator<CppTypeFor<TypeCategory::Integer, 4>>{x}, "IANY");
+}
+CppTypeFor<TypeCategory::Integer, 4> RTNAME(IAny4)(const Descriptor &x,
+    const char *source, int line, int dim, const Descriptor *mask) {
+  return GetTotalReduction<TypeCategory::Integer, 4>(x, source, line, dim, mask,
+      IntegerOrAccumulator<CppTypeFor<TypeCategory::Integer, 4>>{x}, "IANY");
+}
+CppTypeFor<TypeCategory::Integer, 8> RTNAME(IAny8)(const Descriptor &x,
+    const char *source, int line, int dim, const Descriptor *mask) {
+  return GetTotalReduction<TypeCategory::Integer, 8>(x, source, line, dim, mask,
+      IntegerOrAccumulator<CppTypeFor<TypeCategory::Integer, 8>>{x}, "IANY");
+}
+#ifdef __SIZEOF_INT128__
+CppTypeFor<TypeCategory::Integer, 16> RTNAME(IAny16)(const Descriptor &x,
+    const char *source, int line, int dim, const Descriptor *mask) {
+  return GetTotalReduction<TypeCategory::Integer, 16>(x, source, line, dim,
+      mask, IntegerOrAccumulator<CppTypeFor<TypeCategory::Integer, 16>>{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<IntegerOrAccumulator>(
+      result, x, dim, catKind->second, mask, "IANY", terminator);
+}
+
 CppTypeFor<TypeCategory::Integer, 1> RTNAME(IParity1)(const Descriptor &x,
     const char *source, int line, int dim, const Descriptor *mask) {
   return GetTotalReduction<TypeCategory::Integer, 1>(x, source, line, dim, mask,
diff --git a/runtime/reduction.h b/runtime/reduction.h
index 379fcb8..a52a921 100644
--- a/runtime/reduction.h
+++ b/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/unittests/RuntimeGTest/Reduction.cpp b/unittests/RuntimeGTest/Reduction.cpp
index 4c01cf4..617131c 100644
--- a/unittests/RuntimeGTest/Reduction.cpp
+++ b/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<TypeCategory::Integer, 4>(
       std::vector<int>{2, 3}, std::vector<std::int32_t>{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) {