21#ifndef FORTRAN_RUNTIME_REDUCTION_TEMPLATES_H_
22#define FORTRAN_RUNTIME_REDUCTION_TEMPLATES_H_
24#include "numeric-templates.h"
25#include "terminator.h"
27#include "flang/Runtime/cpp-type.h"
28#include "flang/Runtime/descriptor.h"
31namespace Fortran::runtime {
44template <
typename TYPE,
typename ACCUMULATOR>
45inline RT_API_ATTRS
void DoTotalReduction(
const Descriptor &x,
int dim,
46 const Descriptor *mask, ACCUMULATOR &accumulator,
const char *intrinsic,
47 Terminator &terminator) {
48 if (dim < 0 || dim > 1) {
49 terminator.Crash(
"%s: bad DIM=%d for ARRAY argument with rank %d",
50 intrinsic, dim, x.rank());
52 SubscriptValue xAt[maxRank];
53 x.GetLowerBounds(xAt);
55 CheckConformability(x, *mask, terminator, intrinsic,
"ARRAY",
"MASK");
56 if (mask->rank() > 0) {
57 SubscriptValue maskAt[maxRank];
58 mask->GetLowerBounds(maskAt);
59 for (
auto elements{x.Elements()}; elements--;
60 x.IncrementSubscripts(xAt), mask->IncrementSubscripts(maskAt)) {
61 if (IsLogicalElementTrue(*mask, maskAt)) {
62 if (!accumulator.template AccumulateAt<TYPE>(xAt)) {
68 }
else if (!IsLogicalScalarTrue(*mask)) {
74 for (
auto elements{x.Elements()}; elements--; x.IncrementSubscripts(xAt)) {
75 if (!accumulator.template AccumulateAt<TYPE>(xAt)) {
81template <TypeCategory CAT,
int KIND,
typename ACCUMULATOR>
82inline RT_API_ATTRS CppTypeFor<CAT, KIND> GetTotalReduction(
const Descriptor &x,
83 const char *source,
int line,
int dim,
const Descriptor *mask,
84 ACCUMULATOR &&accumulator,
const char *intrinsic,
85 bool allowUnsignedForInteger =
false) {
86 Terminator terminator{source, line};
87 RUNTIME_CHECK(terminator,
88 TypeCode(CAT, KIND) == x.type() ||
89 (CAT == TypeCategory::Integer && allowUnsignedForInteger &&
90 TypeCode(TypeCategory::Unsigned, KIND) == x.type()));
91 using CppType = CppTypeFor<CAT, KIND>;
92 DoTotalReduction<CppType>(x, dim, mask, accumulator, intrinsic, terminator);
93 if constexpr (std::is_void_v<CppType>) {
96 accumulator.GetResult();
98 accumulator.template GetResult<CppType>();
103 accumulator.GetResult(&result);
105 accumulator.template GetResult<CppType>(&result);
117inline RT_API_ATTRS
void GetExpandedSubscripts(SubscriptValue at[],
118 const Descriptor &descriptor,
int zeroBasedDim,
119 const SubscriptValue from[]) {
120 descriptor.GetLowerBounds(at);
121 int rank{descriptor.rank()};
123 for (; j < zeroBasedDim; ++j) {
124 at[j] += from[j] - 1 ;
126 for (++j; j < rank; ++j) {
127 at[j] += from[j - 1] - 1;
131template <
typename TYPE,
typename ACCUMULATOR>
132inline RT_API_ATTRS
void ReduceDimToScalar(
const Descriptor &x,
133 int zeroBasedDim, SubscriptValue subscripts[], TYPE *result,
134 ACCUMULATOR &accumulator) {
135 SubscriptValue xAt[maxRank];
136 GetExpandedSubscripts(xAt, x, zeroBasedDim, subscripts);
137 const auto &dim{x.GetDimension(zeroBasedDim)};
138 SubscriptValue at{dim.LowerBound()};
139 for (
auto n{dim.Extent()}; n-- > 0; ++at) {
140 xAt[zeroBasedDim] = at;
141 if (!accumulator.template AccumulateAt<TYPE>(xAt)) {
146 accumulator.GetResult(result, zeroBasedDim);
148 accumulator.template GetResult<TYPE>(result, zeroBasedDim);
152template <
typename TYPE,
typename ACCUMULATOR>
153inline RT_API_ATTRS
void ReduceDimMaskToScalar(
const Descriptor &x,
154 int zeroBasedDim, SubscriptValue subscripts[],
const Descriptor &mask,
155 TYPE *result, ACCUMULATOR &accumulator) {
156 SubscriptValue xAt[maxRank], maskAt[maxRank];
157 GetExpandedSubscripts(xAt, x, zeroBasedDim, subscripts);
158 GetExpandedSubscripts(maskAt, mask, zeroBasedDim, subscripts);
159 const auto &xDim{x.GetDimension(zeroBasedDim)};
160 SubscriptValue xPos{xDim.LowerBound()};
161 const auto &maskDim{mask.GetDimension(zeroBasedDim)};
162 SubscriptValue maskPos{maskDim.LowerBound()};
163 for (
auto n{x.GetDimension(zeroBasedDim).Extent()}; n-- > 0;
165 maskAt[zeroBasedDim] = maskPos;
166 if (IsLogicalElementTrue(mask, maskAt)) {
167 xAt[zeroBasedDim] = xPos;
168 if (!accumulator.template AccumulateAt<TYPE>(xAt)) {
174 accumulator.GetResult(result, zeroBasedDim);
176 accumulator.template GetResult<TYPE>(result, zeroBasedDim);
182template <
typename ACCUMULATOR, TypeCategory CAT,
int KIND>
183inline RT_API_ATTRS
void PartialReduction(Descriptor &result,
184 const Descriptor &x, std::size_t resultElementSize,
int dim,
185 const Descriptor *mask, Terminator &terminator,
const char *intrinsic,
186 ACCUMULATOR &accumulator) {
187 CreatePartialReductionResult(result, x, resultElementSize, dim, terminator,
188 intrinsic, TypeCode{CAT, KIND});
189 SubscriptValue at[maxRank];
190 result.GetLowerBounds(at);
191 INTERNAL_CHECK(result.rank() == 0 || at[0] == 1);
192 using CppType = CppTypeFor<CAT, KIND>;
194 CheckConformability(x, *mask, terminator, intrinsic,
"ARRAY",
"MASK");
195 if (mask->rank() > 0) {
196 for (
auto n{result.Elements()}; n-- > 0; result.IncrementSubscripts(at)) {
197 accumulator.Reinitialize();
198 ReduceDimMaskToScalar<CppType, ACCUMULATOR>(
199 x, dim - 1, at, *mask, result.Element<CppType>(at), accumulator);
202 }
else if (!IsLogicalScalarTrue(*mask)) {
204 accumulator.Reinitialize();
205 for (
auto n{result.Elements()}; n-- > 0; result.IncrementSubscripts(at)) {
206 accumulator.GetResult(result.Element<CppType>(at));
212 for (
auto n{result.Elements()}; n-- > 0; result.IncrementSubscripts(at)) {
213 accumulator.Reinitialize();
214 ReduceDimToScalar<CppType, ACCUMULATOR>(
215 x, dim - 1, at, result.Element<CppType>(at), accumulator);
219template <
template <
typename>
class ACCUM>
222 static constexpr int Intermediate{
226 const char *intrinsic)
const {
228 ACCUM<CppTypeFor<TypeCategory::Integer, Intermediate>>;
232 PartialReduction<Accumulator, TypeCategory::Integer, KIND>(result, x,
233 x.ElementBytes(), dim, mask, terminator, intrinsic, accumulator);
238template <
template <
typename>
class INTEGER_ACCUM>
239inline RT_API_ATTRS
void PartialIntegerReduction(
Descriptor &result,
241 const char *intrinsic,
Terminator &terminator) {
244 kind, terminator, result, x, dim, mask, terminator, intrinsic);
247template <TypeCategory CAT,
template <
typename>
class ACCUM,
int MIN_KIND>
250 static constexpr int Intermediate{std::max(KIND, MIN_KIND)};
253 const char *intrinsic)
const {
254 using Accumulator = ACCUM<CppTypeFor<TypeCategory::Real, Intermediate>>;
258 PartialReduction<Accumulator, CAT, KIND>(result, x, x.ElementBytes(), dim,
259 mask, terminator, intrinsic, accumulator);
264template <
template <
typename>
class INTEGER_ACCUM,
265 template <
typename>
class REAL_ACCUM,
266 template <
typename>
class COMPLEX_ACCUM,
int MIN_REAL_KIND>
267inline RT_API_ATTRS
void TypedPartialNumericReduction(
Descriptor &result,
268 const Descriptor &x,
int dim,
const char *source,
int line,
269 const Descriptor *mask,
const char *intrinsic) {
271 auto catKind{x.type().GetCategoryAndKind()};
272 RUNTIME_CHECK(terminator, catKind.has_value());
273 switch (catKind->first) {
274 case TypeCategory::Integer:
275 PartialIntegerReduction<INTEGER_ACCUM>(
276 result, x, dim, catKind->second, mask, intrinsic, terminator);
278 case TypeCategory::Real:
279 ApplyFloatingPointKind<PartialFloatingReductionHelper<TypeCategory::Real,
280 REAL_ACCUM, MIN_REAL_KIND>::template Functor,
281 void>(catKind->second, terminator, result, x, dim, mask, terminator,
284 case TypeCategory::Complex:
285 ApplyFloatingPointKind<PartialFloatingReductionHelper<TypeCategory::Complex,
286 COMPLEX_ACCUM, MIN_REAL_KIND>::template Functor,
287 void>(catKind->second, terminator, result, x, dim, mask, terminator,
291 terminator.Crash(
"%s: bad type code %d", intrinsic, x.type().raw());
297 RT_API_ATTRS
void operator()(
298 ACCUMULATOR &accumulator,
const Descriptor &result)
const {
299 accumulator.GetResult(
300 result.OffsetElement<CppTypeFor<TypeCategory::Integer, KIND>>());
309 const char *intrinsic, ACCUMULATOR &accumulator)
const {
312 PartialReduction<ACCUMULATOR, TypeCategory::Integer, KIND>(result, x,
313 Descriptor::BytesFor(TypeCategory::Integer, KIND), dim, mask,
314 terminator, intrinsic, accumulator);
325static constexpr RT_CONST_VAR_ATTRS
int Norm2LargestLDKind{
326#if HAS_LDBL128 || HAS_FLOAT128
337template <TypeCategory CAT,
int KIND,
typename ACCUMULATOR>
338inline RT_API_ATTRS
void DoMaxMinNorm2(Descriptor &result,
const Descriptor &x,
339 int dim,
const Descriptor *mask,
const char *intrinsic,
340 Terminator &terminator) {
341 using Type = CppTypeFor<CAT, KIND>;
342 ACCUMULATOR accumulator{x};
343 if (dim == 0 || x.rank() == 1) {
348 result.Establish(x.type(), x.ElementBytes(),
nullptr, 0,
nullptr,
349 CFI_attribute_allocatable);
350 if (
int stat{result.Allocate()}) {
352 "%s: could not allocate memory for result; STAT=%d", intrinsic, stat);
354 DoTotalReduction<Type>(x, dim, mask, accumulator, intrinsic, terminator);
355 accumulator.GetResult(result.OffsetElement<Type>());
361 PartialReduction<ACCUMULATOR, CAT, KIND>(result, x, x.ElementBytes(), dim,
362 mask, terminator, intrinsic, accumulator);
368using Norm2AccumType =
369 CppTypeFor<TypeCategory::Real, std::clamp(KIND, 8, Norm2LargestLDKind)>;
373 using Type = CppTypeFor<TypeCategory::Real, KIND>;
374 using AccumType = Norm2AccumType<KIND>;
377 RT_API_ATTRS
void Reinitialize() { max_ = sum_ = 0; }
378 template <
typename A>
379 RT_API_ATTRS
void GetResult(A *p,
int = -1)
const {
383 RT_API_ATTRS
bool Accumulate(Type x) {
387 }
else if (absX > max_) {
399 template <
typename A>
400 RT_API_ATTRS
bool AccumulateAt(
const SubscriptValue at[]) {
401 return Accumulate(*array_.Element<A>(at));
413 DoMaxMinNorm2<TypeCategory::Real, KIND, Norm2Accumulator<KIND>>(
414 result, x, dim, mask,
"NORM2", terminator);
Definition: dot-product.cpp:27
Definition: descriptor.h:138
Definition: reduction-templates.h:371
Definition: terminator.h:23
Definition: numeric-templates.h:126
Definition: reduction-templates.h:296
Definition: reduction-templates.h:295
Definition: reduction-templates.h:410
Definition: reduction-templates.h:249
Definition: reduction-templates.h:248
Definition: reduction-templates.h:221
Definition: reduction-templates.h:220
Definition: reduction-templates.h:306
Definition: reduction-templates.h:305
Definition: numeric-templates.h:185