[flang-commits] [flang] [flang][runtime] Runtime support for REDUCE() (PR #86214)

via flang-commits flang-commits at lists.llvm.org
Thu Mar 21 16:21:07 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-flang-runtime

Author: Peter Klausler (klausler)

<details>
<summary>Changes</summary>

Supports the REDUCE() transformational intrinsic function of Fortran (see F'2023 16.9.173) in a manner similar to the existing support for SUM(), PRODUCT(), &c.  There are APIs for total reductions to scalar results, and APIs for partial reductions that reduce the rank of the argument by one.

This implementation requires more functions than other reductions because the various possible types of the user-supplied OPERATION= function need to be elaborated.

Once the basic API in reduce.h has been approved, later patches will implement lowering.

REDUCE() is primarily for completeness, not portability; only one other Fortran compiler implements this F'2018 feature today, and only some types work correctly with it.

---

Patch is 50.19 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/86214.diff


10 Files Affected:

- (added) flang/include/flang/Runtime/reduce.h (+254) 
- (modified) flang/lib/Semantics/check-call.cpp (+3) 
- (modified) flang/runtime/CMakeLists.txt (+1) 
- (modified) flang/runtime/complex-reduction.c (+22) 
- (modified) flang/runtime/complex-reduction.h (+45) 
- (added) flang/runtime/reduce.cpp (+526) 
- (modified) flang/runtime/reduction-templates.h (+13-33) 
- (modified) flang/runtime/tools.cpp (+29) 
- (modified) flang/runtime/tools.h (+4) 
- (modified) flang/unittests/Runtime/Reduction.cpp (+37) 


``````````diff
diff --git a/flang/include/flang/Runtime/reduce.h b/flang/include/flang/Runtime/reduce.h
new file mode 100644
index 00000000000000..f314129f6e9351
--- /dev/null
+++ b/flang/include/flang/Runtime/reduce.h
@@ -0,0 +1,254 @@
+//===-- include/flang/Runtime/reduce.h --------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// Defines the API for implementations of the transformational intrinsic
+// functionREDUCE(); see F'2023 16.9.173.
+//
+// Similar to the definition of the APIs for SUM(), &c., in reduction.h,
+// there are typed functions here like ReduceInteger4() for total reductions
+// to scalars and void functions like ReduceInteger4Dim() for partial
+// reductions to smaller arrays.
+
+#ifndef FORTRAN_RUNTIME_REDUCE_H_
+#define FORTRAN_RUNTIME_REDUCE_H_
+
+#include "flang/Common/float128.h"
+#include "flang/Common/uint128.h"
+#include "flang/Runtime/cpp-type.h"
+#include "flang/Runtime/entry-names.h"
+#include <complex>
+#include <cstdint>
+
+namespace Fortran::runtime {
+
+class Descriptor;
+
+template <typename T> using ReductionOperation = T (*)(const T *, const T *);
+template <typename CHAR>
+using ReductionCharOperation = void (*)(CHAR *hiddenResult, const CHAR *x,
+    const CHAR *y, std::size_t resultLen, std::size_t xLen, std::size_t yLen);
+using ReductionDerivedTypeOperation = void (*)(
+    void *hiddenResult, const void *x, const void *y);
+
+extern "C" {
+
+std::int8_t RTDECL(ReduceInteger1)(const Descriptor &,
+    ReductionOperation<std::int8_t>, const char *source, int line, int dim = 0,
+    const Descriptor *mask = nullptr, const std::int8_t *identity = nullptr,
+    bool ordered = true);
+void RTDECL(ReduceInteger1Dim)(Descriptor &result, const Descriptor &array,
+    ReductionOperation<std::int8_t>, const char *source, int line, int dim,
+    const Descriptor *mask = nullptr, const std::int8_t *identity = nullptr,
+    bool ordered = true);
+std::int16_t RTDECL(ReduceInteger2)(const Descriptor &,
+    ReductionOperation<std::int16_t>, const char *source, int line, int dim = 0,
+    const Descriptor *mask = nullptr, const std::int16_t *identity = nullptr,
+    bool ordered = true);
+void RTDECL(ReduceInteger2Dim)(Descriptor &result, const Descriptor &array,
+    ReductionOperation<std::int16_t>, const char *source, int line, int dim,
+    const Descriptor *mask = nullptr, const std::int16_t *identity = nullptr,
+    bool ordered = true);
+std::int32_t RTDECL(ReduceInteger4)(const Descriptor &,
+    ReductionOperation<std::int32_t>, const char *source, int line, int dim = 0,
+    const Descriptor *mask = nullptr, const std::int32_t *identity = nullptr,
+    bool ordered = true);
+void RTDECL(ReduceInteger4Dim)(Descriptor &result, const Descriptor &array,
+    ReductionOperation<std::int32_t>, const char *source, int line, int dim,
+    const Descriptor *mask = nullptr, const std::int32_t *identity = nullptr,
+    bool ordered = true);
+std::int64_t RTDECL(ReduceInteger8)(const Descriptor &,
+    ReductionOperation<std::int64_t>, const char *source, int line, int dim = 0,
+    const Descriptor *mask = nullptr, const std::int64_t *identity = nullptr,
+    bool ordered = true);
+void RTDECL(ReduceInteger8Dim)(Descriptor &result, const Descriptor &array,
+    ReductionOperation<std::int64_t>, const char *source, int line, int dim,
+    const Descriptor *mask = nullptr, const std::int64_t *identity = nullptr,
+    bool ordered = true);
+#ifdef __SIZEOF_INT128__
+common::int128_t RTDECL(ReduceInteger16)(const Descriptor &,
+    ReductionOperation<common::int128_t>, const char *source, int line,
+    int dim = 0, const Descriptor *mask = nullptr,
+    const common::int128_t *identity = nullptr, bool ordered = true);
+void RTDECL(ReduceInteger16Dim)(Descriptor &result, const Descriptor &array,
+    ReductionOperation<common::int128_t>, const char *source, int line, int dim,
+    const Descriptor *mask = nullptr,
+    const common::int128_t *identity = nullptr, bool ordered = true);
+#endif
+
+// REAL/COMPLEX(2 & 3) return 32-bit float results for the caller to downconvert
+float RTDECL(ReduceReal2)(const Descriptor &, ReductionOperation<float>,
+    const char *source, int line, int dim = 0, const Descriptor *mask = nullptr,
+    const float *identity = nullptr, bool ordered = true);
+void RTDECL(ReduceReal2Dim)(Descriptor &result, const Descriptor &array,
+    ReductionOperation<float>, const char *source, int line, int dim,
+    const Descriptor *mask = nullptr, const float *identity = nullptr,
+    bool ordered = true);
+float RTDECL(ReduceReal3)(const Descriptor &, ReductionOperation<float>,
+    const char *source, int line, int dim = 0, const Descriptor *mask = nullptr,
+    const float *identity = nullptr, bool ordered = true);
+void RTDECL(ReduceReal3Dim)(Descriptor &result, const Descriptor &array,
+    ReductionOperation<float>, const char *source, int line, int dim,
+    const Descriptor *mask = nullptr, const float *identity = nullptr,
+    bool ordered = true);
+float RTDECL(ReduceReal4)(const Descriptor &, ReductionOperation<float>,
+    const char *source, int line, int dim = 0, const Descriptor *mask = nullptr,
+    const float *identity = nullptr, bool ordered = true);
+void RTDECL(ReduceReal4Dim)(Descriptor &result, const Descriptor &array,
+    ReductionOperation<float>, const char *source, int line, int dim,
+    const Descriptor *mask = nullptr, const float *identity = nullptr,
+    bool ordered = true);
+double RTDECL(ReduceReal8)(const Descriptor &, ReductionOperation<double>,
+    const char *source, int line, int dim = 0, const Descriptor *mask = nullptr,
+    const double *identity = nullptr, bool ordered = true);
+void RTDECL(ReduceReal8Dim)(Descriptor &result, const Descriptor &array,
+    ReductionOperation<double>, const char *source, int line, int dim,
+    const Descriptor *mask = nullptr, const double *identity = nullptr,
+    bool ordered = true);
+#if LDBL_MANT_DIG == 64
+long double RTDECL(ReduceReal10)(const Descriptor &,
+    ReductionOperation<long double>, const char *source, int line, int dim = 0,
+    const Descriptor *mask = nullptr, const long double *identity = nullptr,
+    bool ordered = true);
+void RTDECL(ReduceReal10Dim)(Descriptor &result, const Descriptor &array,
+    ReductionOperation<long double>, const char *source, int line, int dim,
+    const Descriptor *mask = nullptr, const long double *identity = nullptr,
+    bool ordered = true);
+#endif
+#if LDBL_MANT_DIG == 113 || HAS_FLOAT128
+CppFloat128Type RTDECL(ReduceReal16)(const Descriptor &,
+    ReductionOperation<CppFloat128Type>, const char *source, int line,
+    int dim = 0, const Descriptor *mask = nullptr,
+    const CppFloat128Type *identity = nullptr, bool ordered = true);
+void RTDECL(ReduceReal16Dim)(Descriptor &result, const Descriptor &array,
+    ReductionOperation<CppFloat128Type>, const char *source, int line, int dim,
+    const Descriptor *mask = nullptr, const CppFloat128Type *identity = nullptr,
+    bool ordered = true);
+#endif
+
+void RTDECL(CppReduceComplex2)(std::complex<float> &, const Descriptor &,
+    ReductionOperation<std::complex<float>>, const char *source, int line,
+    int dim = 0, const Descriptor *mask = nullptr,
+    const std::complex<float> *identity = nullptr, bool ordered = true);
+void RTDECL(CppReduceComplex2Dim)(Descriptor &result, const Descriptor &array,
+    ReductionOperation<std::complex<float>>, const char *source, int line,
+    int dim, const Descriptor *mask = nullptr,
+    const std::complex<float> *identity = nullptr, bool ordered = true);
+void RTDECL(CppReduceComplex3)(std::complex<float> &, const Descriptor &,
+    ReductionOperation<std::complex<float>>, const char *source, int line,
+    int dim = 0, const Descriptor *mask = nullptr,
+    const std::complex<float> *identity = nullptr, bool ordered = true);
+void RTDECL(CppReduceComplex3Dim)(Descriptor &result, const Descriptor &array,
+    ReductionOperation<std::complex<float>>, const char *source, int line,
+    int dim, const Descriptor *mask = nullptr,
+    const std::complex<float> *identity = nullptr, bool ordered = true);
+void RTDECL(CppReduceComplex4)(std::complex<float> &, const Descriptor &,
+    ReductionOperation<std::complex<float>>, const char *source, int line,
+    int dim = 0, const Descriptor *mask = nullptr,
+    const std::complex<float> *identity = nullptr, bool ordered = true);
+void RTDECL(CppReduceComplex4Dim)(Descriptor &result, const Descriptor &array,
+    ReductionOperation<std::complex<float>>, const char *source, int line,
+    int dim, const Descriptor *mask = nullptr,
+    const std::complex<float> *identity = nullptr, bool ordered = true);
+void RTDECL(CppReduceComplex8)(std::complex<double> &, const Descriptor &,
+    ReductionOperation<std::complex<double>>, const char *source, int line,
+    int dim = 0, const Descriptor *mask = nullptr,
+    const std::complex<double> *identity = nullptr, bool ordered = true);
+void RTDECL(CppReduceComplex8Dim)(Descriptor &result, const Descriptor &array,
+    ReductionOperation<std::complex<double>>, const char *source, int line,
+    int dim, const Descriptor *mask = nullptr,
+    const std::complex<double> *identity = nullptr, bool ordered = true);
+void RTDECL(CppReduceComplex10)(std::complex<long double> &, const Descriptor &,
+    ReductionOperation<std::complex<long double>>, const char *source, int line,
+    int dim = 0, const Descriptor *mask = nullptr,
+    const std::complex<long double> *identity = nullptr, bool ordered = true);
+void RTDECL(CppReduceComplex10Dim)(Descriptor &result, const Descriptor &array,
+    ReductionOperation<std::complex<long double>>, const char *source, int line,
+    int dim, const Descriptor *mask = nullptr,
+    const std::complex<long double> *identity = nullptr, bool ordered = true);
+#if LDBL_MANT_DIG == 113 || HAS_FLOAT128
+void RTDECL(CppReduceComplex16)(std::complex<CppFloat128Type> &,
+    const Descriptor &, ReductionOperation<std::complex<CppFloat128Type>>,
+    const char *source, int line, int dim = 0, const Descriptor *mask = nullptr,
+    const std::complex<CppFloat128Type> *identity = nullptr,
+    bool ordered = true);
+void RTDECL(CppReduceComplex16Dim)(Descriptor &result, const Descriptor &array,
+    ReductionOperation<std::complex<CppFloat128Type>>, const char *source,
+    int line, int dim, const Descriptor *mask = nullptr,
+    const std::complex<CppFloat128Type> *identity = nullptr,
+    bool ordered = true);
+#endif
+
+bool RTDECL(ReduceLogical1)(const Descriptor &, ReductionOperation<std::int8_t>,
+    const char *source, int line, int dim = 0, const Descriptor *mask = nullptr,
+    const std::int8_t *identity = nullptr, bool ordered = true);
+void RTDECL(ReduceLogical1Dim)(Descriptor &result, const Descriptor &array,
+    ReductionOperation<std::int8_t>, const char *source, int line, int dim,
+    const Descriptor *mask = nullptr, const std::int8_t *identity = nullptr,
+    bool ordered = true);
+bool RTDECL(ReduceLogical2)(const Descriptor &,
+    ReductionOperation<std::int16_t>, const char *source, int line, int dim = 0,
+    const Descriptor *mask = nullptr, const std::int16_t *identity = nullptr,
+    bool ordered = true);
+void RTDECL(ReduceLogical2Dim)(Descriptor &result, const Descriptor &array,
+    ReductionOperation<std::int16_t>, const char *source, int line, int dim,
+    const Descriptor *mask = nullptr, const std::int16_t *identity = nullptr,
+    bool ordered = true);
+bool RTDECL(ReduceLogical4)(const Descriptor &,
+    ReductionOperation<std::int32_t>, const char *source, int line, int dim = 0,
+    const Descriptor *mask = nullptr, const std::int32_t *identity = nullptr,
+    bool ordered = true);
+void RTDECL(ReduceLogical4Dim)(Descriptor &result, const Descriptor &array,
+    ReductionOperation<std::int32_t>, const char *source, int line, int dim,
+    const Descriptor *mask = nullptr, const std::int32_t *identity = nullptr,
+    bool ordered = true);
+bool RTDECL(ReduceLogical8)(const Descriptor &,
+    ReductionOperation<std::int64_t>, const char *source, int line, int dim = 0,
+    const Descriptor *mask = nullptr, const std::int64_t *identity = nullptr,
+    bool ordered = true);
+void RTDECL(ReduceLogical8Dim)(Descriptor &result, const Descriptor &array,
+    ReductionOperation<std::int64_t>, const char *source, int line, int dim,
+    const Descriptor *mask = nullptr, const std::int64_t *identity = nullptr,
+    bool ordered = true);
+
+void RTDECL(ReduceChar1)(char *result, const Descriptor &array,
+    ReductionCharOperation<char>, const char *source, int line, int dim = 0,
+    const Descriptor *mask = nullptr, const char *identity = nullptr,
+    bool ordered = true);
+void RTDECL(ReduceCharacter1Dim)(Descriptor &result, const Descriptor &array,
+    ReductionCharOperation<char>, const char *source, int line, int dim,
+    const Descriptor *mask = nullptr, const char *identity = nullptr,
+    bool ordered = true);
+void RTDECL(ReduceChar2)(char16_t *result, const Descriptor &array,
+    ReductionCharOperation<char16_t>, const char *source, int line, int dim = 0,
+    const Descriptor *mask = nullptr, const char16_t *identity = nullptr,
+    bool ordered = true);
+void RTDECL(ReduceCharacter2Dim)(Descriptor &result, const Descriptor &array,
+    ReductionCharOperation<char16_t>, const char *source, int line, int dim,
+    const Descriptor *mask = nullptr, const char16_t *identity = nullptr,
+    bool ordered = true);
+void RTDECL(ReduceChar4)(char32_t *result, const Descriptor &array,
+    ReductionCharOperation<char32_t>, const char *source, int line, int dim = 0,
+    const Descriptor *mask = nullptr, const char32_t *identity = nullptr,
+    bool ordered = true);
+void RTDECL(ReduceCharacter4Dim)(Descriptor &result, const Descriptor &array,
+    ReductionCharOperation<char32_t>, const char *source, int line, int dim,
+    const Descriptor *mask = nullptr, const char32_t *identity = nullptr,
+    bool ordered = true);
+
+void RTDECL(ReduceDerivedType)(char *result, const Descriptor &array,
+    ReductionDerivedTypeOperation, const char *source, int line, int dim = 0,
+    const Descriptor *mask = nullptr, const char *identity = nullptr,
+    bool ordered = true);
+void RTDECL(ReduceDerivedTypeDim)(Descriptor &result, const Descriptor &array,
+    ReductionDerivedTypeOperation, const char *source, int line, int dim,
+    const Descriptor *mask = nullptr, const char *identity = nullptr,
+    bool ordered = true);
+
+} // extern "C"
+} // namespace Fortran::runtime
+#endif // FORTRAN_RUNTIME_REDUCE_H_
diff --git a/flang/lib/Semantics/check-call.cpp b/flang/lib/Semantics/check-call.cpp
index d625f8c2f7fc11..51a16ee155fabb 100644
--- a/flang/lib/Semantics/check-call.cpp
+++ b/flang/lib/Semantics/check-call.cpp
@@ -1588,6 +1588,9 @@ static void CheckReduce(
       procChars->dummyArguments.size() != 2 || !procChars->functionResult) {
     messages.Say(
         "OPERATION= argument of REDUCE() must be a pure function of two data arguments"_err_en_US);
+  } else if (procChars->attrs.test(characteristics::Procedure::Attr::BindC)) {
+    messages.Say(
+        "A BIND(C) OPERATION= argument of REDUCE() is not supported"_err_en_US);
   } else if (!result || result->Rank() != 0) {
     messages.Say(
         "OPERATION= argument of REDUCE() must be a scalar function"_err_en_US);
diff --git a/flang/runtime/CMakeLists.txt b/flang/runtime/CMakeLists.txt
index 7dd60b5edcd5fb..55986e190ac1b7 100644
--- a/flang/runtime/CMakeLists.txt
+++ b/flang/runtime/CMakeLists.txt
@@ -151,6 +151,7 @@ set(sources
   product.cpp
   ragged.cpp
   random.cpp
+  reduce.cpp
   reduction.cpp
   stat.cpp
   stop.cpp
diff --git a/flang/runtime/complex-reduction.c b/flang/runtime/complex-reduction.c
index c91d1253991176..7654de8080a152 100644
--- a/flang/runtime/complex-reduction.c
+++ b/flang/runtime/complex-reduction.c
@@ -155,3 +155,25 @@ ADAPT_REDUCTION(DotProductComplex10, long_double_Complex_t,
 ADAPT_REDUCTION(DotProductComplex16, CFloat128ComplexType, CppComplexFloat128,
     CMPLXF128, DOT_PRODUCT_ARGS, DOT_PRODUCT_ARG_NAMES)
 #endif
+
+/* REDUCE() */
+#define RARGS REDUCE_ARGS(float_Complex_t)
+ADAPT_REDUCTION(ReduceComplex4, float_Complex_t, CppComplexFloat, CMPLXF, RARGS,
+    REDUCE_ARG_NAMES)
+#undef RARGS
+#define RARGS REDUCE_ARGS(double_Complex_t)
+ADAPT_REDUCTION(ReduceComplex8, double_Complex_t, CppComplexDouble, CMPLX,
+    RARGS, REDUCE_ARG_NAMES)
+#undef RARGS
+#if LDBL_MANT_DIG == 64
+#define RARGS REDUCE_ARGS(long_double_Complex_t)
+ADAPT_REDUCTION(ReduceComplex10, long_double_Complex_t, CppComplexLongDouble,
+    CMPLXL, RARGS, REDUCE_ARG_NAMES)
+#undef RARGS
+#endif
+#if LDBL_MANT_DIG == 113 || HAS_FLOAT128
+#define RARGS REDUCE_ARGS(CFloat128ComplexType)
+ADAPT_REDUCTION(ReduceComplex16, CFloat128ComplexType, CppComplexFloat128,
+    CMPLXF128, RARGS, REDUCE_ARG_NAMES)
+#undef RARGS
+#endif
diff --git a/flang/runtime/complex-reduction.h b/flang/runtime/complex-reduction.h
index 1d37b235d5194b..98b20d1e592be8 100644
--- a/flang/runtime/complex-reduction.h
+++ b/flang/runtime/complex-reduction.h
@@ -69,4 +69,49 @@ long_double_Complex_t RTNAME(DotProductComplex10)(DOT_PRODUCT_ARGS);
 CFloat128ComplexType RTNAME(DotProductComplex16)(DOT_PRODUCT_ARGS);
 #endif
 
+#define REDUCE_ARGS(T) \
+  T##_op operation, const struct CppDescriptor *x, \
+      const struct CppDescriptor *y, const char *source, int line, \
+      int dim /*=0*/, const struct CppDescriptor *mask /*=NULL*/, \
+      const T *identity /*=NULL*/, _Bool ordered /*=true*/
+#define REDUCE_ARG_NAMES \
+  operation, x, y, source, line, dim, mask, identity, ordered
+
+typedef float_Complex_t (*float_Complex_t_op)(
+    const float_Complex_t *, const float_Complex_t *);
+typedef double_Complex_t (*double_Complex_t_op)(
+    const double_Complex_t *, const double_Complex_t *);
+typedef long_double_Complex_t (*long_double_Complex_t_op)(
+    const long_double_Complex_t *, const long_double_Complex_t *);
+
+float_Complex_t RTNAME(ReduceComplex2)(REDUCE_ARGS(float_Complex_t));
+float_Complex_t RTNAME(ReduceComplex3)(REDUCE_ARGS(float_Complex_t));
+float_Complex_t RTNAME(ReduceComplex4)(REDUCE_ARGS(float_Complex_t));
+double_Complex_t RTNAME(ReduceComplex8)(REDUCE_ARGS(double_Complex_t));
+long_double_Complex_t RTNAME(ReduceComplex10)(
+    REDUCE_ARGS(long_double_Complex_t));
+#if LDBL_MANT_DIG == 113 || HAS_FLOAT128
+typedef CFloat128ComplexType (*CFloat128ComplexType_op)(
+    const CFloat128ComplexType *, const CFloat128ComplexType *);
+CFloat128ComplexType RTNAME(ReduceComplex16)(REDUCE_ARGS(CFloat128ComplexType));
+#endif
+
+#define REDUCE_DIM_ARGS(T) \
+  struct CppDescriptor *result, T##_op operation, \
+      const struct CppDescriptor *x, const struct CppDescriptor *y, \
+      const char *source, int line, int dim, \
+      const struct CppDescriptor *mask /*=NULL*/, const T *identity /*=NULL*/, \
+      _Bool ordered /*=true*/
+#define REDUCE_DIM_ARG_NAMES \
+  result, operation, x, y, source, line, dim, mask, identity, ordered
+
+void RTNAME(ReduceComplex2Dim)(REDUCE_DIM_ARGS(float_Complex_t));
+void RTNAME(ReduceComplex3Dim)(REDUCE_DIM_ARGS(float_Complex_t));
+void RTNAME(ReduceComplex4Dim)(REDUCE_DIM_ARGS(float_Complex_t));
+void RTNAME(ReduceComplex8Dim)(REDUCE_DIM_ARGS(double_Complex_t));
+void RTNAME(ReduceComplex10Dim)(REDUCE_DIM_ARGS(long_double_Complex_t));
+#if LDBL_MANT_DIG == 113 || HAS_FLOAT128
+void RTNAME(ReduceComplex16Dim)(REDUCE_DIM_ARGS(CFloat128ComplexType));
+#endif
+
 #endif // FORTRAN_RUNTIME_COMPLEX_REDUCTION_H_
diff --git a/flang/runtime/reduce.cpp b/flang/runtime/reduce.cpp
new file mode 100644
index 00000000000000..da2dcd5a193a9b
--- /dev/null
+++ b/flang/runtime/reduce.cpp
@@ -0,0 +1,526 @@
+//===-- runtime/reduce.cpp ------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REDUCE() implementation
+
+#include "flang/Runtime/reduce.h"
+#incl...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/86214


More information about the flang-commits mailing list