1 | //===-- runtime/reduce.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 | // REDUCE() implementation |
10 | |
11 | #include "flang/Runtime/reduce.h" |
12 | #include "reduction-templates.h" |
13 | #include "terminator.h" |
14 | #include "tools.h" |
15 | #include "flang/Runtime/descriptor.h" |
16 | |
17 | namespace Fortran::runtime { |
18 | |
19 | template <typename T> class ReduceAccumulator { |
20 | public: |
21 | RT_API_ATTRS ReduceAccumulator(const Descriptor &array, |
22 | ReductionOperation<T> operation, const T *identity, |
23 | Terminator &terminator) |
24 | : array_{array}, operation_{operation}, identity_{identity}, |
25 | terminator_{terminator} {} |
26 | RT_API_ATTRS void Reinitialize() { result_.reset(); } |
27 | template <typename A> |
28 | RT_API_ATTRS bool AccumulateAt(const SubscriptValue at[]) { |
29 | const auto *operand{array_.Element<A>(at)}; |
30 | if (result_) { |
31 | result_ = operation_(&*result_, operand); |
32 | } else { |
33 | result_ = *operand; |
34 | } |
35 | return true; |
36 | } |
37 | template <typename A> |
38 | RT_API_ATTRS void GetResult(A *to, int /*zeroBasedDim*/ = -1) { |
39 | if (result_) { |
40 | *to = *result_; |
41 | } else if (identity_) { |
42 | *to = *identity_; |
43 | } else { |
44 | terminator_.Crash("REDUCE() without IDENTITY= has no result" ); |
45 | } |
46 | } |
47 | |
48 | private: |
49 | const Descriptor &array_; |
50 | common::optional<T> result_; |
51 | ReductionOperation<T> operation_; |
52 | const T *identity_{nullptr}; |
53 | Terminator &terminator_; |
54 | }; |
55 | |
56 | template <typename T, typename OP, bool hasLength> |
57 | class BufferedReduceAccumulator { |
58 | public: |
59 | RT_API_ATTRS BufferedReduceAccumulator(const Descriptor &array, OP operation, |
60 | const T *identity, Terminator &terminator) |
61 | : array_{array}, operation_{operation}, identity_{identity}, |
62 | terminator_{terminator} {} |
63 | RT_API_ATTRS void Reinitialize() { activeTemp_ = -1; } |
64 | template <typename A> |
65 | RT_API_ATTRS bool AccumulateAt(const SubscriptValue at[]) { |
66 | const auto *operand{array_.Element<A>(at)}; |
67 | if (activeTemp_ >= 0) { |
68 | if constexpr (hasLength) { |
69 | operation_(&*temp_[1 - activeTemp_], length_, &*temp_[activeTemp_], |
70 | operand, length_, length_); |
71 | } else { |
72 | operation_(&*temp_[1 - activeTemp_], &*temp_[activeTemp_], operand); |
73 | } |
74 | activeTemp_ = 1 - activeTemp_; |
75 | } else { |
76 | activeTemp_ = 0; |
77 | std::memcpy(&*temp_[activeTemp_], operand, elementBytes_); |
78 | } |
79 | return true; |
80 | } |
81 | template <typename A> |
82 | RT_API_ATTRS void GetResult(A *to, int /*zeroBasedDim*/ = -1) { |
83 | if (activeTemp_ >= 0) { |
84 | std::memcpy(to, &*temp_[activeTemp_], elementBytes_); |
85 | } else if (identity_) { |
86 | std::memcpy(dest: to, src: identity_, n: elementBytes_); |
87 | } else { |
88 | terminator_.Crash("REDUCE() without IDENTITY= has no result" ); |
89 | } |
90 | } |
91 | |
92 | private: |
93 | const Descriptor &array_; |
94 | OP operation_; |
95 | const T *identity_{nullptr}; |
96 | Terminator &terminator_; |
97 | std::size_t elementBytes_{array_.ElementBytes()}; |
98 | OwningPtr<T> temp_[2]{SizedNew<T>{terminator_}(elementBytes_), |
99 | SizedNew<T>{terminator_}(elementBytes_)}; |
100 | int activeTemp_{-1}; |
101 | std::size_t length_{elementBytes_ / sizeof(T)}; |
102 | }; |
103 | |
104 | extern "C" { |
105 | RT_EXT_API_GROUP_BEGIN |
106 | |
107 | std::int8_t RTDEF(ReduceInteger1)(const Descriptor &array, |
108 | ReductionOperation<std::int8_t> operation, const char *source, int line, |
109 | int dim, const Descriptor *mask, const std::int8_t *identity, |
110 | bool ordered) { |
111 | Terminator terminator{source, line}; |
112 | return GetTotalReduction<TypeCategory::Integer, 1>(array, source, line, dim, |
113 | mask, |
114 | ReduceAccumulator<std::int8_t>{array, operation, identity, terminator}, |
115 | "REDUCE" ); |
116 | } |
117 | void RTDEF(ReduceInteger1Dim)(Descriptor &result, const Descriptor &array, |
118 | ReductionOperation<std::int8_t> operation, const char *source, int line, |
119 | int dim, const Descriptor *mask, const std::int8_t *identity, |
120 | bool ordered) { |
121 | Terminator terminator{source, line}; |
122 | using Accumulator = ReduceAccumulator<std::int8_t>; |
123 | Accumulator accumulator{array, operation, identity, terminator}; |
124 | PartialReduction<Accumulator, TypeCategory::Integer, 1>(result, array, |
125 | array.ElementBytes(), dim, mask, terminator, "REDUCE" , accumulator); |
126 | } |
127 | std::int16_t RTDEF(ReduceInteger2)(const Descriptor &array, |
128 | ReductionOperation<std::int16_t> operation, const char *source, int line, |
129 | int dim, const Descriptor *mask, const std::int16_t *identity, |
130 | bool ordered) { |
131 | Terminator terminator{source, line}; |
132 | return GetTotalReduction<TypeCategory::Integer, 2>(array, source, line, dim, |
133 | mask, |
134 | ReduceAccumulator<std::int16_t>{array, operation, identity, terminator}, |
135 | "REDUCE" ); |
136 | } |
137 | void RTDEF(ReduceInteger2Dim)(Descriptor &result, const Descriptor &array, |
138 | ReductionOperation<std::int16_t> operation, const char *source, int line, |
139 | int dim, const Descriptor *mask, const std::int16_t *identity, |
140 | bool ordered) { |
141 | Terminator terminator{source, line}; |
142 | using Accumulator = ReduceAccumulator<std::int16_t>; |
143 | Accumulator accumulator{array, operation, identity, terminator}; |
144 | PartialReduction<Accumulator, TypeCategory::Integer, 2>(result, array, |
145 | array.ElementBytes(), dim, mask, terminator, "REDUCE" , accumulator); |
146 | } |
147 | std::int32_t RTDEF(ReduceInteger4)(const Descriptor &array, |
148 | ReductionOperation<std::int32_t> operation, const char *source, int line, |
149 | int dim, const Descriptor *mask, const std::int32_t *identity, |
150 | bool ordered) { |
151 | Terminator terminator{source, line}; |
152 | return GetTotalReduction<TypeCategory::Integer, 4>(array, source, line, dim, |
153 | mask, |
154 | ReduceAccumulator<std::int32_t>{array, operation, identity, terminator}, |
155 | "REDUCE" ); |
156 | } |
157 | void RTDEF(ReduceInteger4Dim)(Descriptor &result, const Descriptor &array, |
158 | ReductionOperation<std::int32_t> operation, const char *source, int line, |
159 | int dim, const Descriptor *mask, const std::int32_t *identity, |
160 | bool ordered) { |
161 | Terminator terminator{source, line}; |
162 | using Accumulator = ReduceAccumulator<std::int32_t>; |
163 | Accumulator accumulator{array, operation, identity, terminator}; |
164 | PartialReduction<Accumulator, TypeCategory::Integer, 4>(result, array, |
165 | array.ElementBytes(), dim, mask, terminator, "REDUCE" , accumulator); |
166 | } |
167 | std::int64_t RTDEF(ReduceInteger8)(const Descriptor &array, |
168 | ReductionOperation<std::int64_t> operation, const char *source, int line, |
169 | int dim, const Descriptor *mask, const std::int64_t *identity, |
170 | bool ordered) { |
171 | Terminator terminator{source, line}; |
172 | return GetTotalReduction<TypeCategory::Integer, 8>(array, source, line, dim, |
173 | mask, |
174 | ReduceAccumulator<std::int64_t>{array, operation, identity, terminator}, |
175 | "REDUCE" ); |
176 | } |
177 | void RTDEF(ReduceInteger8Dim)(Descriptor &result, const Descriptor &array, |
178 | ReductionOperation<std::int64_t> operation, const char *source, int line, |
179 | int dim, const Descriptor *mask, const std::int64_t *identity, |
180 | bool ordered) { |
181 | Terminator terminator{source, line}; |
182 | using Accumulator = ReduceAccumulator<std::int64_t>; |
183 | Accumulator accumulator{array, operation, identity, terminator}; |
184 | PartialReduction<Accumulator, TypeCategory::Integer, 8>(result, array, |
185 | array.ElementBytes(), dim, mask, terminator, "REDUCE" , accumulator); |
186 | } |
187 | #ifdef __SIZEOF_INT128__ |
188 | common::int128_t RTDEF(ReduceInteger16)(const Descriptor &array, |
189 | ReductionOperation<common::int128_t> operation, const char *source, |
190 | int line, int dim, const Descriptor *mask, const common::int128_t *identity, |
191 | bool ordered) { |
192 | Terminator terminator{source, line}; |
193 | return GetTotalReduction<TypeCategory::Integer, 16>(array, source, line, dim, |
194 | mask, |
195 | ReduceAccumulator<common::int128_t>{ |
196 | array, operation, identity, terminator}, |
197 | "REDUCE" ); |
198 | } |
199 | void RTDEF(ReduceInteger16Dim)(Descriptor &result, const Descriptor &array, |
200 | ReductionOperation<common::int128_t> operation, const char *source, |
201 | int line, int dim, const Descriptor *mask, const common::int128_t *identity, |
202 | bool ordered) { |
203 | Terminator terminator{source, line}; |
204 | using Accumulator = ReduceAccumulator<common::int128_t>; |
205 | Accumulator accumulator{array, operation, identity, terminator}; |
206 | PartialReduction<Accumulator, TypeCategory::Integer, 16>(result, array, |
207 | array.ElementBytes(), dim, mask, terminator, "REDUCE" , accumulator); |
208 | } |
209 | #endif |
210 | |
211 | // TODO: real/complex(2 & 3) |
212 | float RTDEF(ReduceReal4)(const Descriptor &array, |
213 | ReductionOperation<float> operation, const char *source, int line, int dim, |
214 | const Descriptor *mask, const float *identity, bool ordered) { |
215 | Terminator terminator{source, line}; |
216 | return GetTotalReduction<TypeCategory::Real, 4>(array, source, line, dim, |
217 | mask, ReduceAccumulator<float>{array, operation, identity, terminator}, |
218 | "REDUCE" ); |
219 | } |
220 | void RTDEF(ReduceReal4Dim)(Descriptor &result, const Descriptor &array, |
221 | ReductionOperation<float> operation, const char *source, int line, int dim, |
222 | const Descriptor *mask, const float *identity, bool ordered) { |
223 | Terminator terminator{source, line}; |
224 | using Accumulator = ReduceAccumulator<float>; |
225 | Accumulator accumulator{array, operation, identity, terminator}; |
226 | PartialReduction<Accumulator, TypeCategory::Real, 4>(result, array, |
227 | array.ElementBytes(), dim, mask, terminator, "REDUCE" , accumulator); |
228 | } |
229 | double RTDEF(ReduceReal8)(const Descriptor &array, |
230 | ReductionOperation<double> operation, const char *source, int line, int dim, |
231 | const Descriptor *mask, const double *identity, bool ordered) { |
232 | Terminator terminator{source, line}; |
233 | return GetTotalReduction<TypeCategory::Real, 8>(array, source, line, dim, |
234 | mask, ReduceAccumulator<double>{array, operation, identity, terminator}, |
235 | "REDUCE" ); |
236 | } |
237 | void RTDEF(ReduceReal8Dim)(Descriptor &result, const Descriptor &array, |
238 | ReductionOperation<double> operation, const char *source, int line, int dim, |
239 | const Descriptor *mask, const double *identity, bool ordered) { |
240 | Terminator terminator{source, line}; |
241 | using Accumulator = ReduceAccumulator<double>; |
242 | Accumulator accumulator{array, operation, identity, terminator}; |
243 | PartialReduction<Accumulator, TypeCategory::Real, 8>(result, array, |
244 | array.ElementBytes(), dim, mask, terminator, "REDUCE" , accumulator); |
245 | } |
246 | #if LDBL_MANT_DIG == 64 |
247 | long double RTDEF(ReduceReal10)(const Descriptor &array, |
248 | ReductionOperation<long double> operation, const char *source, int line, |
249 | int dim, const Descriptor *mask, const long double *identity, |
250 | bool ordered) { |
251 | Terminator terminator{source, line}; |
252 | return GetTotalReduction<TypeCategory::Real, 10>(array, source, line, dim, |
253 | mask, |
254 | ReduceAccumulator<long double>{array, operation, identity, terminator}, |
255 | "REDUCE" ); |
256 | } |
257 | void RTDEF(ReduceReal10Dim)(Descriptor &result, const Descriptor &array, |
258 | ReductionOperation<long double> operation, const char *source, int line, |
259 | int dim, const Descriptor *mask, const long double *identity, |
260 | bool ordered) { |
261 | Terminator terminator{source, line}; |
262 | using Accumulator = ReduceAccumulator<long double>; |
263 | Accumulator accumulator{array, operation, identity, terminator}; |
264 | PartialReduction<Accumulator, TypeCategory::Real, 10>(result, array, |
265 | array.ElementBytes(), dim, mask, terminator, "REDUCE" , accumulator); |
266 | } |
267 | #endif |
268 | #if LDBL_MANT_DIG == 113 || HAS_FLOAT128 |
269 | CppFloat128Type RTDEF(ReduceReal16)(const Descriptor &array, |
270 | ReductionOperation<CppFloat128Type> operation, const char *source, int line, |
271 | int dim, const Descriptor *mask, const CppFloat128Type *identity, |
272 | bool ordered) { |
273 | Terminator terminator{source, line}; |
274 | return GetTotalReduction<TypeCategory::Real, 16>(array, source, line, dim, |
275 | mask, |
276 | ReduceAccumulator<CppFloat128Type>{ |
277 | array, operation, identity, terminator}, |
278 | "REDUCE" ); |
279 | } |
280 | void RTDEF(ReduceReal16Dim)(Descriptor &result, const Descriptor &array, |
281 | ReductionOperation<CppFloat128Type> operation, const char *source, int line, |
282 | int dim, const Descriptor *mask, const CppFloat128Type *identity, |
283 | bool ordered) { |
284 | Terminator terminator{source, line}; |
285 | using Accumulator = ReduceAccumulator<CppFloat128Type>; |
286 | Accumulator accumulator{array, operation, identity, terminator}; |
287 | PartialReduction<Accumulator, TypeCategory::Real, 16>(result, array, |
288 | array.ElementBytes(), dim, mask, terminator, "REDUCE" , accumulator); |
289 | } |
290 | #endif |
291 | |
292 | void RTDEF(CppReduceComplex4)(std::complex<float> &result, |
293 | const Descriptor &array, ReductionOperation<std::complex<float>> operation, |
294 | const char *source, int line, int dim, const Descriptor *mask, |
295 | const std::complex<float> *identity, bool ordered) { |
296 | Terminator terminator{source, line}; |
297 | result = GetTotalReduction<TypeCategory::Complex, 4>(array, source, line, dim, |
298 | mask, |
299 | ReduceAccumulator<std::complex<float>>{ |
300 | array, operation, identity, terminator}, |
301 | "REDUCE" ); |
302 | } |
303 | void RTDEF(CppReduceComplex4Dim)(Descriptor &result, const Descriptor &array, |
304 | ReductionOperation<std::complex<float>> operation, const char *source, |
305 | int line, int dim, const Descriptor *mask, |
306 | const std::complex<float> *identity, bool ordered) { |
307 | Terminator terminator{source, line}; |
308 | using Accumulator = ReduceAccumulator<std::complex<float>>; |
309 | Accumulator accumulator{array, operation, identity, terminator}; |
310 | PartialReduction<Accumulator, TypeCategory::Complex, 4>(result, array, |
311 | array.ElementBytes(), dim, mask, terminator, "REDUCE" , accumulator); |
312 | } |
313 | void RTDEF(CppReduceComplex8)(std::complex<double> &result, |
314 | const Descriptor &array, ReductionOperation<std::complex<double>> operation, |
315 | const char *source, int line, int dim, const Descriptor *mask, |
316 | const std::complex<double> *identity, bool ordered) { |
317 | Terminator terminator{source, line}; |
318 | result = GetTotalReduction<TypeCategory::Complex, 8>(array, source, line, dim, |
319 | mask, |
320 | ReduceAccumulator<std::complex<double>>{ |
321 | array, operation, identity, terminator}, |
322 | "REDUCE" ); |
323 | } |
324 | void RTDEF(CppReduceComplex8Dim)(Descriptor &result, const Descriptor &array, |
325 | ReductionOperation<std::complex<double>> operation, const char *source, |
326 | int line, int dim, const Descriptor *mask, |
327 | const std::complex<double> *identity, bool ordered) { |
328 | Terminator terminator{source, line}; |
329 | using Accumulator = ReduceAccumulator<std::complex<double>>; |
330 | Accumulator accumulator{array, operation, identity, terminator}; |
331 | PartialReduction<Accumulator, TypeCategory::Complex, 8>(result, array, |
332 | array.ElementBytes(), dim, mask, terminator, "REDUCE" , accumulator); |
333 | } |
334 | #if LDBL_MANT_DIG == 64 |
335 | void RTDEF(CppReduceComplex10)(std::complex<long double> &result, |
336 | const Descriptor &array, |
337 | ReductionOperation<std::complex<long double>> operation, const char *source, |
338 | int line, int dim, const Descriptor *mask, |
339 | const std::complex<long double> *identity, bool ordered) { |
340 | Terminator terminator{source, line}; |
341 | result = GetTotalReduction<TypeCategory::Complex, 10>(array, source, line, |
342 | dim, mask, |
343 | ReduceAccumulator<std::complex<long double>>{ |
344 | array, operation, identity, terminator}, |
345 | "REDUCE" ); |
346 | } |
347 | void RTDEF(CppReduceComplex10Dim)(Descriptor &result, const Descriptor &array, |
348 | ReductionOperation<std::complex<long double>> operation, const char *source, |
349 | int line, int dim, const Descriptor *mask, |
350 | const std::complex<long double> *identity, bool ordered) { |
351 | Terminator terminator{source, line}; |
352 | using Accumulator = ReduceAccumulator<std::complex<long double>>; |
353 | Accumulator accumulator{array, operation, identity, terminator}; |
354 | PartialReduction<Accumulator, TypeCategory::Complex, 10>(result, array, |
355 | array.ElementBytes(), dim, mask, terminator, "REDUCE" , accumulator); |
356 | } |
357 | #endif |
358 | #if LDBL_MANT_DIG == 113 || HAS_FLOAT128 |
359 | void RTDEF(CppReduceComplex16)(std::complex<CppFloat128Type> &result, |
360 | const Descriptor &array, |
361 | ReductionOperation<std::complex<CppFloat128Type>> operation, |
362 | const char *source, int line, int dim, const Descriptor *mask, |
363 | const std::complex<CppFloat128Type> *identity, bool ordered) { |
364 | Terminator terminator{source, line}; |
365 | result = GetTotalReduction<TypeCategory::Complex, 16>(array, source, line, |
366 | dim, mask, |
367 | ReduceAccumulator<std::complex<CppFloat128Type>>{ |
368 | array, operation, identity, terminator}, |
369 | "REDUCE" ); |
370 | } |
371 | void RTDEF(CppReduceComplex16Dim)(Descriptor &result, const Descriptor &array, |
372 | ReductionOperation<std::complex<CppFloat128Type>> operation, |
373 | const char *source, int line, int dim, const Descriptor *mask, |
374 | const std::complex<CppFloat128Type> *identity, bool ordered) { |
375 | Terminator terminator{source, line}; |
376 | using Accumulator = ReduceAccumulator<std::complex<CppFloat128Type>>; |
377 | Accumulator accumulator{array, operation, identity, terminator}; |
378 | PartialReduction<Accumulator, TypeCategory::Complex, 16>(result, array, |
379 | array.ElementBytes(), dim, mask, terminator, "REDUCE" , accumulator); |
380 | } |
381 | #endif |
382 | |
383 | bool RTDEF(ReduceLogical1)(const Descriptor &array, |
384 | ReductionOperation<std::int8_t> operation, const char *source, int line, |
385 | int dim, const Descriptor *mask, const std::int8_t *identity, |
386 | bool ordered) { |
387 | return RTNAME(ReduceInteger1)( |
388 | array, operation, source, line, dim, mask, identity, ordered) != 0; |
389 | } |
390 | void RTDEF(ReduceLogical1Dim)(Descriptor &result, const Descriptor &array, |
391 | ReductionOperation<std::int8_t> operation, const char *source, int line, |
392 | int dim, const Descriptor *mask, const std::int8_t *identity, |
393 | bool ordered) { |
394 | RTNAME(ReduceInteger1Dim) |
395 | (result, array, operation, source, line, dim, mask, identity, ordered); |
396 | } |
397 | bool RTDEF(ReduceLogical2)(const Descriptor &array, |
398 | ReductionOperation<std::int16_t> operation, const char *source, int line, |
399 | int dim, const Descriptor *mask, const std::int16_t *identity, |
400 | bool ordered) { |
401 | return RTNAME(ReduceInteger2)( |
402 | array, operation, source, line, dim, mask, identity, ordered) != 0; |
403 | } |
404 | void RTDEF(ReduceLogical2Dim)(Descriptor &result, const Descriptor &array, |
405 | ReductionOperation<std::int16_t> operation, const char *source, int line, |
406 | int dim, const Descriptor *mask, const std::int16_t *identity, |
407 | bool ordered) { |
408 | RTNAME(ReduceInteger2Dim) |
409 | (result, array, operation, source, line, dim, mask, identity, ordered); |
410 | } |
411 | bool RTDEF(ReduceLogical4)(const Descriptor &array, |
412 | ReductionOperation<std::int32_t> operation, const char *source, int line, |
413 | int dim, const Descriptor *mask, const std::int32_t *identity, |
414 | bool ordered) { |
415 | return RTNAME(ReduceInteger4)( |
416 | array, operation, source, line, dim, mask, identity, ordered) != 0; |
417 | } |
418 | void RTDEF(ReduceLogical4Dim)(Descriptor &result, const Descriptor &array, |
419 | ReductionOperation<std::int32_t> operation, const char *source, int line, |
420 | int dim, const Descriptor *mask, const std::int32_t *identity, |
421 | bool ordered) { |
422 | RTNAME(ReduceInteger4Dim) |
423 | (result, array, operation, source, line, dim, mask, identity, ordered); |
424 | } |
425 | bool RTDEF(ReduceLogical8)(const Descriptor &array, |
426 | ReductionOperation<std::int64_t> operation, const char *source, int line, |
427 | int dim, const Descriptor *mask, const std::int64_t *identity, |
428 | bool ordered) { |
429 | return RTNAME(ReduceInteger8)( |
430 | array, operation, source, line, dim, mask, identity, ordered) != 0; |
431 | } |
432 | void RTDEF(ReduceLogical8Dim)(Descriptor &result, const Descriptor &array, |
433 | ReductionOperation<std::int64_t> operation, const char *source, int line, |
434 | int dim, const Descriptor *mask, const std::int64_t *identity, |
435 | bool ordered) { |
436 | RTNAME(ReduceInteger8Dim) |
437 | (result, array, operation, source, line, dim, mask, identity, ordered); |
438 | } |
439 | |
440 | void RTDEF(ReduceChar1)(char *result, const Descriptor &array, |
441 | ReductionCharOperation<char> operation, const char *source, int line, |
442 | int dim, const Descriptor *mask, const char *identity, bool ordered) { |
443 | Terminator terminator{source, line}; |
444 | BufferedReduceAccumulator<char, ReductionCharOperation<char>, |
445 | /*hasLength=*/true> |
446 | accumulator{array, operation, identity, terminator}; |
447 | DoTotalReduction<char>(array, dim, mask, accumulator, "REDUCE" , terminator); |
448 | accumulator.GetResult(result); |
449 | } |
450 | void RTDEF(ReduceCharacter1Dim)(Descriptor &result, const Descriptor &array, |
451 | ReductionCharOperation<char> operation, const char *source, int line, |
452 | int dim, const Descriptor *mask, const char *identity, bool ordered) { |
453 | Terminator terminator{source, line}; |
454 | using Accumulator = BufferedReduceAccumulator<char, |
455 | ReductionCharOperation<char>, /*hasLength=*/true>; |
456 | Accumulator accumulator{array, operation, identity, terminator}; |
457 | PartialReduction<Accumulator, TypeCategory::Character, 1>(result, array, |
458 | array.ElementBytes(), dim, mask, terminator, "REDUCE" , accumulator); |
459 | } |
460 | void RTDEF(ReduceChar2)(char16_t *result, const Descriptor &array, |
461 | ReductionCharOperation<char16_t> operation, const char *source, int line, |
462 | int dim, const Descriptor *mask, const char16_t *identity, bool ordered) { |
463 | Terminator terminator{source, line}; |
464 | BufferedReduceAccumulator<char16_t, ReductionCharOperation<char16_t>, |
465 | /*hasLength=*/true> |
466 | accumulator{array, operation, identity, terminator}; |
467 | DoTotalReduction<char16_t>( |
468 | array, dim, mask, accumulator, "REDUCE" , terminator); |
469 | accumulator.GetResult(result); |
470 | } |
471 | void RTDEF(ReduceCharacter2Dim)(Descriptor &result, const Descriptor &array, |
472 | ReductionCharOperation<char16_t> operation, const char *source, int line, |
473 | int dim, const Descriptor *mask, const char16_t *identity, bool ordered) { |
474 | Terminator terminator{source, line}; |
475 | using Accumulator = BufferedReduceAccumulator<char16_t, |
476 | ReductionCharOperation<char16_t>, /*hasLength=*/true>; |
477 | Accumulator accumulator{array, operation, identity, terminator}; |
478 | PartialReduction<Accumulator, TypeCategory::Character, 2>(result, array, |
479 | array.ElementBytes(), dim, mask, terminator, "REDUCE" , accumulator); |
480 | } |
481 | void RTDEF(ReduceChar4)(char32_t *result, const Descriptor &array, |
482 | ReductionCharOperation<char32_t> operation, const char *source, int line, |
483 | int dim, const Descriptor *mask, const char32_t *identity, bool ordered) { |
484 | Terminator terminator{source, line}; |
485 | BufferedReduceAccumulator<char32_t, ReductionCharOperation<char32_t>, |
486 | /*hasLength=*/true> |
487 | accumulator{array, operation, identity, terminator}; |
488 | DoTotalReduction<char32_t>( |
489 | array, dim, mask, accumulator, "REDUCE" , terminator); |
490 | accumulator.GetResult(result); |
491 | } |
492 | void RTDEF(ReduceCharacter4Dim)(Descriptor &result, const Descriptor &array, |
493 | ReductionCharOperation<char32_t> operation, const char *source, int line, |
494 | int dim, const Descriptor *mask, const char32_t *identity, bool ordered) { |
495 | Terminator terminator{source, line}; |
496 | using Accumulator = BufferedReduceAccumulator<char32_t, |
497 | ReductionCharOperation<char32_t>, /*hasLength=*/true>; |
498 | Accumulator accumulator{array, operation, identity, terminator}; |
499 | PartialReduction<Accumulator, TypeCategory::Character, 4>(result, array, |
500 | array.ElementBytes(), dim, mask, terminator, "REDUCE" , accumulator); |
501 | } |
502 | |
503 | void RTDEF(ReduceDerivedType)(char *result, const Descriptor &array, |
504 | ReductionDerivedTypeOperation operation, const char *source, int line, |
505 | int dim, const Descriptor *mask, const char *identity, bool ordered) { |
506 | Terminator terminator{source, line}; |
507 | BufferedReduceAccumulator<char, ReductionDerivedTypeOperation, |
508 | /*hasLength=*/false> |
509 | accumulator{array, operation, identity, terminator}; |
510 | DoTotalReduction<char>(array, dim, mask, accumulator, "REDUCE" , terminator); |
511 | accumulator.GetResult(result); |
512 | } |
513 | void RTDEF(ReduceDerivedTypeDim)(Descriptor &result, const Descriptor &array, |
514 | ReductionDerivedTypeOperation operation, const char *source, int line, |
515 | int dim, const Descriptor *mask, const char *identity, bool ordered) { |
516 | Terminator terminator{source, line}; |
517 | using Accumulator = BufferedReduceAccumulator<char, |
518 | ReductionDerivedTypeOperation, /*hasLength=*/false>; |
519 | Accumulator accumulator{array, operation, identity, terminator}; |
520 | PartialReduction<Accumulator, TypeCategory::Derived, 0>(result, array, |
521 | array.ElementBytes(), dim, mask, terminator, "REDUCE" , accumulator); |
522 | } |
523 | |
524 | RT_EXT_API_GROUP_END |
525 | } // extern "C" |
526 | } // namespace Fortran::runtime |
527 | |