//===-- 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 using "Kahan summation" // (basically the same as manual "double-double"). #include "reduction-templates.h" #include "flang/Runtime/float128.h" #include "flang/Runtime/reduction.h" #include #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() { sum_ = correction_ = 0; } template A Result() const { return sum_; } template void GetResult(A *p, int /*zeroBasedDim*/ = -1) const { *p = Result(); } template bool Accumulate(A x) { // Kahan summation auto next{x + correction_}; auto oldSum{sum_}; sum_ += next; correction_ = (sum_ - oldSum) - next; // algebraically zero return true; } template bool AccumulateAt(const SubscriptValue at[]) { return Accumulate(*array_.Element(at)); } private: const Descriptor &array_; INTERMEDIATE sum_{0.0}, correction_{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 LDBL_MANT_DIG == 64 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"); } #endif #if LDBL_MANT_DIG == 113 || HAS_FLOAT128 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 LDBL_MANT_DIG == 64 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 LDBL_MANT_DIG == 113 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