9#ifndef FORTRAN_EVALUATE_FOLD_REDUCTION_H_
10#define FORTRAN_EVALUATE_FOLD_REDUCTION_H_
12#include "fold-implementation.h"
19 using Element =
typename Constant<T>::Element;
20 auto args{funcRef.arguments()};
21 CHECK(args.size() == 2);
26 CHECK(va->Rank() == 1 && vb->Rank() == 1);
27 if (va->size() != vb->size()) {
28 context.messages().Say(
29 "Vector arguments to DOT_PRODUCT have distinct extents %zd and %zd"_err_en_US,
30 va->size(), vb->size());
31 return MakeInvalidIntrinsic(std::move(funcRef));
35 if constexpr (T::category == TypeCategory::Complex) {
36 std::vector<Element> conjugates;
37 for (
const Element &x : va->values()) {
38 conjugates.emplace_back(x.CONJG());
41 std::move(conjugates), ConstantSubscripts{va->shape()}};
44 Constant<T> &cProducts{DEREF(UnwrapConstantValue<T>(products))};
45 [[maybe_unused]] Element correction{};
46 const auto &rounding{context.targetCharacteristics().roundingMode()};
47 for (
const Element &x : cProducts.values()) {
48 if constexpr (useKahanSummation) {
49 auto added{sum.KahanSummation(x, correction, rounding)};
50 overflow |= added.flags.test(RealFlag::Overflow);
53 auto added{sum.Add(x, rounding)};
54 overflow |= added.flags.test(RealFlag::Overflow);
58 }
else if constexpr (T::category == TypeCategory::Logical) {
59 Expr<T> conjunctions{Fold(context,
62 Constant<T> &cConjunctions{DEREF(UnwrapConstantValue<T>(conjunctions))};
63 for (
const Element &x : cConjunctions.values()) {
69 }
else if constexpr (T::category == TypeCategory::Integer) {
72 Constant<T> &cProducts{DEREF(UnwrapConstantValue<T>(products))};
73 for (
const Element &x : cProducts.values()) {
74 auto next{sum.AddSigned(x)};
75 overflow |= next.overflow;
76 sum = std::move(next.value);
78 }
else if constexpr (T::category == TypeCategory::Unsigned) {
81 Constant<T> &cProducts{DEREF(UnwrapConstantValue<T>(products))};
82 for (
const Element &x : cProducts.values()) {
83 sum = sum.AddUnsigned(x).value;
86 static_assert(T::category == TypeCategory::Real);
89 Constant<T> &cProducts{DEREF(UnwrapConstantValue<T>(products))};
90 [[maybe_unused]] Element correction{};
91 const auto &rounding{context.targetCharacteristics().roundingMode()};
92 for (
const Element &x : cProducts.values()) {
93 if constexpr (useKahanSummation) {
94 auto added{sum.KahanSummation(x, correction, rounding)};
95 overflow |= added.flags.test(RealFlag::Overflow);
98 auto added{sum.Add(x, rounding)};
99 overflow |= added.flags.test(RealFlag::Overflow);
105 context.Warn(common::UsageWarning::FoldingException,
106 "DOT_PRODUCT of %s data overflowed during computation"_warn_en_US,
111 return Expr<T>{std::move(funcRef)};
116 ActualArguments &, std::optional<int> dimIndex,
int rank);
121 std::optional<ActualArgument> &maskArg,
const ConstantSubscripts &shape,
134std::optional<ArrayAndMask<T>> ProcessReductionArgs(
FoldingContext &context,
135 ActualArguments &arg, std::optional<int> &dim,
int arrayIndex,
136 std::optional<int> dimIndex = std::nullopt,
137 std::optional<int> maskIndex = std::nullopt) {
141 Constant<T> *folded{Folder<T>{context}.Folding(arg[arrayIndex])};
142 if (!folded || folded->Rank() < 1) {
145 if (!CheckReductionDIM(dim, context, arg, dimIndex, folded->Rank())) {
148 std::size_t n{folded->size()};
149 std::vector<Scalar<LogicalResult>> maskElement;
150 if (maskIndex &&
static_cast<std::size_t
>(*maskIndex) < arg.size() &&
153 GetReductionMASK(arg[*maskIndex], folded->shape(), context)}) {
154 if (
auto scalarMask{origMask->GetScalarValue()}) {
156 std::vector<Scalar<LogicalResult>>(n, scalarMask->IsTrue());
158 maskElement = origMask->values();
164 maskElement = std::vector<Scalar<LogicalResult>>(n,
true);
168 std::move(maskElement), ConstantSubscripts{folded->shape()}}};
175template <
typename T,
typename ACCUMULATOR,
typename ARRAY>
178 const Scalar<T> &identity, ACCUMULATOR &accumulator) {
179 ConstantSubscripts at{array.lbounds()};
180 ConstantSubscripts maskAt{mask.lbounds()};
181 std::vector<typename Constant<T>::Element> elements;
182 ConstantSubscripts resultShape;
184 resultShape = array.shape();
185 resultShape.erase(resultShape.begin() + (*dim - 1));
186 ConstantSubscript dimExtent{array.shape().at(*dim - 1)};
187 CHECK(dimExtent == mask.shape().at(*dim - 1));
188 ConstantSubscript &dimAt{at[*dim - 1]};
189 ConstantSubscript dimLbound{dimAt};
190 ConstantSubscript &maskDimAt{maskAt[*dim - 1]};
191 ConstantSubscript maskDimLbound{maskDimAt};
192 for (
auto n{GetSize(resultShape)}; n-- > 0;
193 array.IncrementSubscripts(at), mask.IncrementSubscripts(maskAt)) {
194 elements.push_back(identity);
197 maskDimAt = maskDimLbound;
198 bool firstUnmasked{
true};
199 for (ConstantSubscript j{0}; j < dimExtent; ++j, ++dimAt, ++maskDimAt) {
200 if (mask.At(maskAt).IsTrue()) {
201 accumulator(elements.back(), at, firstUnmasked);
202 firstUnmasked =
false;
205 --dimAt, --maskDimAt;
207 accumulator.Done(elements.back());
210 elements.push_back(identity);
211 bool firstUnmasked{
true};
212 for (
auto n{array.size()}; n-- > 0;
213 array.IncrementSubscripts(at), mask.IncrementSubscripts(maskAt)) {
214 if (mask.At(maskAt).IsTrue()) {
215 accumulator(elements.back(), at, firstUnmasked);
216 firstUnmasked =
false;
219 accumulator.Done(elements.back());
221 if constexpr (T::category == TypeCategory::Character) {
222 return {
static_cast<ConstantSubscript
>(identity.size()),
223 std::move(elements), std::move(resultShape)};
225 return {std::move(elements), std::move(resultShape)};
230template <
typename T,
bool ABS = false>
class MaxvalMinvalAccumulator {
232 MaxvalMinvalAccumulator(
234 : opr_{opr}, context_{context}, array_{array} {};
235 void operator()(Scalar<T> &element,
const ConstantSubscripts &at,
236 [[maybe_unused]]
bool firstUnmasked)
const {
237 auto aAt{array_.At(at)};
241 if constexpr (T::category == TypeCategory::Real) {
242 if (firstUnmasked || element.IsNotANumber()) {
251 auto folded{GetScalarConstantValue<LogicalResult>(
252 test.Rewrite(context_, std::move(test)))};
253 CHECK(folded.has_value());
254 if (folded->IsTrue()) {
258 void Done(Scalar<T> &)
const {}
261 RelationalOperator opr_;
268 RelationalOperator opr,
const Scalar<T> &identity) {
269 static_assert(T::category == TypeCategory::Integer ||
270 T::category == TypeCategory::Unsigned ||
271 T::category == TypeCategory::Real ||
272 T::category == TypeCategory::Character);
273 std::optional<int> dim;
275 ProcessReductionArgs<T>(context, ref.arguments(), dim,
277 MaxvalMinvalAccumulator<T> accumulator{opr, context, arrayAndMask->array};
278 return Expr<T>{DoReduction<T>(
279 arrayAndMask->array, arrayAndMask->mask, dim, identity, accumulator)};
281 return Expr<T>{std::move(ref)};
285template <
typename T>
class ProductAccumulator {
287 ProductAccumulator(
const Constant<T> &array) : array_{array} {}
289 Scalar<T> &element,
const ConstantSubscripts &at,
bool ) {
290 if constexpr (T::category == TypeCategory::Integer) {
291 auto prod{element.MultiplySigned(array_.At(at))};
292 overflow_ |= prod.SignedMultiplicationOverflowed();
293 element = prod.lower;
294 }
else if constexpr (T::category == TypeCategory::Unsigned) {
295 element = element.MultiplyUnsigned(array_.At(at)).lower;
297 auto prod{element.Multiply(array_.At(at))};
298 overflow_ |= prod.flags.test(RealFlag::Overflow);
299 element = prod.value;
302 bool overflow()
const {
return overflow_; }
303 void Done(Scalar<T> &)
const {}
307 bool overflow_{
false};
313 static_assert(T::category == TypeCategory::Integer ||
314 T::category == TypeCategory::Unsigned ||
315 T::category == TypeCategory::Real ||
316 T::category == TypeCategory::Complex);
317 std::optional<int> dim;
319 ProcessReductionArgs<T>(context, ref.arguments(), dim,
321 ProductAccumulator accumulator{arrayAndMask->array};
322 auto result{Expr<T>{DoReduction<T>(
323 arrayAndMask->array, arrayAndMask->mask, dim, identity, accumulator)}};
324 if (accumulator.overflow()) {
325 context.Warn(common::UsageWarning::FoldingException,
326 "PRODUCT() of %s data overflowed"_warn_en_US, T::AsFortran());
330 return Expr<T>{std::move(ref)};
334template <
typename T>
class SumAccumulator {
335 using Element =
typename Constant<T>::Element;
339 : array_{array}, rounding_{rounding} {}
341 Element &element,
const ConstantSubscripts &at,
bool ) {
342 if constexpr (T::category == TypeCategory::Integer) {
343 auto sum{element.AddSigned(array_.At(at))};
344 overflow_ |= sum.overflow;
346 }
else if constexpr (T::category == TypeCategory::Unsigned) {
347 element = element.AddUnsigned(array_.At(at)).value;
349 auto sum{element.KahanSummation(array_.At(at), correction_, rounding_)};
350 overflow_ |= sum.flags.test(RealFlag::Overflow);
354 bool overflow()
const {
return overflow_; }
355 void Done([[maybe_unused]] Element &element) {
356 if constexpr (T::category != TypeCategory::Integer &&
357 T::category != TypeCategory::Unsigned) {
358 auto corrected{element.Add(correction_, rounding_)};
359 overflow_ |= corrected.flags.test(RealFlag::Overflow);
360 correction_ = Scalar<T>{};
361 element = corrected.value;
368 bool overflow_{
false};
369 Element correction_{};
374 static_assert(T::category == TypeCategory::Integer ||
375 T::category == TypeCategory::Unsigned ||
376 T::category == TypeCategory::Real ||
377 T::category == TypeCategory::Complex);
378 using Element =
typename Constant<T>::Element;
379 std::optional<int> dim;
381 if (std::optional<ArrayAndMask<T>> arrayAndMask{
382 ProcessReductionArgs<T>(context, ref.arguments(), dim,
384 SumAccumulator accumulator{
385 arrayAndMask->array, context.targetCharacteristics().roundingMode()};
386 auto result{
Expr<T>{DoReduction<T>(
387 arrayAndMask->array, arrayAndMask->mask, dim, identity, accumulator)}};
388 if (accumulator.overflow()) {
389 context.Warn(common::UsageWarning::FoldingException,
390 "SUM() of %s data overflowed"_warn_en_US, T::AsFortran());
394 return Expr<T>{std::move(ref)};
398template <
typename T>
class OperationAccumulator {
401 Scalar<T> (Scalar<T>::*operation)(
const Scalar<T> &)
const)
402 : array_{array}, operation_{operation} {}
404 Scalar<T> &element,
const ConstantSubscripts &at,
bool ) {
405 element = (element.*operation_)(array_.At(at));
407 void Done(Scalar<T> &)
const {}
411 Scalar<T> (Scalar<T>::*operation_)(
const Scalar<T> &)
const;
Definition constant.h:147
Definition fold-implementation.h:54
Definition target-rounding.h:18
Definition fold-reduction.h:129
Definition expression.h:378