1 //===-- flang/unittests/Runtime/Reductions.cpp ----------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "flang/Runtime/reduction.h"
10 #include "gtest/gtest.h"
12 #include "flang/Common/float128.h"
13 #include "flang/Runtime/allocatable.h"
14 #include "flang/Runtime/cpp-type.h"
15 #include "flang/Runtime/descriptor.h"
16 #include "flang/Runtime/reduce.h"
17 #include "flang/Runtime/type-code.h"
23 using namespace Fortran::runtime
;
24 using Fortran::common::TypeCategory
;
26 TEST(Reductions
, Int4Ops
) {
27 auto array
{MakeArray
<TypeCategory::Integer
, 4>(
28 std::vector
<int>{2, 3}, std::vector
<std::int32_t>{1, 2, 3, 4, 5, 6})};
29 std::int32_t sum
{RTNAME(SumInteger4
)(*array
, __FILE__
, __LINE__
)};
30 EXPECT_EQ(sum
, 21) << sum
;
31 std::int32_t all
{RTNAME(IAll4
)(*array
, __FILE__
, __LINE__
)};
32 EXPECT_EQ(all
, 0) << all
;
33 std::int32_t any
{RTNAME(IAny4
)(*array
, __FILE__
, __LINE__
)};
34 EXPECT_EQ(any
, 7) << any
;
35 std::int32_t eor
{RTNAME(IParity4
)(*array
, __FILE__
, __LINE__
)};
36 EXPECT_EQ(eor
, 7) << eor
;
39 TEST(Reductions
, DimMaskProductInt4
) {
40 std::vector
<int> shape
{2, 3};
41 auto array
{MakeArray
<TypeCategory::Integer
, 4>(
42 shape
, std::vector
<std::int32_t>{1, 2, 3, 4, 5, 6})};
43 auto mask
{MakeArray
<TypeCategory::Logical
, 1>(
44 shape
, std::vector
<bool>{true, false, false, true, true, true})};
45 StaticDescriptor
<maxRank
, true> statDesc
;
46 Descriptor
&prod
{statDesc
.descriptor()};
47 RTNAME(ProductDim
)(prod
, *array
, 1, __FILE__
, __LINE__
, &*mask
);
48 EXPECT_EQ(prod
.rank(), 1);
49 EXPECT_EQ(prod
.GetDimension(0).LowerBound(), 1);
50 EXPECT_EQ(prod
.GetDimension(0).Extent(), 3);
51 EXPECT_EQ(*prod
.ZeroBasedIndexedElement
<std::int32_t>(0), 1);
52 EXPECT_EQ(*prod
.ZeroBasedIndexedElement
<std::int32_t>(1), 4);
53 EXPECT_EQ(*prod
.ZeroBasedIndexedElement
<std::int32_t>(2), 30);
54 EXPECT_EQ(RTNAME(SumInteger4
)(prod
, __FILE__
, __LINE__
), 35);
58 TEST(Reductions
, DoubleMaxMinNorm2
) {
59 std::vector
<int> shape
{3, 4, 2}; // rows, columns, planes
60 // 0 -3 6 -9 12 -15 18 -21
61 // -1 4 -7 10 -13 16 -19 22
62 // 2 -5 8 -11 14 -17 20 22 <- note last two are equal to test
64 std::vector
<double> rawData
{0, -1, 2, -3, 4, -5, 6, -7, 8, -9, 10, -11, 12,
65 -13, 14, -15, 16, -17, 18, -19, 20, -21, 22, 22};
66 auto array
{MakeArray
<TypeCategory::Real
, 8>(shape
, rawData
)};
67 EXPECT_EQ(RTNAME(MaxvalReal8
)(*array
, __FILE__
, __LINE__
), 22.0);
68 EXPECT_EQ(RTNAME(MinvalReal8
)(*array
, __FILE__
, __LINE__
), -21.0);
70 for (auto x
: rawData
) {
73 naiveNorm2
= std::sqrt(naiveNorm2
);
75 std::abs(naiveNorm2
- RTNAME(Norm2_8
)(*array
, __FILE__
, __LINE__
))};
76 EXPECT_LE(norm2Error
, 0.000001 * naiveNorm2
);
77 StaticDescriptor
<2, true> statDesc
;
78 Descriptor
&loc
{statDesc
.descriptor()};
80 (loc
, *array
, /*KIND=*/8, __FILE__
, __LINE__
, /*MASK=*/nullptr,
82 EXPECT_EQ(loc
.rank(), 1);
83 EXPECT_EQ(loc
.type().raw(), (TypeCode
{TypeCategory::Integer
, 8}.raw()));
84 EXPECT_EQ(loc
.GetDimension(0).LowerBound(), 1);
85 EXPECT_EQ(loc
.GetDimension(0).Extent(), 3);
87 *array
->Element
<double>(loc
.ZeroBasedIndexedElement
<SubscriptValue
>(0)),
89 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int64_t>(0), 2);
90 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int64_t>(1), 4);
91 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int64_t>(2), 2);
94 (loc
, *array
, /*KIND=*/8, __FILE__
, __LINE__
, /*MASK=*/nullptr,
96 EXPECT_EQ(loc
.rank(), 1);
97 EXPECT_EQ(loc
.type().raw(), (TypeCode
{TypeCategory::Integer
, 8}.raw()));
98 EXPECT_EQ(loc
.GetDimension(0).LowerBound(), 1);
99 EXPECT_EQ(loc
.GetDimension(0).Extent(), 3);
101 *array
->Element
<double>(loc
.ZeroBasedIndexedElement
<SubscriptValue
>(0)),
103 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int64_t>(0), 3);
104 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int64_t>(1), 4);
105 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int64_t>(2), 2);
108 (loc
, *array
, /*KIND=*/2, /*DIM=*/1, __FILE__
, __LINE__
, /*MASK=*/nullptr,
110 EXPECT_EQ(loc
.rank(), 2);
111 EXPECT_EQ(loc
.type().raw(), (TypeCode
{TypeCategory::Integer
, 2}.raw()));
112 EXPECT_EQ(loc
.GetDimension(0).LowerBound(), 1);
113 EXPECT_EQ(loc
.GetDimension(0).Extent(), 4);
114 EXPECT_EQ(loc
.GetDimension(1).LowerBound(), 1);
115 EXPECT_EQ(loc
.GetDimension(1).Extent(), 2);
116 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int16_t>(0), 2); // -1
117 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int16_t>(1), 3); // -5
118 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int16_t>(2), 2); // -2
119 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int16_t>(3), 3); // -11
120 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int16_t>(4), 2); // -13
121 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int16_t>(5), 3); // -17
122 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int16_t>(6), 2); // -19
123 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int16_t>(7), 1); // -21
125 auto mask
{MakeArray
<TypeCategory::Logical
, 1>(shape
,
126 std::vector
<bool>{false, false, false, false, false, true, false, true,
127 false, false, true, true, true, false, false, true, false, true, true,
128 true, false, true, true, true})};
130 (loc
, *array
, /*KIND=*/2, /*DIM=*/3, __FILE__
, __LINE__
, /*MASK=*/&*mask
,
132 EXPECT_EQ(loc
.rank(), 2);
133 EXPECT_EQ(loc
.type().raw(), (TypeCode
{TypeCategory::Integer
, 2}.raw()));
134 EXPECT_EQ(loc
.GetDimension(0).LowerBound(), 1);
135 EXPECT_EQ(loc
.GetDimension(0).Extent(), 3);
136 EXPECT_EQ(loc
.GetDimension(1).LowerBound(), 1);
137 EXPECT_EQ(loc
.GetDimension(1).Extent(), 4);
138 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int16_t>(0), 2); // 12
139 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int16_t>(1), 0);
140 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int16_t>(2), 0);
141 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int16_t>(3), 2); // -15
142 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int16_t>(4), 0);
143 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int16_t>(5), 1); // -5
144 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int16_t>(6), 2); // 18
145 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int16_t>(7), 1); // -7
146 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int16_t>(8), 0);
147 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int16_t>(9), 2); // -21
148 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int16_t>(10), 2); // 22
149 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int16_t>(11), 2); // 22
151 // Test scalar result for MaxlocDim, MinlocDim, MaxvalDim, MinvalDim.
152 // A scalar result occurs when you have a rank 1 array and dim == 1.
153 std::vector
<int> shape1
{24};
154 auto array1
{MakeArray
<TypeCategory::Real
, 8>(shape1
, rawData
)};
155 StaticDescriptor
<2, true> statDesc0
[1];
156 Descriptor
&scalarResult
{statDesc0
[0].descriptor()};
158 (scalarResult
, *array1
, /*KIND=*/2, /*DIM=*/1, __FILE__
, __LINE__
,
159 /*MASK=*/nullptr, /*BACK=*/false);
160 EXPECT_EQ(scalarResult
.rank(), 0);
161 EXPECT_EQ(*scalarResult
.ZeroBasedIndexedElement
<std::int16_t>(0), 23);
162 scalarResult
.Destroy();
164 // Test .FALSE. scalar MASK argument
165 auto falseMask
{MakeArray
<TypeCategory::Logical
, 4>(
166 std::vector
<int>{}, std::vector
<std::int32_t>{0})};
168 (loc
, *array
, /*KIND=*/4, /*DIM=*/2, __FILE__
, __LINE__
,
169 /*MASK=*/&*falseMask
, /*BACK=*/false);
170 EXPECT_EQ(loc
.rank(), 2);
171 EXPECT_EQ(loc
.type().raw(), (TypeCode
{TypeCategory::Integer
, 4}.raw()));
172 EXPECT_EQ(loc
.GetDimension(0).LowerBound(), 1);
173 EXPECT_EQ(loc
.GetDimension(0).Extent(), 3);
174 EXPECT_EQ(loc
.GetDimension(1).LowerBound(), 1);
175 EXPECT_EQ(loc
.GetDimension(1).Extent(), 2);
176 for (int i
{0}; i
< 6; ++i
) {
177 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int32_t>(0), 0);
181 // Test .TRUE. scalar MASK argument
182 auto trueMask
{MakeArray
<TypeCategory::Logical
, 4>(
183 std::vector
<int>{}, std::vector
<std::int32_t>{1})};
185 (loc
, *array
, /*KIND=*/4, /*DIM=*/2, __FILE__
, __LINE__
,
186 /*MASK=*/&*trueMask
, /*BACK=*/false);
187 EXPECT_EQ(loc
.rank(), 2);
188 EXPECT_EQ(loc
.type().raw(), (TypeCode
{TypeCategory::Integer
, 4}.raw()));
189 EXPECT_EQ(loc
.GetDimension(0).LowerBound(), 1);
190 EXPECT_EQ(loc
.GetDimension(0).Extent(), 3);
191 EXPECT_EQ(loc
.GetDimension(1).LowerBound(), 1);
192 EXPECT_EQ(loc
.GetDimension(1).Extent(), 2);
193 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int32_t>(0), 3);
194 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int32_t>(1), 4);
195 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int32_t>(2), 3);
196 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int32_t>(3), 3);
197 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int32_t>(4), 4);
198 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int32_t>(5), 4);
202 (scalarResult
, *array1
, /*KIND=*/2, /*DIM=*/1, __FILE__
, __LINE__
,
203 /*MASK=*/nullptr, /*BACK=*/true);
204 EXPECT_EQ(scalarResult
.rank(), 0);
205 EXPECT_EQ(*scalarResult
.ZeroBasedIndexedElement
<std::int16_t>(0), 22);
206 scalarResult
.Destroy();
208 // Test .FALSE. scalar MASK argument
210 (loc
, *array
, /*KIND=*/4, /*DIM=*/2, __FILE__
, __LINE__
,
211 /*MASK=*/&*falseMask
, /*BACK=*/false);
212 EXPECT_EQ(loc
.rank(), 2);
213 EXPECT_EQ(loc
.type().raw(), (TypeCode
{TypeCategory::Integer
, 4}.raw()));
214 EXPECT_EQ(loc
.GetDimension(0).LowerBound(), 1);
215 EXPECT_EQ(loc
.GetDimension(0).Extent(), 3);
216 EXPECT_EQ(loc
.GetDimension(1).LowerBound(), 1);
217 EXPECT_EQ(loc
.GetDimension(1).Extent(), 2);
218 for (int i
{0}; i
< 6; ++i
) {
219 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int32_t>(0), 0);
223 // Test .TRUE. scalar MASK argument
225 (loc
, *array
, /*KIND=*/4, /*DIM=*/2, __FILE__
, __LINE__
,
226 /*MASK=*/&*trueMask
, /*BACK=*/false);
227 EXPECT_EQ(loc
.rank(), 2);
228 EXPECT_EQ(loc
.type().raw(), (TypeCode
{TypeCategory::Integer
, 4}.raw()));
229 EXPECT_EQ(loc
.GetDimension(0).LowerBound(), 1);
230 EXPECT_EQ(loc
.GetDimension(0).Extent(), 3);
231 EXPECT_EQ(loc
.GetDimension(1).LowerBound(), 1);
232 EXPECT_EQ(loc
.GetDimension(1).Extent(), 2);
233 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int32_t>(0), 4);
234 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int32_t>(1), 3);
235 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int32_t>(2), 4);
236 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int32_t>(3), 4);
237 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int32_t>(4), 3);
238 EXPECT_EQ(*loc
.ZeroBasedIndexedElement
<std::int32_t>(5), 2);
242 (scalarResult
, *array1
, /*DIM=*/1, __FILE__
, __LINE__
, /*MASK=*/nullptr);
243 EXPECT_EQ(scalarResult
.rank(), 0);
244 EXPECT_EQ(*scalarResult
.ZeroBasedIndexedElement
<double>(0), 22.0);
245 scalarResult
.Destroy();
247 (scalarResult
, *array1
, /*DIM=*/1, __FILE__
, __LINE__
, /*MASK=*/nullptr);
248 EXPECT_EQ(scalarResult
.rank(), 0);
249 EXPECT_EQ(*scalarResult
.ZeroBasedIndexedElement
<double>(0), -21.0);
250 scalarResult
.Destroy();
253 TEST(Reductions
, Character
) {
254 std::vector
<int> shape
{2, 3};
255 auto array
{MakeArray
<TypeCategory::Character
, 1>(shape
,
256 std::vector
<std::string
>{"abc", "def", "ghi", "jkl", "mno", "abc"}, 3)};
257 StaticDescriptor
<1, true> statDesc
[2];
258 Descriptor
&res
{statDesc
[0].descriptor()};
259 RTNAME(MaxvalCharacter
)(res
, *array
, __FILE__
, __LINE__
);
260 EXPECT_EQ(res
.rank(), 0);
261 EXPECT_EQ(res
.type().raw(), (TypeCode
{TypeCategory::Character
, 1}.raw()));
262 EXPECT_EQ(std::memcmp(res
.OffsetElement
<char>(), "mno", 3), 0);
264 RTNAME(MinvalCharacter
)(res
, *array
, __FILE__
, __LINE__
);
265 EXPECT_EQ(res
.rank(), 0);
266 EXPECT_EQ(res
.type().raw(), (TypeCode
{TypeCategory::Character
, 1}.raw()));
267 EXPECT_EQ(std::memcmp(res
.OffsetElement
<char>(), "abc", 3), 0);
269 RTNAME(MaxlocCharacter
)
270 (res
, *array
, /*KIND=*/4, __FILE__
, __LINE__
, /*MASK=*/nullptr,
272 EXPECT_EQ(res
.rank(), 1);
273 EXPECT_EQ(res
.type().raw(), (TypeCode
{TypeCategory::Integer
, 4}.raw()));
274 EXPECT_EQ(res
.GetDimension(0).LowerBound(), 1);
275 EXPECT_EQ(res
.GetDimension(0).Extent(), 2);
276 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<std::int32_t>(0), 1);
277 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<std::int32_t>(1), 3);
279 auto mask
{MakeArray
<TypeCategory::Logical
, 1>(
280 shape
, std::vector
<bool>{false, true, false, true, false, true})};
281 RTNAME(MaxlocCharacter
)
282 (res
, *array
, /*KIND=*/4, __FILE__
, __LINE__
, /*MASK=*/&*mask
,
284 EXPECT_EQ(res
.rank(), 1);
285 EXPECT_EQ(res
.type().raw(), (TypeCode
{TypeCategory::Integer
, 4}.raw()));
286 EXPECT_EQ(res
.GetDimension(0).LowerBound(), 1);
287 EXPECT_EQ(res
.GetDimension(0).Extent(), 2);
288 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<std::int32_t>(0), 2);
289 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<std::int32_t>(1), 2);
291 RTNAME(MinlocCharacter
)
292 (res
, *array
, /*KIND=*/4, __FILE__
, __LINE__
, /*MASK=*/nullptr,
294 EXPECT_EQ(res
.rank(), 1);
295 EXPECT_EQ(res
.type().raw(), (TypeCode
{TypeCategory::Integer
, 4}.raw()));
296 EXPECT_EQ(res
.GetDimension(0).LowerBound(), 1);
297 EXPECT_EQ(res
.GetDimension(0).Extent(), 2);
298 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<std::int32_t>(0), 1);
299 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<std::int32_t>(1), 1);
301 RTNAME(MinlocCharacter
)
302 (res
, *array
, /*KIND=*/4, __FILE__
, __LINE__
, /*MASK=*/nullptr,
304 EXPECT_EQ(res
.rank(), 1);
305 EXPECT_EQ(res
.type().raw(), (TypeCode
{TypeCategory::Integer
, 4}.raw()));
306 EXPECT_EQ(res
.GetDimension(0).LowerBound(), 1);
307 EXPECT_EQ(res
.GetDimension(0).Extent(), 2);
308 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<std::int32_t>(0), 2);
309 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<std::int32_t>(1), 3);
311 RTNAME(MinlocCharacter
)
312 (res
, *array
, /*KIND=*/4, __FILE__
, __LINE__
, /*MASK=*/&*mask
,
314 EXPECT_EQ(res
.rank(), 1);
315 EXPECT_EQ(res
.type().raw(), (TypeCode
{TypeCategory::Integer
, 4}.raw()));
316 EXPECT_EQ(res
.GetDimension(0).LowerBound(), 1);
317 EXPECT_EQ(res
.GetDimension(0).Extent(), 2);
318 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<std::int32_t>(0), 2);
319 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<std::int32_t>(1), 3);
321 static const char targetChar
[]{"abc"};
322 Descriptor
&target
{statDesc
[1].descriptor()};
323 target
.Establish(1, std::strlen(targetChar
),
324 const_cast<void *>(static_cast<const void *>(&targetChar
)), 0, nullptr,
325 CFI_attribute_pointer
);
327 (res
, *array
, target
, /*KIND=*/4, __FILE__
, __LINE__
, nullptr,
329 EXPECT_EQ(res
.rank(), 1);
330 EXPECT_EQ(res
.type().raw(), (TypeCode
{TypeCategory::Integer
, 4}.raw()));
331 EXPECT_EQ(res
.GetDimension(0).LowerBound(), 1);
332 EXPECT_EQ(res
.GetDimension(0).Extent(), 2);
333 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<std::int32_t>(0), 1);
334 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<std::int32_t>(1), 1);
337 (res
, *array
, target
, /*KIND=*/4, __FILE__
, __LINE__
, nullptr, /*BACK=*/true);
338 EXPECT_EQ(res
.rank(), 1);
339 EXPECT_EQ(res
.type().raw(), (TypeCode
{TypeCategory::Integer
, 4}.raw()));
340 EXPECT_EQ(res
.GetDimension(0).LowerBound(), 1);
341 EXPECT_EQ(res
.GetDimension(0).Extent(), 2);
342 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<std::int32_t>(0), 2);
343 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<std::int32_t>(1), 3);
347 TEST(Reductions
, Logical
) {
348 std::vector
<int> shape
{2, 2};
349 auto array
{MakeArray
<TypeCategory::Logical
, 4>(
350 shape
, std::vector
<std::int32_t>{false, false, true, true})};
351 ASSERT_EQ(array
->ElementBytes(), std::size_t{4});
352 EXPECT_EQ(RTNAME(All
)(*array
, __FILE__
, __LINE__
), false);
353 EXPECT_EQ(RTNAME(Any
)(*array
, __FILE__
, __LINE__
), true);
354 EXPECT_EQ(RTNAME(Parity
)(*array
, __FILE__
, __LINE__
), false);
355 EXPECT_EQ(RTNAME(Count
)(*array
, __FILE__
, __LINE__
), 2);
356 StaticDescriptor
<2, true> statDesc
[2];
357 Descriptor
&res
{statDesc
[0].descriptor()};
358 RTNAME(AllDim
)(res
, *array
, /*DIM=*/1, __FILE__
, __LINE__
);
359 EXPECT_EQ(res
.rank(), 1);
360 EXPECT_EQ(res
.type().raw(), (TypeCode
{TypeCategory::Logical
, 4}.raw()));
361 EXPECT_EQ(res
.GetDimension(0).LowerBound(), 1);
362 EXPECT_EQ(res
.GetDimension(0).Extent(), 2);
363 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<std::int32_t>(0), 0);
364 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<std::int32_t>(1), 1);
366 RTNAME(AllDim
)(res
, *array
, /*DIM=*/2, __FILE__
, __LINE__
);
367 EXPECT_EQ(res
.rank(), 1);
368 EXPECT_EQ(res
.type().raw(), (TypeCode
{TypeCategory::Logical
, 4}.raw()));
369 EXPECT_EQ(res
.GetDimension(0).LowerBound(), 1);
370 EXPECT_EQ(res
.GetDimension(0).Extent(), 2);
371 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<std::int32_t>(0), 0);
372 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<std::int32_t>(1), 0);
374 // Test scalar result for AllDim.
375 // A scalar result occurs when you have a rank 1 array.
376 std::vector
<int> shape1
{4};
377 auto array1
{MakeArray
<TypeCategory::Logical
, 4>(
378 shape1
, std::vector
<std::int32_t>{false, false, true, true})};
379 StaticDescriptor
<1, true> statDesc0
[1];
380 Descriptor
&scalarResult
{statDesc0
[0].descriptor()};
381 RTNAME(AllDim
)(scalarResult
, *array1
, /*DIM=*/1, __FILE__
, __LINE__
);
382 EXPECT_EQ(scalarResult
.rank(), 0);
383 EXPECT_EQ(*scalarResult
.ZeroBasedIndexedElement
<std::int32_t>(0), 0);
384 scalarResult
.Destroy();
385 RTNAME(AnyDim
)(res
, *array
, /*DIM=*/1, __FILE__
, __LINE__
);
386 EXPECT_EQ(res
.rank(), 1);
387 EXPECT_EQ(res
.type().raw(), (TypeCode
{TypeCategory::Logical
, 4}.raw()));
388 EXPECT_EQ(res
.GetDimension(0).LowerBound(), 1);
389 EXPECT_EQ(res
.GetDimension(0).Extent(), 2);
390 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<std::int32_t>(0), 0);
391 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<std::int32_t>(1), 1);
393 RTNAME(AnyDim
)(res
, *array
, /*DIM=*/2, __FILE__
, __LINE__
);
394 EXPECT_EQ(res
.rank(), 1);
395 EXPECT_EQ(res
.type().raw(), (TypeCode
{TypeCategory::Logical
, 4}.raw()));
396 EXPECT_EQ(res
.GetDimension(0).LowerBound(), 1);
397 EXPECT_EQ(res
.GetDimension(0).Extent(), 2);
398 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<std::int32_t>(0), 1);
399 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<std::int32_t>(1), 1);
401 // Test scalar result for AnyDim.
402 // A scalar result occurs when you have a rank 1 array.
403 RTNAME(AnyDim
)(scalarResult
, *array1
, /*DIM=*/1, __FILE__
, __LINE__
);
404 EXPECT_EQ(scalarResult
.rank(), 0);
405 EXPECT_EQ(*scalarResult
.ZeroBasedIndexedElement
<std::int32_t>(0), 1);
406 scalarResult
.Destroy();
407 RTNAME(ParityDim
)(res
, *array
, /*DIM=*/1, __FILE__
, __LINE__
);
408 EXPECT_EQ(res
.rank(), 1);
409 EXPECT_EQ(res
.type().raw(), (TypeCode
{TypeCategory::Logical
, 4}.raw()));
410 EXPECT_EQ(res
.GetDimension(0).LowerBound(), 1);
411 EXPECT_EQ(res
.GetDimension(0).Extent(), 2);
412 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<std::int32_t>(0), 0);
413 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<std::int32_t>(1), 0);
415 RTNAME(ParityDim
)(res
, *array
, /*DIM=*/2, __FILE__
, __LINE__
);
416 EXPECT_EQ(res
.rank(), 1);
417 EXPECT_EQ(res
.type().raw(), (TypeCode
{TypeCategory::Logical
, 4}.raw()));
418 EXPECT_EQ(res
.GetDimension(0).LowerBound(), 1);
419 EXPECT_EQ(res
.GetDimension(0).Extent(), 2);
420 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<std::int32_t>(0), 1);
421 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<std::int32_t>(1), 1);
423 // Test scalar result for ParityDim.
424 // A scalar result occurs when you have a rank 1 array.
425 RTNAME(ParityDim
)(scalarResult
, *array1
, /*DIM=*/1, __FILE__
, __LINE__
);
426 EXPECT_EQ(scalarResult
.rank(), 0);
427 EXPECT_EQ(*scalarResult
.ZeroBasedIndexedElement
<std::int32_t>(0), 0);
428 scalarResult
.Destroy();
429 RTNAME(CountDim
)(res
, *array
, /*DIM=*/1, /*KIND=*/4, __FILE__
, __LINE__
);
430 EXPECT_EQ(res
.rank(), 1);
431 EXPECT_EQ(res
.type().raw(), (TypeCode
{TypeCategory::Integer
, 4}.raw()));
432 EXPECT_EQ(res
.GetDimension(0).LowerBound(), 1);
433 EXPECT_EQ(res
.GetDimension(0).Extent(), 2);
434 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<std::int32_t>(0), 0);
435 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<std::int32_t>(1), 2);
437 RTNAME(CountDim
)(res
, *array
, /*DIM=*/2, /*KIND=*/8, __FILE__
, __LINE__
);
438 EXPECT_EQ(res
.rank(), 1);
439 EXPECT_EQ(res
.type().raw(), (TypeCode
{TypeCategory::Integer
, 8}.raw()));
440 EXPECT_EQ(res
.GetDimension(0).LowerBound(), 1);
441 EXPECT_EQ(res
.GetDimension(0).Extent(), 2);
442 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<std::int64_t>(0), 1);
443 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<std::int64_t>(1), 1);
445 // Test scalar result for CountDim.
446 // A scalar result occurs when you have a rank 1 array and dim == 1.
448 (scalarResult
, *array1
, /*DIM=*/1, /*KIND=*/8, __FILE__
, __LINE__
);
449 EXPECT_EQ(scalarResult
.rank(), 0);
450 EXPECT_EQ(*scalarResult
.ZeroBasedIndexedElement
<std::int64_t>(0), 2);
451 scalarResult
.Destroy();
452 bool boolValue
{false};
453 Descriptor
&target
{statDesc
[1].descriptor()};
454 target
.Establish(TypeCategory::Logical
, 1, static_cast<void *>(&boolValue
), 0,
455 nullptr, CFI_attribute_pointer
);
457 (res
, *array
, target
, /*KIND=*/4, __FILE__
, __LINE__
, nullptr,
459 EXPECT_EQ(res
.rank(), 1);
460 EXPECT_EQ(res
.type().raw(), (TypeCode
{TypeCategory::Integer
, 4}.raw()));
461 EXPECT_EQ(res
.GetDimension(0).LowerBound(), 1);
462 EXPECT_EQ(res
.GetDimension(0).Extent(), 2);
463 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<std::int32_t>(0), 1);
464 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<std::int32_t>(1), 1);
468 (res
, *array
, target
, /*KIND=*/4, __FILE__
, __LINE__
, nullptr, /*BACK=*/true);
469 EXPECT_EQ(res
.rank(), 1);
470 EXPECT_EQ(res
.type().raw(), (TypeCode
{TypeCategory::Integer
, 4}.raw()));
471 EXPECT_EQ(res
.GetDimension(0).LowerBound(), 1);
472 EXPECT_EQ(res
.GetDimension(0).Extent(), 2);
473 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<std::int32_t>(0), 2);
474 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<std::int32_t>(1), 2);
478 TEST(Reductions
, FindlocNumeric
) {
479 std::vector
<int> shape
{2, 3};
480 auto realArray
{MakeArray
<TypeCategory::Real
, 8>(shape
,
481 std::vector
<double>{0.0, -0.0, 1.0, 3.14,
482 std::numeric_limits
<double>::quiet_NaN(),
483 std::numeric_limits
<double>::infinity()})};
484 ASSERT_EQ(realArray
->ElementBytes(), sizeof(double));
485 StaticDescriptor
<2, true> statDesc
[2];
486 Descriptor
&res
{statDesc
[0].descriptor()};
487 // Find the first zero
488 Descriptor
&target
{statDesc
[1].descriptor()};
490 target
.Establish(TypeCategory::Real
, 8, static_cast<void *>(&value
), 0,
491 nullptr, CFI_attribute_pointer
);
493 (res
, *realArray
, target
, 8, __FILE__
, __LINE__
, nullptr, /*BACK=*/false);
494 EXPECT_EQ(res
.rank(), 1);
495 EXPECT_EQ(res
.type().raw(), (TypeCode
{TypeCategory::Integer
, 8}.raw()));
496 EXPECT_EQ(res
.GetDimension(0).LowerBound(), 1);
497 EXPECT_EQ(res
.GetDimension(0).UpperBound(), 2);
498 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<SubscriptValue
>(0), 1);
499 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<SubscriptValue
>(1), 1);
501 // Find last zero (even though it's negative)
503 (res
, *realArray
, target
, 8, __FILE__
, __LINE__
, nullptr, /*BACK=*/true);
504 EXPECT_EQ(res
.rank(), 1);
505 EXPECT_EQ(res
.type().raw(), (TypeCode
{TypeCategory::Integer
, 8}.raw()));
506 EXPECT_EQ(res
.GetDimension(0).LowerBound(), 1);
507 EXPECT_EQ(res
.GetDimension(0).UpperBound(), 2);
508 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<SubscriptValue
>(0), 2);
509 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<SubscriptValue
>(1), 1);
512 value
= std::numeric_limits
<double>::infinity();
514 (res
, *realArray
, target
, 8, __FILE__
, __LINE__
, nullptr, /*BACK=*/false);
515 EXPECT_EQ(res
.rank(), 1);
516 EXPECT_EQ(res
.type().raw(), (TypeCode
{TypeCategory::Integer
, 8}.raw()));
517 EXPECT_EQ(res
.GetDimension(0).LowerBound(), 1);
518 EXPECT_EQ(res
.GetDimension(0).UpperBound(), 2);
519 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<SubscriptValue
>(0), 2);
520 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<SubscriptValue
>(1), 3);
522 // Ensure that we can't find a NaN
523 value
= std::numeric_limits
<double>::quiet_NaN();
525 (res
, *realArray
, target
, 8, __FILE__
, __LINE__
, nullptr, /*BACK=*/false);
526 EXPECT_EQ(res
.rank(), 1);
527 EXPECT_EQ(res
.type().raw(), (TypeCode
{TypeCategory::Integer
, 8}.raw()));
528 EXPECT_EQ(res
.GetDimension(0).LowerBound(), 1);
529 EXPECT_EQ(res
.GetDimension(0).UpperBound(), 2);
530 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<SubscriptValue
>(0), 0);
531 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<SubscriptValue
>(1), 0);
533 // Find a value of a distinct type
535 target
.Establish(TypeCategory::Integer
, 4, static_cast<void *>(&intValue
), 0,
536 nullptr, CFI_attribute_pointer
);
538 (res
, *realArray
, target
, 8, __FILE__
, __LINE__
, nullptr, /*BACK=*/false);
539 EXPECT_EQ(res
.rank(), 1);
540 EXPECT_EQ(res
.type().raw(), (TypeCode
{TypeCategory::Integer
, 8}.raw()));
541 EXPECT_EQ(res
.GetDimension(0).LowerBound(), 1);
542 EXPECT_EQ(res
.GetDimension(0).UpperBound(), 2);
543 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<SubscriptValue
>(0), 1);
544 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<SubscriptValue
>(1), 2);
546 // Partial reductions
548 target
.Establish(TypeCategory::Real
, 8, static_cast<void *>(&value
), 0,
549 nullptr, CFI_attribute_pointer
);
551 (res
, *realArray
, target
, 8, /*DIM=*/1, __FILE__
, __LINE__
, nullptr,
553 EXPECT_EQ(res
.rank(), 1);
554 EXPECT_EQ(res
.type().raw(), (TypeCode
{TypeCategory::Integer
, 8}.raw()));
555 EXPECT_EQ(res
.GetDimension(0).LowerBound(), 1);
556 EXPECT_EQ(res
.GetDimension(0).UpperBound(), 3);
557 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<SubscriptValue
>(0), 0);
558 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<SubscriptValue
>(1), 1);
559 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<SubscriptValue
>(2), 0);
562 (res
, *realArray
, target
, 8, /*DIM=*/2, __FILE__
, __LINE__
, nullptr,
564 EXPECT_EQ(res
.rank(), 1);
565 EXPECT_EQ(res
.type().raw(), (TypeCode
{TypeCategory::Integer
, 8}.raw()));
566 EXPECT_EQ(res
.GetDimension(0).LowerBound(), 1);
567 EXPECT_EQ(res
.GetDimension(0).UpperBound(), 2);
568 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<SubscriptValue
>(0), 2);
569 EXPECT_EQ(*res
.ZeroBasedIndexedElement
<SubscriptValue
>(1), 0);
571 // Test scalar result for FindlocDim.
572 // A scalar result occurs when you have a rank 1 array, value, and dim == 1.
573 std::vector
<int> shape1
{6};
574 auto realArray1
{MakeArray
<TypeCategory::Real
, 8>(shape1
,
575 std::vector
<double>{0.0, -0.0, 1.0, 3.14,
576 std::numeric_limits
<double>::quiet_NaN(),
577 std::numeric_limits
<double>::infinity()})};
578 StaticDescriptor
<1, true> statDesc0
[1];
579 Descriptor
&scalarResult
{statDesc0
[0].descriptor()};
581 (scalarResult
, *realArray1
, target
, 8, /*DIM=*/1, __FILE__
, __LINE__
, nullptr,
583 EXPECT_EQ(scalarResult
.rank(), 0);
584 EXPECT_EQ(*scalarResult
.ZeroBasedIndexedElement
<SubscriptValue
>(0), 3);
585 scalarResult
.Destroy();
588 TEST(Reductions
, DotProduct
) {
589 auto realVector
{MakeArray
<TypeCategory::Real
, 8>(
590 std::vector
<int>{4}, std::vector
<double>{0.0, -0.0, 1.0, -2.0})};
592 RTNAME(DotProductReal8
)(*realVector
, *realVector
, __FILE__
, __LINE__
),
594 auto complexVector
{MakeArray
<TypeCategory::Complex
, 4>(std::vector
<int>{4},
595 std::vector
<std::complex<float>>{
596 {0.0}, {-0.0, -0.0}, {1.0, -2.0}, {-2.0, 4.0}})};
597 std::complex<double> result8
;
598 RTNAME(CppDotProductComplex8
)
599 (result8
, *realVector
, *complexVector
, __FILE__
, __LINE__
);
600 EXPECT_EQ(result8
, (std::complex<double>{5.0, -10.0}));
601 RTNAME(CppDotProductComplex8
)
602 (result8
, *complexVector
, *realVector
, __FILE__
, __LINE__
);
603 EXPECT_EQ(result8
, (std::complex<double>{5.0, 10.0}));
604 std::complex<float> result4
;
605 RTNAME(CppDotProductComplex4
)
606 (result4
, *complexVector
, *complexVector
, __FILE__
, __LINE__
);
607 EXPECT_EQ(result4
, (std::complex<float>{25.0, 0.0}));
608 auto logicalVector1
{MakeArray
<TypeCategory::Logical
, 1>(
609 std::vector
<int>{4}, std::vector
<bool>{false, false, true, true})};
610 EXPECT_TRUE(RTNAME(DotProductLogical
)(
611 *logicalVector1
, *logicalVector1
, __FILE__
, __LINE__
));
612 auto logicalVector2
{MakeArray
<TypeCategory::Logical
, 1>(
613 std::vector
<int>{4}, std::vector
<bool>{true, true, false, false})};
614 EXPECT_TRUE(RTNAME(DotProductLogical
)(
615 *logicalVector2
, *logicalVector2
, __FILE__
, __LINE__
));
616 EXPECT_FALSE(RTNAME(DotProductLogical
)(
617 *logicalVector1
, *logicalVector2
, __FILE__
, __LINE__
));
618 EXPECT_FALSE(RTNAME(DotProductLogical
)(
619 *logicalVector2
, *logicalVector1
, __FILE__
, __LINE__
));
622 #if HAS_LDBL128 || HAS_FLOAT128
623 TEST(Reductions
, ExtremaReal16
) {
624 // The identity value for Min/Maxval for REAL(16) was mistakenly
626 using ElemType
= CppTypeFor
<TypeCategory::Real
, 16>;
627 std::vector
<int> shape
{3};
629 std::vector
<ElemType
> rawMinData
{1.0, 2.0, 3.0};
630 auto minArray
{MakeArray
<TypeCategory::Real
, 16>(shape
, rawMinData
)};
631 EXPECT_EQ(RTNAME(MinvalReal16
)(*minArray
, __FILE__
, __LINE__
), 1.0);
633 std::vector
<ElemType
> rawMaxData
{-1.0, -2.0, -3.0};
634 auto maxArray
{MakeArray
<TypeCategory::Real
, 16>(shape
, rawMaxData
)};
635 EXPECT_EQ(RTNAME(MaxvalReal16
)(*maxArray
, __FILE__
, __LINE__
), -1.0);
637 #endif // HAS_LDBL128 || HAS_FLOAT128
639 static std::int32_t IAdd(const std::int32_t *x
, const std::int32_t *y
) {
643 static std::int32_t IMultiply(const std::int32_t *x
, const std::int32_t *y
) {
647 TEST(Reductions
, ReduceInt4
) {
648 auto intVector
{MakeArray
<TypeCategory::Integer
, 4>(
649 std::vector
<int>{4}, std::vector
<std::int32_t>{1, 2, 3, 4})};
651 RTNAME(ReduceInteger4Ref
)(*intVector
, IAdd
, __FILE__
, __LINE__
), 10);
653 RTNAME(ReduceInteger4Ref
)(*intVector
, IMultiply
, __FILE__
, __LINE__
), 24);
655 TEST(Reductions
, ReduceInt4Dim
) {
656 auto intMatrix
{MakeArray
<TypeCategory::Integer
, 4>(
657 std::vector
<int>{2, 2}, std::vector
<std::int32_t>{1, 2, 3, 4})};
658 StaticDescriptor
<2, true> statDesc
;
659 Descriptor
&sums
{statDesc
.descriptor()};
660 RTNAME(ReduceInteger4DimRef
)(sums
, *intMatrix
, IAdd
, __FILE__
, __LINE__
, 1);
661 EXPECT_EQ(sums
.rank(), 1);
662 EXPECT_EQ(sums
.GetDimension(0).LowerBound(), 1);
663 EXPECT_EQ(sums
.GetDimension(0).Extent(), 2);
664 EXPECT_EQ(*sums
.ZeroBasedIndexedElement
<std::int32_t>(0), 3);
665 EXPECT_EQ(*sums
.ZeroBasedIndexedElement
<std::int32_t>(1), 7);
667 RTNAME(ReduceInteger4DimRef
)(sums
, *intMatrix
, IAdd
, __FILE__
, __LINE__
, 2);
668 EXPECT_EQ(sums
.rank(), 1);
669 EXPECT_EQ(sums
.GetDimension(0).LowerBound(), 1);
670 EXPECT_EQ(sums
.GetDimension(0).Extent(), 2);
671 EXPECT_EQ(*sums
.ZeroBasedIndexedElement
<std::int32_t>(0), 4);
672 EXPECT_EQ(*sums
.ZeroBasedIndexedElement
<std::int32_t>(1), 6);