FLANG
fold-matmul.h
1//===-- lib/Evaluate/fold-matmul.h ----------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef FORTRAN_EVALUATE_FOLD_MATMUL_H_
10#define FORTRAN_EVALUATE_FOLD_MATMUL_H_
11
12#include "fold-implementation.h"
13
14namespace Fortran::evaluate {
15
16template <typename T>
17static Expr<T> FoldMatmul(FoldingContext &context, FunctionRef<T> &&funcRef) {
18 const int kind{funcRef.kind()};
19 using Element = typename Constant<T>::Element;
20 auto args{funcRef.arguments()};
21 CHECK(args.size() == 2);
22 Folder<T> folder{kind, context};
23 Constant<T> *ma{folder.Folding(args[0])};
24 Constant<T> *mb{folder.Folding(args[1])};
25 if (!ma || !mb) {
26 return Expr<T>{std::move(funcRef)};
27 }
28 CHECK(ma->Rank() >= 1 && ma->Rank() <= 2 && mb->Rank() >= 1 &&
29 mb->Rank() <= 2 && (ma->Rank() == 2 || mb->Rank() == 2));
30 ConstantSubscript commonExtent{ma->shape().back()};
31 if (mb->shape().front() != commonExtent) {
32 context.messages().Say(
33 "Arguments to MATMUL have distinct extents %zd and %zd on their last and first dimensions"_err_en_US,
34 commonExtent, mb->shape().front());
35 return MakeInvalidIntrinsic(std::move(funcRef));
36 }
37 ConstantSubscript rows{ma->Rank() == 1 ? 1 : ma->shape()[0]};
38 ConstantSubscript columns{mb->Rank() == 1 ? 1 : mb->shape()[1]};
39 std::vector<Element> elements;
40 elements.reserve(rows * columns);
41 bool overflow{false};
42 [[maybe_unused]] const auto &rounding{
43 context.targetCharacteristics().roundingMode()};
44 // result(j,k) = SUM(A(j,:) * B(:,k))
45 for (ConstantSubscript ci{0}; ci < columns; ++ci) {
46 for (ConstantSubscript ri{0}; ri < rows; ++ri) {
47 ConstantSubscripts aAt{ma->lbounds()};
48 if (ma->Rank() == 2) {
49 aAt[0] += ri;
50 }
51 ConstantSubscripts bAt{mb->lbounds()};
52 if (mb->Rank() == 2) {
53 bAt[1] += ci;
54 }
55 Element sum{Element::Zero(kind)};
56 [[maybe_unused]] Element correction{Element::Zero(kind)};
57 for (ConstantSubscript j{0}; j < commonExtent; ++j) {
58 Element aElt{ma->At(aAt)};
59 Element bElt{mb->At(bAt)};
60 if constexpr (T::category == TypeCategory::Real ||
61 T::category == TypeCategory::Complex) {
62 auto product{aElt.Multiply(bElt)};
63 overflow |= product.flags.test(RealFlag::Overflow);
64 if constexpr (useKahanSummation) {
65 auto added{sum.KahanSummation(product.value, correction)};
66 overflow |= added.flags.test(RealFlag::Overflow);
67 sum = added.value;
68 } else {
69 auto added{sum.Add(product.value)};
70 overflow |= added.flags.test(RealFlag::Overflow);
71 sum = added.value;
72 }
73 } else if constexpr (T::category == TypeCategory::Integer) {
74 auto product{aElt.MultiplySigned(bElt)};
75 overflow |= product.SignedMultiplicationOverflowed();
76 auto added{sum.AddSigned(product.lower)};
77 overflow |= added.overflow;
78 sum = std::move(added.value);
79 } else if constexpr (T::category == TypeCategory::Unsigned) {
80 sum = sum.AddUnsigned(aElt.MultiplyUnsigned(bElt).lower).value;
81 } else {
82 static_assert(T::category == TypeCategory::Logical);
83 sum = sum.OR(aElt.AND(bElt));
84 }
85 ++aAt.back();
86 ++bAt.front();
87 }
88 elements.push_back(sum);
89 }
90 }
91 if (overflow) {
92 context.Warn(common::UsageWarning::FoldingException,
93 "MATMUL of %s data overflowed during computation"_warn_en_US,
94 Type<T::category>(kind).AsFortran());
95 }
96 ConstantSubscripts shape;
97 if (ma->Rank() == 2) {
98 shape.push_back(rows);
99 }
100 if (mb->Rank() == 2) {
101 shape.push_back(columns);
102 }
103 return Expr<T>{Constant<T>{kind, std::move(elements), std::move(shape)}};
104}
105} // namespace Fortran::evaluate
106#endif // FORTRAN_EVALUATE_FOLD_MATMUL_H_
Definition constant.h:181
Definition common.h:222
Definition fold-implementation.h:54
Definition common.h:224
Definition call.h:417
Definition type.h:61
Definition call.h:34