Mercurial > hg > CbC > CbC_llvm
view flang/runtime/sum.cpp @ 207:2e18cbf3894f
LLVM12
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Tue, 08 Jun 2021 06:07:14 +0900 |
parents | |
children | 5f17cb93ff66 |
line wrap: on
line source
//===-- 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 <cinttypes> #include <complex> namespace Fortran::runtime { template <typename INTERMEDIATE> class IntegerSumAccumulator { public: explicit IntegerSumAccumulator(const Descriptor &array) : array_{array} {} void Reinitialize() { sum_ = 0; } template <typename A> void GetResult(A *p, int /*zeroBasedDim*/ = -1) const { *p = static_cast<A>(sum_); } template <typename A> bool AccumulateAt(const SubscriptValue at[]) { sum_ += *array_.Element<A>(at); return true; } private: const Descriptor &array_; INTERMEDIATE sum_{0}; }; template <typename INTERMEDIATE> class RealSumAccumulator { public: explicit RealSumAccumulator(const Descriptor &array) : array_{array} {} void Reinitialize() { positives_ = negatives_ = inOrder_ = 0; } template <typename A> A Result() const { auto sum{static_cast<A>(positives_ + negatives_)}; return std::isfinite(sum) ? sum : static_cast<A>(inOrder_); } template <typename A> void GetResult(A *p, int /*zeroBasedDim*/ = -1) const { *p = Result<A>(); } template <typename A> 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 <typename A> bool AccumulateAt(const SubscriptValue at[]) { return Accumulate(*array_.Element<A>(at)); } private: const Descriptor &array_; INTERMEDIATE positives_{0.0}, negatives_{0.0}, inOrder_{0.0}; }; template <typename PART> class ComplexSumAccumulator { public: explicit ComplexSumAccumulator(const Descriptor &array) : array_{array} {} void Reinitialize() { reals_.Reinitialize(); imaginaries_.Reinitialize(); } template <typename A> void GetResult(A *p, int /*zeroBasedDim*/ = -1) const { using ResultPart = typename A::value_type; *p = {reals_.template Result<ResultPart>(), imaginaries_.template Result<ResultPart>()}; } template <typename A> bool Accumulate(const A &z) { reals_.Accumulate(z.real()); imaginaries_.Accumulate(z.imag()); return true; } template <typename A> bool AccumulateAt(const SubscriptValue at[]) { return Accumulate(*array_.Element<A>(at)); } private: const Descriptor &array_; RealSumAccumulator<PART> reals_{array_}, imaginaries_{array_}; }; extern "C" { CppTypeFor<TypeCategory::Integer, 1> RTNAME(SumInteger1)(const Descriptor &x, const char *source, int line, int dim, const Descriptor *mask) { return GetTotalReduction<TypeCategory::Integer, 1>(x, source, line, dim, mask, IntegerSumAccumulator<CppTypeFor<TypeCategory::Integer, 4>>{x}, "SUM"); } CppTypeFor<TypeCategory::Integer, 2> RTNAME(SumInteger2)(const Descriptor &x, const char *source, int line, int dim, const Descriptor *mask) { return GetTotalReduction<TypeCategory::Integer, 2>(x, source, line, dim, mask, IntegerSumAccumulator<CppTypeFor<TypeCategory::Integer, 4>>{x}, "SUM"); } CppTypeFor<TypeCategory::Integer, 4> RTNAME(SumInteger4)(const Descriptor &x, const char *source, int line, int dim, const Descriptor *mask) { return GetTotalReduction<TypeCategory::Integer, 4>(x, source, line, dim, mask, IntegerSumAccumulator<CppTypeFor<TypeCategory::Integer, 4>>{x}, "SUM"); } CppTypeFor<TypeCategory::Integer, 8> RTNAME(SumInteger8)(const Descriptor &x, const char *source, int line, int dim, const Descriptor *mask) { return GetTotalReduction<TypeCategory::Integer, 8>(x, source, line, dim, mask, IntegerSumAccumulator<CppTypeFor<TypeCategory::Integer, 8>>{x}, "SUM"); } #ifdef __SIZEOF_INT128__ CppTypeFor<TypeCategory::Integer, 16> RTNAME(SumInteger16)(const Descriptor &x, const char *source, int line, int dim, const Descriptor *mask) { return GetTotalReduction<TypeCategory::Integer, 16>(x, source, line, dim, mask, IntegerSumAccumulator<CppTypeFor<TypeCategory::Integer, 16>>{x}, "SUM"); } #endif // TODO: real/complex(2 & 3) CppTypeFor<TypeCategory::Real, 4> RTNAME(SumReal4)(const Descriptor &x, const char *source, int line, int dim, const Descriptor *mask) { return GetTotalReduction<TypeCategory::Real, 4>( x, source, line, dim, mask, RealSumAccumulator<double>{x}, "SUM"); } CppTypeFor<TypeCategory::Real, 8> RTNAME(SumReal8)(const Descriptor &x, const char *source, int line, int dim, const Descriptor *mask) { return GetTotalReduction<TypeCategory::Real, 8>( x, source, line, dim, mask, RealSumAccumulator<double>{x}, "SUM"); } #if LONG_DOUBLE == 80 CppTypeFor<TypeCategory::Real, 10> RTNAME(SumReal10)(const Descriptor &x, const char *source, int line, int dim, const Descriptor *mask) { return GetTotalReduction<TypeCategory::Real, 10>( x, source, line, dim, mask, RealSumAccumulator<long double>{x}, "SUM"); } #elif LONG_DOUBLE == 128 CppTypeFor<TypeCategory::Real, 16> RTNAME(SumReal16)(const Descriptor &x, const char *source, int line, int dim, const Descriptor *mask) { return GetTotalReduction<TypeCategory::Real, 16>( x, source, line, dim, mask, RealSumAccumulator<long double>{x}, "SUM"); } #endif void RTNAME(CppSumComplex4)(CppTypeFor<TypeCategory::Complex, 4> &result, const Descriptor &x, const char *source, int line, int dim, const Descriptor *mask) { result = GetTotalReduction<TypeCategory::Complex, 4>( x, source, line, dim, mask, ComplexSumAccumulator<double>{x}, "SUM"); } void RTNAME(CppSumComplex8)(CppTypeFor<TypeCategory::Complex, 8> &result, const Descriptor &x, const char *source, int line, int dim, const Descriptor *mask) { result = GetTotalReduction<TypeCategory::Complex, 8>( x, source, line, dim, mask, ComplexSumAccumulator<double>{x}, "SUM"); } #if LONG_DOUBLE == 80 void RTNAME(CppSumComplex10)(CppTypeFor<TypeCategory::Complex, 10> &result, const Descriptor &x, const char *source, int line, int dim, const Descriptor *mask) { result = GetTotalReduction<TypeCategory::Complex, 10>( x, source, line, dim, mask, ComplexSumAccumulator<long double>{x}, "SUM"); } #elif LONG_DOUBLE == 128 void RTNAME(CppSumComplex16)(CppTypeFor<TypeCategory::Complex, 16> &result, const Descriptor &x, const char *source, int line, int dim, const Descriptor *mask) { result = GetTotalReduction<TypeCategory::Complex, 16>( x, source, line, dim, mask, ComplexSumAccumulator<long double>{x}, "SUM"); } #endif void RTNAME(SumDim)(Descriptor &result, const Descriptor &x, int dim, const char *source, int line, const Descriptor *mask) { TypedPartialNumericReduction<IntegerSumAccumulator, RealSumAccumulator, ComplexSumAccumulator>(result, x, dim, source, line, mask, "SUM"); } } // extern "C" } // namespace Fortran::runtime