xref: /llvm-project/flang/runtime/product.cpp (revision fc97d2e68b03bc2979395e84b645e5b3ba35aecd)
1 //===-- runtime/product.cpp -----------------------------------------------===//
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 // Implements PRODUCT for all required operand types and shapes.
10 
11 #include "reduction-templates.h"
12 #include "flang/Common/float128.h"
13 #include "flang/Runtime/reduction.h"
14 #include <cfloat>
15 #include <cinttypes>
16 #include <complex>
17 
18 namespace Fortran::runtime {
19 template <typename INTERMEDIATE> class NonComplexProductAccumulator {
20 public:
21   explicit RT_API_ATTRS NonComplexProductAccumulator(const Descriptor &array)
22       : array_{array} {}
23   RT_API_ATTRS void Reinitialize() { product_ = 1; }
24   template <typename A>
25   RT_API_ATTRS void GetResult(A *p, int /*zeroBasedDim*/ = -1) const {
26     *p = static_cast<A>(product_);
27   }
28   template <typename A>
29   RT_API_ATTRS bool AccumulateAt(const SubscriptValue at[]) {
30     product_ *= *array_.Element<A>(at);
31     return product_ != 0;
32   }
33 
34 private:
35   const Descriptor &array_;
36   INTERMEDIATE product_{1};
37 };
38 
39 template <typename PART> class ComplexProductAccumulator {
40 public:
41   explicit RT_API_ATTRS ComplexProductAccumulator(const Descriptor &array)
42       : array_{array} {}
43   RT_API_ATTRS void Reinitialize() { product_ = rtcmplx::complex<PART>{1, 0}; }
44   template <typename A>
45   RT_API_ATTRS void GetResult(A *p, int /*zeroBasedDim*/ = -1) const {
46     using ResultPart = typename A::value_type;
47     *p = {static_cast<ResultPart>(product_.real()),
48         static_cast<ResultPart>(product_.imag())};
49   }
50   template <typename A>
51   RT_API_ATTRS bool AccumulateAt(const SubscriptValue at[]) {
52     product_ *= *array_.Element<A>(at);
53     return true;
54   }
55 
56 private:
57   const Descriptor &array_;
58   rtcmplx::complex<PART> product_{1, 0};
59 };
60 
61 extern "C" {
62 RT_EXT_API_GROUP_BEGIN
63 
64 CppTypeFor<TypeCategory::Integer, 1> RTDEF(ProductInteger1)(const Descriptor &x,
65     const char *source, int line, int dim, const Descriptor *mask) {
66   return GetTotalReduction<TypeCategory::Integer, 1>(x, source, line, dim, mask,
67       NonComplexProductAccumulator<CppTypeFor<TypeCategory::Integer, 4>>{x},
68       "PRODUCT");
69 }
70 CppTypeFor<TypeCategory::Integer, 2> RTDEF(ProductInteger2)(const Descriptor &x,
71     const char *source, int line, int dim, const Descriptor *mask) {
72   return GetTotalReduction<TypeCategory::Integer, 2>(x, source, line, dim, mask,
73       NonComplexProductAccumulator<CppTypeFor<TypeCategory::Integer, 4>>{x},
74       "PRODUCT");
75 }
76 CppTypeFor<TypeCategory::Integer, 4> RTDEF(ProductInteger4)(const Descriptor &x,
77     const char *source, int line, int dim, const Descriptor *mask) {
78   return GetTotalReduction<TypeCategory::Integer, 4>(x, source, line, dim, mask,
79       NonComplexProductAccumulator<CppTypeFor<TypeCategory::Integer, 4>>{x},
80       "PRODUCT");
81 }
82 CppTypeFor<TypeCategory::Integer, 8> RTDEF(ProductInteger8)(const Descriptor &x,
83     const char *source, int line, int dim, const Descriptor *mask) {
84   return GetTotalReduction<TypeCategory::Integer, 8>(x, source, line, dim, mask,
85       NonComplexProductAccumulator<CppTypeFor<TypeCategory::Integer, 8>>{x},
86       "PRODUCT");
87 }
88 #ifdef __SIZEOF_INT128__
89 CppTypeFor<TypeCategory::Integer, 16> RTDEF(ProductInteger16)(
90     const Descriptor &x, const char *source, int line, int dim,
91     const Descriptor *mask) {
92   return GetTotalReduction<TypeCategory::Integer, 16>(x, source, line, dim,
93       mask,
94       NonComplexProductAccumulator<CppTypeFor<TypeCategory::Integer, 16>>{x},
95       "PRODUCT");
96 }
97 #endif
98 
99 CppTypeFor<TypeCategory::Unsigned, 1> RTDEF(ProductUnsigned1)(
100     const Descriptor &x, const char *source, int line, int dim,
101     const Descriptor *mask) {
102   return GetTotalReduction<TypeCategory::Unsigned, 1>(x, source, line, dim,
103       mask,
104       NonComplexProductAccumulator<CppTypeFor<TypeCategory::Unsigned, 4>>{x},
105       "PRODUCT");
106 }
107 CppTypeFor<TypeCategory::Unsigned, 2> RTDEF(ProductUnsigned2)(
108     const Descriptor &x, const char *source, int line, int dim,
109     const Descriptor *mask) {
110   return GetTotalReduction<TypeCategory::Unsigned, 2>(x, source, line, dim,
111       mask,
112       NonComplexProductAccumulator<CppTypeFor<TypeCategory::Unsigned, 4>>{x},
113       "PRODUCT");
114 }
115 CppTypeFor<TypeCategory::Unsigned, 4> RTDEF(ProductUnsigned4)(
116     const Descriptor &x, const char *source, int line, int dim,
117     const Descriptor *mask) {
118   return GetTotalReduction<TypeCategory::Unsigned, 4>(x, source, line, dim,
119       mask,
120       NonComplexProductAccumulator<CppTypeFor<TypeCategory::Unsigned, 4>>{x},
121       "PRODUCT");
122 }
123 CppTypeFor<TypeCategory::Unsigned, 8> RTDEF(ProductUnsigned8)(
124     const Descriptor &x, const char *source, int line, int dim,
125     const Descriptor *mask) {
126   return GetTotalReduction<TypeCategory::Unsigned, 8>(x, source, line, dim,
127       mask,
128       NonComplexProductAccumulator<CppTypeFor<TypeCategory::Unsigned, 8>>{x},
129       "PRODUCT");
130 }
131 #ifdef __SIZEOF_INT128__
132 CppTypeFor<TypeCategory::Unsigned, 16> RTDEF(ProductUnsigned16)(
133     const Descriptor &x, const char *source, int line, int dim,
134     const Descriptor *mask) {
135   return GetTotalReduction<TypeCategory::Unsigned, 16>(x, source, line, dim,
136       mask,
137       NonComplexProductAccumulator<CppTypeFor<TypeCategory::Unsigned, 16>>{x},
138       "PRODUCT");
139 }
140 #endif
141 
142 // TODO: real/complex(2 & 3)
143 CppTypeFor<TypeCategory::Real, 4> RTDEF(ProductReal4)(const Descriptor &x,
144     const char *source, int line, int dim, const Descriptor *mask) {
145   return GetTotalReduction<TypeCategory::Real, 4>(x, source, line, dim, mask,
146       NonComplexProductAccumulator<CppTypeFor<TypeCategory::Real, 4>>{x},
147       "PRODUCT");
148 }
149 CppTypeFor<TypeCategory::Real, 8> RTDEF(ProductReal8)(const Descriptor &x,
150     const char *source, int line, int dim, const Descriptor *mask) {
151   return GetTotalReduction<TypeCategory::Real, 8>(x, source, line, dim, mask,
152       NonComplexProductAccumulator<CppTypeFor<TypeCategory::Real, 8>>{x},
153       "PRODUCT");
154 }
155 #if HAS_FLOAT80
156 CppTypeFor<TypeCategory::Real, 10> RTDEF(ProductReal10)(const Descriptor &x,
157     const char *source, int line, int dim, const Descriptor *mask) {
158   return GetTotalReduction<TypeCategory::Real, 10>(x, source, line, dim, mask,
159       NonComplexProductAccumulator<CppTypeFor<TypeCategory::Real, 10>>{x},
160       "PRODUCT");
161 }
162 #endif
163 #if HAS_LDBL128 || HAS_FLOAT128
164 CppTypeFor<TypeCategory::Real, 16> RTDEF(ProductReal16)(const Descriptor &x,
165     const char *source, int line, int dim, const Descriptor *mask) {
166   return GetTotalReduction<TypeCategory::Real, 16>(x, source, line, dim, mask,
167       NonComplexProductAccumulator<CppTypeFor<TypeCategory::Real, 16>>{x},
168       "PRODUCT");
169 }
170 #endif
171 
172 void RTDEF(CppProductComplex4)(CppTypeFor<TypeCategory::Complex, 4> &result,
173     const Descriptor &x, const char *source, int line, int dim,
174     const Descriptor *mask) {
175   result = GetTotalReduction<TypeCategory::Complex, 4>(x, source, line, dim,
176       mask, ComplexProductAccumulator<CppTypeFor<TypeCategory::Real, 4>>{x},
177       "PRODUCT");
178 }
179 void RTDEF(CppProductComplex8)(CppTypeFor<TypeCategory::Complex, 8> &result,
180     const Descriptor &x, const char *source, int line, int dim,
181     const Descriptor *mask) {
182   result = GetTotalReduction<TypeCategory::Complex, 8>(x, source, line, dim,
183       mask, ComplexProductAccumulator<CppTypeFor<TypeCategory::Real, 8>>{x},
184       "PRODUCT");
185 }
186 #if HAS_FLOAT80
187 void RTDEF(CppProductComplex10)(CppTypeFor<TypeCategory::Complex, 10> &result,
188     const Descriptor &x, const char *source, int line, int dim,
189     const Descriptor *mask) {
190   result = GetTotalReduction<TypeCategory::Complex, 10>(x, source, line, dim,
191       mask, ComplexProductAccumulator<CppTypeFor<TypeCategory::Real, 10>>{x},
192       "PRODUCT");
193 }
194 #endif
195 #if HAS_LDBL128 || HAS_FLOAT128
196 void RTDEF(CppProductComplex16)(CppTypeFor<TypeCategory::Complex, 16> &result,
197     const Descriptor &x, const char *source, int line, int dim,
198     const Descriptor *mask) {
199   result = GetTotalReduction<TypeCategory::Complex, 16>(x, source, line, dim,
200       mask, ComplexProductAccumulator<CppTypeFor<TypeCategory::Real, 16>>{x},
201       "PRODUCT");
202 }
203 #endif
204 
205 void RTDEF(ProductDim)(Descriptor &result, const Descriptor &x, int dim,
206     const char *source, int line, const Descriptor *mask) {
207   TypedPartialNumericReduction<NonComplexProductAccumulator,
208       NonComplexProductAccumulator, ComplexProductAccumulator,
209       /*MIN_REAL_KIND=*/4>(result, x, dim, source, line, mask, "PRODUCT");
210 }
211 
212 RT_EXT_API_GROUP_END
213 } // extern "C"
214 } // namespace Fortran::runtime
215