//===-- runtime/sum.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 // //===----------------------------------------------------------------------===// // Implements SUM for all required operand types and shapes. // // Real and complex SUM reductions attempt to reduce floating-point // cancellation on intermediate results by adding up partial sums // for positive and negative elements independently. #include "reduction-templates.h" #include "reduction.h" #include "flang/Common/long-double.h" #include #include namespace Fortran::runtime { template class IntegerSumAccumulator { public: explicit IntegerSumAccumulator(const Descriptor &array) : array_{array} {} void Reinitialize() { sum_ = 0; } template void GetResult(A *p, int /*zeroBasedDim*/ = -1) const { *p = static_cast(sum_); } template bool AccumulateAt(const SubscriptValue at[]) { sum_ += *array_.Element(at); return true; } private: const Descriptor &array_; INTERMEDIATE sum_{0}; }; template class RealSumAccumulator { public: explicit RealSumAccumulator(const Descriptor &array) : array_{array} {} void Reinitialize() { positives_ = negatives_ = inOrder_ = 0; } template A Result() const { auto sum{static_cast(positives_ + negatives_)}; return std::isfinite(sum) ? sum : static_cast(inOrder_); } template void GetResult(A *p, int /*zeroBasedDim*/ = -1) const { *p = Result(); } template bool Accumulate(A x) { // Accumulate the nonnegative and negative elements independently // to reduce cancellation; also record an in-order sum for use // in case of overflow. if (x >= 0) { positives_ += x; } else { negatives_ += x; } inOrder_ += x; return true; } template bool AccumulateAt(const SubscriptValue at[]) { return Accumulate(*array_.Element(at)); } private: const Descriptor &array_; INTERMEDIATE positives_{0.0}, negatives_{0.0}, inOrder_{0.0}; }; template class ComplexSumAccumulator { public: explicit ComplexSumAccumulator(const Descriptor &array) : array_{array} {} void Reinitialize() { reals_.Reinitialize(); imaginaries_.Reinitialize(); } template void GetResult(A *p, int /*zeroBasedDim*/ = -1) const { using ResultPart = typename A::value_type; *p = {reals_.template Result(), imaginaries_.template Result()}; } template bool Accumulate(const A &z) { reals_.Accumulate(z.real()); imaginaries_.Accumulate(z.imag()); return true; } template bool AccumulateAt(const SubscriptValue at[]) { return Accumulate(*array_.Element(at)); } private: const Descriptor &array_; RealSumAccumulator reals_{array_}, imaginaries_{array_}; }; extern "C" { CppTypeFor RTNAME(SumInteger1)(const Descriptor &x, const char *source, int line, int dim, const Descriptor *mask) { return GetTotalReduction(x, source, line, dim, mask, IntegerSumAccumulator>{x}, "SUM"); } CppTypeFor RTNAME(SumInteger2)(const Descriptor &x, const char *source, int line, int dim, const Descriptor *mask) { return GetTotalReduction(x, source, line, dim, mask, IntegerSumAccumulator>{x}, "SUM"); } CppTypeFor RTNAME(SumInteger4)(const Descriptor &x, const char *source, int line, int dim, const Descriptor *mask) { return GetTotalReduction(x, source, line, dim, mask, IntegerSumAccumulator>{x}, "SUM"); } CppTypeFor RTNAME(SumInteger8)(const Descriptor &x, const char *source, int line, int dim, const Descriptor *mask) { return GetTotalReduction(x, source, line, dim, mask, IntegerSumAccumulator>{x}, "SUM"); } #ifdef __SIZEOF_INT128__ CppTypeFor RTNAME(SumInteger16)(const Descriptor &x, const char *source, int line, int dim, const Descriptor *mask) { return GetTotalReduction(x, source, line, dim, mask, IntegerSumAccumulator>{x}, "SUM"); } #endif // TODO: real/complex(2 & 3) CppTypeFor RTNAME(SumReal4)(const Descriptor &x, const char *source, int line, int dim, const Descriptor *mask) { return GetTotalReduction( x, source, line, dim, mask, RealSumAccumulator{x}, "SUM"); } CppTypeFor RTNAME(SumReal8)(const Descriptor &x, const char *source, int line, int dim, const Descriptor *mask) { return GetTotalReduction( x, source, line, dim, mask, RealSumAccumulator{x}, "SUM"); } #if LONG_DOUBLE == 80 CppTypeFor RTNAME(SumReal10)(const Descriptor &x, const char *source, int line, int dim, const Descriptor *mask) { return GetTotalReduction( x, source, line, dim, mask, RealSumAccumulator{x}, "SUM"); } #elif LONG_DOUBLE == 128 CppTypeFor RTNAME(SumReal16)(const Descriptor &x, const char *source, int line, int dim, const Descriptor *mask) { return GetTotalReduction( x, source, line, dim, mask, RealSumAccumulator{x}, "SUM"); } #endif void RTNAME(CppSumComplex4)(CppTypeFor &result, const Descriptor &x, const char *source, int line, int dim, const Descriptor *mask) { result = GetTotalReduction( x, source, line, dim, mask, ComplexSumAccumulator{x}, "SUM"); } void RTNAME(CppSumComplex8)(CppTypeFor &result, const Descriptor &x, const char *source, int line, int dim, const Descriptor *mask) { result = GetTotalReduction( x, source, line, dim, mask, ComplexSumAccumulator{x}, "SUM"); } #if LONG_DOUBLE == 80 void RTNAME(CppSumComplex10)(CppTypeFor &result, const Descriptor &x, const char *source, int line, int dim, const Descriptor *mask) { result = GetTotalReduction( x, source, line, dim, mask, ComplexSumAccumulator{x}, "SUM"); } #elif LONG_DOUBLE == 128 void RTNAME(CppSumComplex16)(CppTypeFor &result, const Descriptor &x, const char *source, int line, int dim, const Descriptor *mask) { result = GetTotalReduction( x, source, line, dim, mask, ComplexSumAccumulator{x}, "SUM"); } #endif void RTNAME(SumDim)(Descriptor &result, const Descriptor &x, int dim, const char *source, int line, const Descriptor *mask) { TypedPartialNumericReduction(result, x, dim, source, line, mask, "SUM"); } } // extern "C" } // namespace Fortran::runtime