//===-- 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" #include "reduction-templates.h" #include "terminator.h" #include "tools.h" #include "flang/Runtime/descriptor.h" namespace Fortran::runtime { template class ReduceAccumulator { public: RT_API_ATTRS ReduceAccumulator(const Descriptor &array, ReductionOperation operation, const T *identity, Terminator &terminator) : array_{array}, operation_{operation}, identity_{identity}, terminator_{terminator} {} RT_API_ATTRS void Reinitialize() { result_.reset(); } template RT_API_ATTRS bool AccumulateAt(const SubscriptValue at[]) { const auto *operand{array_.Element(at)}; if (result_) { result_ = operation_(&*result_, operand); } else { result_ = *operand; } return true; } template RT_API_ATTRS void GetResult(A *to, int /*zeroBasedDim*/ = -1) { if (result_) { *to = *result_; } else if (identity_) { *to = *identity_; } else { terminator_.Crash("REDUCE() without IDENTITY= has no result"); } } private: const Descriptor &array_; common::optional result_; ReductionOperation operation_; const T *identity_{nullptr}; Terminator &terminator_; }; template class BufferedReduceAccumulator { public: RT_API_ATTRS BufferedReduceAccumulator(const Descriptor &array, OP operation, const T *identity, Terminator &terminator) : array_{array}, operation_{operation}, identity_{identity}, terminator_{terminator} {} RT_API_ATTRS void Reinitialize() { activeTemp_ = -1; } template RT_API_ATTRS bool AccumulateAt(const SubscriptValue at[]) { const auto *operand{array_.Element(at)}; if (activeTemp_ >= 0) { if constexpr (hasLength) { operation_(&*temp_[1 - activeTemp_], length_, &*temp_[activeTemp_], operand, length_, length_); } else { operation_(&*temp_[1 - activeTemp_], &*temp_[activeTemp_], operand); } activeTemp_ = 1 - activeTemp_; } else { activeTemp_ = 0; std::memcpy(&*temp_[activeTemp_], operand, elementBytes_); } return true; } template RT_API_ATTRS void GetResult(A *to, int /*zeroBasedDim*/ = -1) { if (activeTemp_ >= 0) { std::memcpy(to, &*temp_[activeTemp_], elementBytes_); } else if (identity_) { std::memcpy(to, identity_, elementBytes_); } else { terminator_.Crash("REDUCE() without IDENTITY= has no result"); } } private: const Descriptor &array_; OP operation_; const T *identity_{nullptr}; Terminator &terminator_; std::size_t elementBytes_{array_.ElementBytes()}; OwningPtr temp_[2]{SizedNew{terminator_}(elementBytes_), SizedNew{terminator_}(elementBytes_)}; int activeTemp_{-1}; std::size_t length_{elementBytes_ / sizeof(T)}; }; extern "C" { RT_EXT_API_GROUP_BEGIN std::int8_t RTDEF(ReduceInteger1)(const Descriptor &array, ReductionOperation operation, const char *source, int line, int dim, const Descriptor *mask, const std::int8_t *identity, bool ordered) { Terminator terminator{source, line}; return GetTotalReduction(array, source, line, dim, mask, ReduceAccumulator{array, operation, identity, terminator}, "REDUCE"); } void RTDEF(ReduceInteger1Dim)(Descriptor &result, const Descriptor &array, ReductionOperation operation, const char *source, int line, int dim, const Descriptor *mask, const std::int8_t *identity, bool ordered) { Terminator terminator{source, line}; using Accumulator = ReduceAccumulator; Accumulator accumulator{array, operation, identity, terminator}; PartialReduction(result, array, array.ElementBytes(), dim, mask, terminator, "REDUCE", accumulator); } std::int16_t RTDEF(ReduceInteger2)(const Descriptor &array, ReductionOperation operation, const char *source, int line, int dim, const Descriptor *mask, const std::int16_t *identity, bool ordered) { Terminator terminator{source, line}; return GetTotalReduction(array, source, line, dim, mask, ReduceAccumulator{array, operation, identity, terminator}, "REDUCE"); } void RTDEF(ReduceInteger2Dim)(Descriptor &result, const Descriptor &array, ReductionOperation operation, const char *source, int line, int dim, const Descriptor *mask, const std::int16_t *identity, bool ordered) { Terminator terminator{source, line}; using Accumulator = ReduceAccumulator; Accumulator accumulator{array, operation, identity, terminator}; PartialReduction(result, array, array.ElementBytes(), dim, mask, terminator, "REDUCE", accumulator); } std::int32_t RTDEF(ReduceInteger4)(const Descriptor &array, ReductionOperation operation, const char *source, int line, int dim, const Descriptor *mask, const std::int32_t *identity, bool ordered) { Terminator terminator{source, line}; return GetTotalReduction(array, source, line, dim, mask, ReduceAccumulator{array, operation, identity, terminator}, "REDUCE"); } void RTDEF(ReduceInteger4Dim)(Descriptor &result, const Descriptor &array, ReductionOperation operation, const char *source, int line, int dim, const Descriptor *mask, const std::int32_t *identity, bool ordered) { Terminator terminator{source, line}; using Accumulator = ReduceAccumulator; Accumulator accumulator{array, operation, identity, terminator}; PartialReduction(result, array, array.ElementBytes(), dim, mask, terminator, "REDUCE", accumulator); } std::int64_t RTDEF(ReduceInteger8)(const Descriptor &array, ReductionOperation operation, const char *source, int line, int dim, const Descriptor *mask, const std::int64_t *identity, bool ordered) { Terminator terminator{source, line}; return GetTotalReduction(array, source, line, dim, mask, ReduceAccumulator{array, operation, identity, terminator}, "REDUCE"); } void RTDEF(ReduceInteger8Dim)(Descriptor &result, const Descriptor &array, ReductionOperation operation, const char *source, int line, int dim, const Descriptor *mask, const std::int64_t *identity, bool ordered) { Terminator terminator{source, line}; using Accumulator = ReduceAccumulator; Accumulator accumulator{array, operation, identity, terminator}; PartialReduction(result, array, array.ElementBytes(), dim, mask, terminator, "REDUCE", accumulator); } #ifdef __SIZEOF_INT128__ common::int128_t RTDEF(ReduceInteger16)(const Descriptor &array, ReductionOperation operation, const char *source, int line, int dim, const Descriptor *mask, const common::int128_t *identity, bool ordered) { Terminator terminator{source, line}; return GetTotalReduction(array, source, line, dim, mask, ReduceAccumulator{ array, operation, identity, terminator}, "REDUCE"); } void RTDEF(ReduceInteger16Dim)(Descriptor &result, const Descriptor &array, ReductionOperation operation, const char *source, int line, int dim, const Descriptor *mask, const common::int128_t *identity, bool ordered) { Terminator terminator{source, line}; using Accumulator = ReduceAccumulator; Accumulator accumulator{array, operation, identity, terminator}; PartialReduction(result, array, array.ElementBytes(), dim, mask, terminator, "REDUCE", accumulator); } #endif // TODO: real/complex(2 & 3) float RTDEF(ReduceReal4)(const Descriptor &array, ReductionOperation operation, const char *source, int line, int dim, const Descriptor *mask, const float *identity, bool ordered) { Terminator terminator{source, line}; return GetTotalReduction(array, source, line, dim, mask, ReduceAccumulator{array, operation, identity, terminator}, "REDUCE"); } void RTDEF(ReduceReal4Dim)(Descriptor &result, const Descriptor &array, ReductionOperation operation, const char *source, int line, int dim, const Descriptor *mask, const float *identity, bool ordered) { Terminator terminator{source, line}; using Accumulator = ReduceAccumulator; Accumulator accumulator{array, operation, identity, terminator}; PartialReduction(result, array, array.ElementBytes(), dim, mask, terminator, "REDUCE", accumulator); } double RTDEF(ReduceReal8)(const Descriptor &array, ReductionOperation operation, const char *source, int line, int dim, const Descriptor *mask, const double *identity, bool ordered) { Terminator terminator{source, line}; return GetTotalReduction(array, source, line, dim, mask, ReduceAccumulator{array, operation, identity, terminator}, "REDUCE"); } void RTDEF(ReduceReal8Dim)(Descriptor &result, const Descriptor &array, ReductionOperation operation, const char *source, int line, int dim, const Descriptor *mask, const double *identity, bool ordered) { Terminator terminator{source, line}; using Accumulator = ReduceAccumulator; Accumulator accumulator{array, operation, identity, terminator}; PartialReduction(result, array, array.ElementBytes(), dim, mask, terminator, "REDUCE", accumulator); } #if LDBL_MANT_DIG == 64 long double RTDEF(ReduceReal10)(const Descriptor &array, ReductionOperation operation, const char *source, int line, int dim, const Descriptor *mask, const long double *identity, bool ordered) { Terminator terminator{source, line}; return GetTotalReduction(array, source, line, dim, mask, ReduceAccumulator{array, operation, identity, terminator}, "REDUCE"); } void RTDEF(ReduceReal10Dim)(Descriptor &result, const Descriptor &array, ReductionOperation operation, const char *source, int line, int dim, const Descriptor *mask, const long double *identity, bool ordered) { Terminator terminator{source, line}; using Accumulator = ReduceAccumulator; Accumulator accumulator{array, operation, identity, terminator}; PartialReduction(result, array, array.ElementBytes(), dim, mask, terminator, "REDUCE", accumulator); } #endif #if LDBL_MANT_DIG == 113 || HAS_FLOAT128 CppFloat128Type RTDEF(ReduceReal16)(const Descriptor &array, ReductionOperation operation, const char *source, int line, int dim, const Descriptor *mask, const CppFloat128Type *identity, bool ordered) { Terminator terminator{source, line}; return GetTotalReduction(array, source, line, dim, mask, ReduceAccumulator{ array, operation, identity, terminator}, "REDUCE"); } void RTDEF(ReduceReal16Dim)(Descriptor &result, const Descriptor &array, ReductionOperation operation, const char *source, int line, int dim, const Descriptor *mask, const CppFloat128Type *identity, bool ordered) { Terminator terminator{source, line}; using Accumulator = ReduceAccumulator; Accumulator accumulator{array, operation, identity, terminator}; PartialReduction(result, array, array.ElementBytes(), dim, mask, terminator, "REDUCE", accumulator); } #endif void RTDEF(CppReduceComplex4)(std::complex &result, const Descriptor &array, ReductionOperation> operation, const char *source, int line, int dim, const Descriptor *mask, const std::complex *identity, bool ordered) { Terminator terminator{source, line}; result = GetTotalReduction(array, source, line, dim, mask, ReduceAccumulator>{ array, operation, identity, terminator}, "REDUCE"); } void RTDEF(CppReduceComplex4Dim)(Descriptor &result, const Descriptor &array, ReductionOperation> operation, const char *source, int line, int dim, const Descriptor *mask, const std::complex *identity, bool ordered) { Terminator terminator{source, line}; using Accumulator = ReduceAccumulator>; Accumulator accumulator{array, operation, identity, terminator}; PartialReduction(result, array, array.ElementBytes(), dim, mask, terminator, "REDUCE", accumulator); } void RTDEF(CppReduceComplex8)(std::complex &result, const Descriptor &array, ReductionOperation> operation, const char *source, int line, int dim, const Descriptor *mask, const std::complex *identity, bool ordered) { Terminator terminator{source, line}; result = GetTotalReduction(array, source, line, dim, mask, ReduceAccumulator>{ array, operation, identity, terminator}, "REDUCE"); } void RTDEF(CppReduceComplex8Dim)(Descriptor &result, const Descriptor &array, ReductionOperation> operation, const char *source, int line, int dim, const Descriptor *mask, const std::complex *identity, bool ordered) { Terminator terminator{source, line}; using Accumulator = ReduceAccumulator>; Accumulator accumulator{array, operation, identity, terminator}; PartialReduction(result, array, array.ElementBytes(), dim, mask, terminator, "REDUCE", accumulator); } #if LDBL_MANT_DIG == 64 void RTDEF(CppReduceComplex10)(std::complex &result, const Descriptor &array, ReductionOperation> operation, const char *source, int line, int dim, const Descriptor *mask, const std::complex *identity, bool ordered) { Terminator terminator{source, line}; result = GetTotalReduction(array, source, line, dim, mask, ReduceAccumulator>{ array, operation, identity, terminator}, "REDUCE"); } void RTDEF(CppReduceComplex10Dim)(Descriptor &result, const Descriptor &array, ReductionOperation> operation, const char *source, int line, int dim, const Descriptor *mask, const std::complex *identity, bool ordered) { Terminator terminator{source, line}; using Accumulator = ReduceAccumulator>; Accumulator accumulator{array, operation, identity, terminator}; PartialReduction(result, array, array.ElementBytes(), dim, mask, terminator, "REDUCE", accumulator); } #endif #if LDBL_MANT_DIG == 113 || HAS_FLOAT128 void RTDEF(CppReduceComplex16)(std::complex &result, const Descriptor &array, ReductionOperation> operation, const char *source, int line, int dim, const Descriptor *mask, const std::complex *identity, bool ordered) { Terminator terminator{source, line}; result = GetTotalReduction(array, source, line, dim, mask, ReduceAccumulator>{ array, operation, identity, terminator}, "REDUCE"); } void RTDEF(CppReduceComplex16Dim)(Descriptor &result, const Descriptor &array, ReductionOperation> operation, const char *source, int line, int dim, const Descriptor *mask, const std::complex *identity, bool ordered) { Terminator terminator{source, line}; using Accumulator = ReduceAccumulator>; Accumulator accumulator{array, operation, identity, terminator}; PartialReduction(result, array, array.ElementBytes(), dim, mask, terminator, "REDUCE", accumulator); } #endif bool RTDEF(ReduceLogical1)(const Descriptor &array, ReductionOperation operation, const char *source, int line, int dim, const Descriptor *mask, const std::int8_t *identity, bool ordered) { return RTNAME(ReduceInteger1)( array, operation, source, line, dim, mask, identity, ordered) != 0; } void RTDEF(ReduceLogical1Dim)(Descriptor &result, const Descriptor &array, ReductionOperation operation, const char *source, int line, int dim, const Descriptor *mask, const std::int8_t *identity, bool ordered) { RTNAME(ReduceInteger1Dim) (result, array, operation, source, line, dim, mask, identity, ordered); } bool RTDEF(ReduceLogical2)(const Descriptor &array, ReductionOperation operation, const char *source, int line, int dim, const Descriptor *mask, const std::int16_t *identity, bool ordered) { return RTNAME(ReduceInteger2)( array, operation, source, line, dim, mask, identity, ordered) != 0; } void RTDEF(ReduceLogical2Dim)(Descriptor &result, const Descriptor &array, ReductionOperation operation, const char *source, int line, int dim, const Descriptor *mask, const std::int16_t *identity, bool ordered) { RTNAME(ReduceInteger2Dim) (result, array, operation, source, line, dim, mask, identity, ordered); } bool RTDEF(ReduceLogical4)(const Descriptor &array, ReductionOperation operation, const char *source, int line, int dim, const Descriptor *mask, const std::int32_t *identity, bool ordered) { return RTNAME(ReduceInteger4)( array, operation, source, line, dim, mask, identity, ordered) != 0; } void RTDEF(ReduceLogical4Dim)(Descriptor &result, const Descriptor &array, ReductionOperation operation, const char *source, int line, int dim, const Descriptor *mask, const std::int32_t *identity, bool ordered) { RTNAME(ReduceInteger4Dim) (result, array, operation, source, line, dim, mask, identity, ordered); } bool RTDEF(ReduceLogical8)(const Descriptor &array, ReductionOperation operation, const char *source, int line, int dim, const Descriptor *mask, const std::int64_t *identity, bool ordered) { return RTNAME(ReduceInteger8)( array, operation, source, line, dim, mask, identity, ordered) != 0; } void RTDEF(ReduceLogical8Dim)(Descriptor &result, const Descriptor &array, ReductionOperation operation, const char *source, int line, int dim, const Descriptor *mask, const std::int64_t *identity, bool ordered) { RTNAME(ReduceInteger8Dim) (result, array, operation, source, line, dim, mask, identity, ordered); } void RTDEF(ReduceChar1)(char *result, const Descriptor &array, ReductionCharOperation operation, const char *source, int line, int dim, const Descriptor *mask, const char *identity, bool ordered) { Terminator terminator{source, line}; BufferedReduceAccumulator, /*hasLength=*/true> accumulator{array, operation, identity, terminator}; DoTotalReduction(array, dim, mask, accumulator, "REDUCE", terminator); accumulator.GetResult(result); } void RTDEF(ReduceCharacter1Dim)(Descriptor &result, const Descriptor &array, ReductionCharOperation operation, const char *source, int line, int dim, const Descriptor *mask, const char *identity, bool ordered) { Terminator terminator{source, line}; using Accumulator = BufferedReduceAccumulator, /*hasLength=*/true>; Accumulator accumulator{array, operation, identity, terminator}; PartialReduction(result, array, array.ElementBytes(), dim, mask, terminator, "REDUCE", accumulator); } void RTDEF(ReduceChar2)(char16_t *result, const Descriptor &array, ReductionCharOperation operation, const char *source, int line, int dim, const Descriptor *mask, const char16_t *identity, bool ordered) { Terminator terminator{source, line}; BufferedReduceAccumulator, /*hasLength=*/true> accumulator{array, operation, identity, terminator}; DoTotalReduction( array, dim, mask, accumulator, "REDUCE", terminator); accumulator.GetResult(result); } void RTDEF(ReduceCharacter2Dim)(Descriptor &result, const Descriptor &array, ReductionCharOperation operation, const char *source, int line, int dim, const Descriptor *mask, const char16_t *identity, bool ordered) { Terminator terminator{source, line}; using Accumulator = BufferedReduceAccumulator, /*hasLength=*/true>; Accumulator accumulator{array, operation, identity, terminator}; PartialReduction(result, array, array.ElementBytes(), dim, mask, terminator, "REDUCE", accumulator); } void RTDEF(ReduceChar4)(char32_t *result, const Descriptor &array, ReductionCharOperation operation, const char *source, int line, int dim, const Descriptor *mask, const char32_t *identity, bool ordered) { Terminator terminator{source, line}; BufferedReduceAccumulator, /*hasLength=*/true> accumulator{array, operation, identity, terminator}; DoTotalReduction( array, dim, mask, accumulator, "REDUCE", terminator); accumulator.GetResult(result); } void RTDEF(ReduceCharacter4Dim)(Descriptor &result, const Descriptor &array, ReductionCharOperation operation, const char *source, int line, int dim, const Descriptor *mask, const char32_t *identity, bool ordered) { Terminator terminator{source, line}; using Accumulator = BufferedReduceAccumulator, /*hasLength=*/true>; Accumulator accumulator{array, operation, identity, terminator}; PartialReduction(result, array, array.ElementBytes(), dim, mask, terminator, "REDUCE", accumulator); } void RTDEF(ReduceDerivedType)(char *result, const Descriptor &array, ReductionDerivedTypeOperation operation, const char *source, int line, int dim, const Descriptor *mask, const char *identity, bool ordered) { Terminator terminator{source, line}; BufferedReduceAccumulator accumulator{array, operation, identity, terminator}; DoTotalReduction(array, dim, mask, accumulator, "REDUCE", terminator); accumulator.GetResult(result); } void RTDEF(ReduceDerivedTypeDim)(Descriptor &result, const Descriptor &array, ReductionDerivedTypeOperation operation, const char *source, int line, int dim, const Descriptor *mask, const char *identity, bool ordered) { Terminator terminator{source, line}; using Accumulator = BufferedReduceAccumulator; Accumulator accumulator{array, operation, identity, terminator}; PartialReduction(result, array, array.ElementBytes(), dim, mask, terminator, "REDUCE", accumulator); } RT_EXT_API_GROUP_END } // extern "C" } // namespace Fortran::runtime