1//===-- flang/unittests/Runtime/Transformational.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#include "flang/Runtime/transformational.h"
10#include "gtest/gtest.h"
11#include "tools.h"
12#include "flang/Common/float128.h"
13#include "flang/Runtime/type-code.h"
14#include <vector>
15
16using namespace Fortran::runtime;
17using Fortran::common::TypeCategory;
18
19template <int KIND>
20using BesselFuncType = std::function<void(Descriptor &, int32_t, int32_t,
21 CppTypeFor<TypeCategory::Real, KIND>, CppTypeFor<TypeCategory::Real, KIND>,
22 CppTypeFor<TypeCategory::Real, KIND>, const char *, int)>;
23
24template <int KIND>
25using BesselX0FuncType =
26 std::function<void(Descriptor &, int32_t, int32_t, const char *, int)>;
27
28template <int KIND>
29constexpr CppTypeFor<TypeCategory::Real, KIND>
30 besselEpsilon = CppTypeFor<TypeCategory::Real, KIND>(1e-4);
31
32template <int KIND>
33static void testBesselJn(BesselFuncType<KIND> rtFunc, int32_t n1, int32_t n2,
34 CppTypeFor<TypeCategory::Real, KIND> x,
35 const std::vector<CppTypeFor<TypeCategory::Real, KIND>> &expected) {
36 StaticDescriptor<1> desc;
37 Descriptor &result{desc.descriptor()};
38 unsigned len = expected.size();
39
40 CppTypeFor<TypeCategory::Real, KIND> anc0 = len > 0 ? expected[len - 1] : 0.0;
41 CppTypeFor<TypeCategory::Real, KIND> anc1 = len > 1 ? expected[len - 2] : 0.0;
42
43 rtFunc(result, n1, n2, x, anc0, anc1, __FILE__, __LINE__);
44
45 EXPECT_EQ(result.type(), (TypeCode{TypeCategory::Real, KIND}));
46 EXPECT_EQ(result.rank(), 1);
47 EXPECT_EQ(
48 result.ElementBytes(), sizeof(CppTypeFor<TypeCategory::Real, KIND>));
49 EXPECT_EQ(result.GetDimension(0).LowerBound(), 1);
50 EXPECT_EQ(result.GetDimension(0).Extent(), len);
51
52 for (size_t j{0}; j < len; ++j) {
53 EXPECT_NEAR(
54 (*result.ZeroBasedIndexedElement<CppTypeFor<TypeCategory::Real, KIND>>(
55 j)),
56 expected[j], besselEpsilon<KIND>);
57 }
58}
59
60template <int KIND>
61static void testBesselJnX0(
62 BesselX0FuncType<KIND> rtFunc, int32_t n1, int32_t n2) {
63 StaticDescriptor<1> desc;
64 Descriptor &result{desc.descriptor()};
65
66 rtFunc(result, n1, n2, __FILE__, __LINE__);
67
68 EXPECT_EQ(result.type(), (TypeCode{TypeCategory::Real, KIND}));
69 EXPECT_EQ(result.rank(), 1);
70 EXPECT_EQ(result.GetDimension(0).LowerBound(), 1);
71 EXPECT_EQ(result.GetDimension(0).Extent(), n2 >= n1 ? n2 - n1 + 1 : 0);
72
73 if (n2 < n1) {
74 return;
75 }
76
77 EXPECT_NEAR(
78 (*result.ZeroBasedIndexedElement<CppTypeFor<TypeCategory::Real, KIND>>(
79 0)),
80 (n1 == 0) ? 1.0 : 0.0, 1e-5);
81
82 for (int j{1}; j < (n2 - n1 + 1); ++j) {
83 EXPECT_NEAR(
84 (*result.ZeroBasedIndexedElement<CppTypeFor<TypeCategory::Real, KIND>>(
85 j)),
86 0.0, besselEpsilon<KIND>);
87 }
88}
89
90template <int KIND> static void testBesselJn(BesselFuncType<KIND> rtFunc) {
91 testBesselJn<KIND>(rtFunc, 1, 0, 1.0, {});
92 testBesselJn<KIND>(rtFunc, 0, 0, 1.0, {0.765197694});
93 testBesselJn<KIND>(rtFunc, 0, 1, 1.0, {0.765197694, 0.440050572});
94 testBesselJn<KIND>(
95 rtFunc, 0, 2, 1.0, {0.765197694, 0.440050572, 0.114903487});
96 testBesselJn<KIND>(rtFunc, 1, 5, 5.0,
97 {-0.327579111, 0.046565145, 0.364831239, 0.391232371, 0.261140555});
98}
99
100template <int KIND> static void testBesselJnX0(BesselX0FuncType<KIND> rtFunc) {
101 testBesselJnX0<KIND>(rtFunc, 1, 0);
102 testBesselJnX0<KIND>(rtFunc, 0, 0);
103 testBesselJnX0<KIND>(rtFunc, 1, 1);
104 testBesselJnX0<KIND>(rtFunc, 0, 3);
105 testBesselJnX0<KIND>(rtFunc, 1, 4);
106}
107
108static void testBesselJn() {
109 testBesselJn<4>(RTNAME(BesselJn_4));
110 testBesselJn<8>(RTNAME(BesselJn_8));
111#if LDBL_MANT_DIG == 64
112 testBesselJn<10>(RTNAME(BesselJn_10));
113#endif
114#if LDBL_MANT_DIG == 113 || HAS_FLOAT128
115 testBesselJn<16>(RTNAME(BesselJn_16));
116#endif
117
118 testBesselJnX0<4>(RTNAME(BesselJnX0_4));
119 testBesselJnX0<8>(RTNAME(BesselJnX0_8));
120#if LDBL_MANT_DIG == 64
121 testBesselJnX0<10>(RTNAME(BesselJnX0_10));
122#endif
123#if LDBL_MANT_DIG == 113 || HAS_FLOAT128
124 testBesselJnX0<16>(RTNAME(BesselJnX0_16));
125#endif
126}
127
128TEST(Transformational, BesselJn) { testBesselJn(); }
129
130template <int KIND>
131static void testBesselYn(BesselFuncType<KIND> rtFunc, int32_t n1, int32_t n2,
132 CppTypeFor<TypeCategory::Real, KIND> x,
133 const std::vector<CppTypeFor<TypeCategory::Real, KIND>> &expected) {
134 StaticDescriptor<1> desc;
135 Descriptor &result{desc.descriptor()};
136 unsigned len = expected.size();
137
138 CppTypeFor<TypeCategory::Real, KIND> anc0 = len > 0 ? expected[0] : 0.0;
139 CppTypeFor<TypeCategory::Real, KIND> anc1 = len > 1 ? expected[1] : 0.0;
140
141 rtFunc(result, n1, n2, x, anc0, anc1, __FILE__, __LINE__);
142
143 EXPECT_EQ(result.type(), (TypeCode{TypeCategory::Real, KIND}));
144 EXPECT_EQ(result.rank(), 1);
145 EXPECT_EQ(
146 result.ElementBytes(), sizeof(CppTypeFor<TypeCategory::Real, KIND>));
147 EXPECT_EQ(result.GetDimension(0).LowerBound(), 1);
148 EXPECT_EQ(result.GetDimension(0).Extent(), len);
149
150 for (size_t j{0}; j < len; ++j) {
151 EXPECT_NEAR(
152 (*result.ZeroBasedIndexedElement<CppTypeFor<TypeCategory::Real, KIND>>(
153 j)),
154 expected[j], besselEpsilon<KIND>);
155 }
156}
157
158template <int KIND>
159static void testBesselYnX0(
160 BesselX0FuncType<KIND> rtFunc, int32_t n1, int32_t n2) {
161 StaticDescriptor<1> desc;
162 Descriptor &result{desc.descriptor()};
163
164 rtFunc(result, n1, n2, __FILE__, __LINE__);
165
166 EXPECT_EQ(result.type(), (TypeCode{TypeCategory::Real, KIND}));
167 EXPECT_EQ(result.rank(), 1);
168 EXPECT_EQ(result.GetDimension(0).LowerBound(), 1);
169 EXPECT_EQ(result.GetDimension(0).Extent(), n2 >= n1 ? n2 - n1 + 1 : 0);
170
171 if (n2 < n1) {
172 return;
173 }
174
175 for (int j{0}; j < (n2 - n1 + 1); ++j) {
176 EXPECT_EQ(
177 (*result.ZeroBasedIndexedElement<CppTypeFor<TypeCategory::Real, KIND>>(
178 j)),
179 (-std::numeric_limits<
180 CppTypeFor<TypeCategory::Real, KIND>>::infinity()));
181 }
182}
183
184template <int KIND> static void testBesselYn(BesselFuncType<KIND> rtFunc) {
185 testBesselYn<KIND>(rtFunc, 1, 0, 1.0, {});
186 testBesselYn<KIND>(rtFunc, 0, 0, 1.0, {0.08825695});
187 testBesselYn<KIND>(rtFunc, 0, 1, 1.0, {0.08825695, -0.7812128});
188 testBesselYn<KIND>(rtFunc, 0, 2, 1.0, {0.0882569555, -0.7812128, -1.6506826});
189 testBesselYn<KIND>(rtFunc, 1, 5, 1.0,
190 {-0.7812128, -1.6506826, -5.8215175, -33.278423, -260.40588});
191}
192
193template <int KIND> static void testBesselYnX0(BesselX0FuncType<KIND> rtFunc) {
194 testBesselYnX0<KIND>(rtFunc, 1, 0);
195 testBesselYnX0<KIND>(rtFunc, 0, 0);
196 testBesselYnX0<KIND>(rtFunc, 1, 1);
197 testBesselYnX0<KIND>(rtFunc, 0, 3);
198 testBesselYnX0<KIND>(rtFunc, 1, 4);
199}
200
201static void testBesselYn() {
202 testBesselYn<4>(RTNAME(BesselYn_4));
203 testBesselYn<8>(RTNAME(BesselYn_8));
204#if LDBL_MANT_DIG == 64
205 testBesselYn<10>(RTNAME(BesselYn_10));
206#endif
207#if LDBL_MANT_DIG == 113 || HAS_FLOAT128
208 testBesselYn<16>(RTNAME(BesselYn_16));
209#endif
210
211 testBesselYnX0<4>(RTNAME(BesselYnX0_4));
212 testBesselYnX0<8>(RTNAME(BesselYnX0_8));
213#if LDBL_MANT_DIG == 64
214 testBesselYnX0<10>(RTNAME(BesselYnX0_10));
215#endif
216#if LDBL_MANT_DIG == 113 || HAS_FLOAT128
217 testBesselYnX0<16>(RTNAME(BesselYnX0_16));
218#endif
219}
220
221TEST(Transformational, BesselYn) { testBesselYn(); }
222
223TEST(Transformational, Shifts) {
224 // ARRAY 1 3 5
225 // 2 4 6
226 auto array{MakeArray<TypeCategory::Integer, 4>(
227 std::vector<int>{2, 3}, std::vector<std::int32_t>{1, 2, 3, 4, 5, 6})};
228 array->GetDimension(0).SetLowerBound(0); // shouldn't matter
229 array->GetDimension(1).SetLowerBound(-1);
230 StaticDescriptor<2, true> statDesc;
231 Descriptor &result{statDesc.descriptor()};
232
233 auto shift3{MakeArray<TypeCategory::Integer, 8>(
234 std::vector<int>{3}, std::vector<std::int64_t>{1, -1, 2})};
235 RTNAME(Cshift)(result, *array, *shift3, 1, __FILE__, __LINE__);
236 EXPECT_EQ(result.type(), array->type());
237 EXPECT_EQ(result.rank(), 2);
238 EXPECT_EQ(result.GetDimension(0).LowerBound(), 1);
239 EXPECT_EQ(result.GetDimension(0).Extent(), 2);
240 EXPECT_EQ(result.GetDimension(1).LowerBound(), 1);
241 EXPECT_EQ(result.GetDimension(1).Extent(), 3);
242 EXPECT_EQ(result.type(), (TypeCode{TypeCategory::Integer, 4}));
243 static std::int32_t cshiftExpect1[6]{2, 1, 4, 3, 5, 6};
244 for (int j{0}; j < 6; ++j) {
245 EXPECT_EQ(
246 *result.ZeroBasedIndexedElement<std::int32_t>(j), cshiftExpect1[j]);
247 }
248 result.Destroy();
249
250 auto shift2{MakeArray<TypeCategory::Integer, 1>(
251 std::vector<int>{2}, std::vector<std::int8_t>{1, -1})};
252 shift2->GetDimension(0).SetLowerBound(-1); // shouldn't matter
253 RTNAME(Cshift)(result, *array, *shift2, 2, __FILE__, __LINE__);
254 EXPECT_EQ(result.type(), array->type());
255 EXPECT_EQ(result.rank(), 2);
256 EXPECT_EQ(result.GetDimension(0).LowerBound(), 1);
257 EXPECT_EQ(result.GetDimension(0).Extent(), 2);
258 EXPECT_EQ(result.GetDimension(1).LowerBound(), 1);
259 EXPECT_EQ(result.GetDimension(1).Extent(), 3);
260 EXPECT_EQ(result.type(), (TypeCode{TypeCategory::Integer, 4}));
261 static std::int32_t cshiftExpect2[6]{3, 6, 5, 2, 1, 4};
262 for (int j{0}; j < 6; ++j) {
263 EXPECT_EQ(
264 *result.ZeroBasedIndexedElement<std::int32_t>(j), cshiftExpect2[j]);
265 }
266 result.Destroy();
267
268 // VECTOR 1 3 5 2 4 6
269 auto vector{MakeArray<TypeCategory::Integer, 4>(
270 std::vector<int>{6}, std::vector<std::int32_t>{1, 2, 3, 4, 5, 6})};
271 vector->GetDimension(0).SetLowerBound(0);
272 StaticDescriptor<1, true> vectorDesc;
273 Descriptor &vectorResult{vectorDesc.descriptor()};
274
275 RTNAME(CshiftVector)(vectorResult, *vector, 2, __FILE__, __LINE__);
276 EXPECT_EQ(vectorResult.type(), array->type());
277 EXPECT_EQ(vectorResult.rank(), 1);
278 EXPECT_EQ(vectorResult.GetDimension(0).LowerBound(), 1);
279 EXPECT_EQ(vectorResult.GetDimension(0).Extent(), 6);
280 EXPECT_EQ(vectorResult.type(), (TypeCode{TypeCategory::Integer, 4}));
281 static std::int32_t cshiftExpect3[6]{3, 4, 5, 6, 1, 2};
282 for (int j{0}; j < 6; ++j) {
283 EXPECT_EQ(*vectorResult.ZeroBasedIndexedElement<std::int32_t>(j),
284 cshiftExpect3[j]);
285 }
286 vectorResult.Destroy();
287
288 RTNAME(CshiftVector)(vectorResult, *vector, -2, __FILE__, __LINE__);
289 EXPECT_EQ(vectorResult.type(), array->type());
290 EXPECT_EQ(vectorResult.rank(), 1);
291 EXPECT_EQ(vectorResult.GetDimension(0).LowerBound(), 1);
292 EXPECT_EQ(vectorResult.GetDimension(0).Extent(), 6);
293 EXPECT_EQ(vectorResult.type(), (TypeCode{TypeCategory::Integer, 4}));
294 static std::int32_t cshiftExpect4[6]{5, 6, 1, 2, 3, 4};
295 for (int j{0}; j < 6; ++j) {
296 EXPECT_EQ(*vectorResult.ZeroBasedIndexedElement<std::int32_t>(j),
297 cshiftExpect4[j]);
298 }
299 vectorResult.Destroy();
300
301 // VECTOR 1 3 5 2 4 6 WITH non zero lower bound in a negative cshift.
302 auto vectorWithLowerBounds{MakeArray<TypeCategory::Integer, 4>(
303 std::vector<int>{6}, std::vector<std::int32_t>{1, 2, 3, 4, 5, 6})};
304 vectorWithLowerBounds->GetDimension(0).SetLowerBound(2);
305
306 RTNAME(CshiftVector)
307 (vectorResult, *vectorWithLowerBounds, -2, __FILE__, __LINE__);
308 EXPECT_EQ(vectorResult.type(), array->type());
309 EXPECT_EQ(vectorResult.rank(), 1);
310 EXPECT_EQ(vectorResult.GetDimension(0).LowerBound(), 1);
311 EXPECT_EQ(vectorResult.GetDimension(0).Extent(), 6);
312 EXPECT_EQ(vectorResult.type(), (TypeCode{TypeCategory::Integer, 4}));
313 static std::int32_t cshiftExpect5[6]{5, 6, 1, 2, 3, 4};
314 for (int j{0}; j < 6; ++j) {
315 EXPECT_EQ(*vectorResult.ZeroBasedIndexedElement<std::int32_t>(j),
316 cshiftExpect5[j]);
317 }
318 vectorResult.Destroy();
319
320 auto boundary{MakeArray<TypeCategory::Integer, 4>(
321 std::vector<int>{3}, std::vector<std::int32_t>{-1, -2, -3})};
322 boundary->GetDimension(0).SetLowerBound(9); // shouldn't matter
323 RTNAME(Eoshift)(result, *array, *shift3, &*boundary, 1, __FILE__, __LINE__);
324 EXPECT_EQ(result.type(), array->type());
325 EXPECT_EQ(result.rank(), 2);
326 EXPECT_EQ(result.GetDimension(0).LowerBound(), 1);
327 EXPECT_EQ(result.GetDimension(0).Extent(), 2);
328 EXPECT_EQ(result.GetDimension(1).LowerBound(), 1);
329 EXPECT_EQ(result.GetDimension(1).Extent(), 3);
330 EXPECT_EQ(result.type(), (TypeCode{TypeCategory::Integer, 4}));
331 static std::int32_t eoshiftExpect1[6]{2, -1, -2, 3, -3, -3};
332 for (int j{0}; j < 6; ++j) {
333 EXPECT_EQ(
334 *result.ZeroBasedIndexedElement<std::int32_t>(j), eoshiftExpect1[j]);
335 }
336 result.Destroy();
337
338 // VECTOR EOSHIFT
339 StaticDescriptor<0> boundaryDescriptor;
340 Descriptor vectorBoundary{boundaryDescriptor.descriptor()};
341 std::int32_t boundaryValue{343};
342 vectorBoundary.Establish(TypeCategory::Integer, 4,
343 const_cast<void *>(reinterpret_cast<const void *>(&boundaryValue)), 0);
344 RTNAME(EoshiftVector)
345 (vectorResult, *vector, 2, &vectorBoundary, __FILE__, __LINE__);
346 EXPECT_EQ(vectorResult.type(), array->type());
347 EXPECT_EQ(vectorResult.rank(), 1);
348 EXPECT_EQ(vectorResult.GetDimension(0).LowerBound(), 1);
349 EXPECT_EQ(vectorResult.GetDimension(0).Extent(), 6);
350 EXPECT_EQ(vectorResult.type(), (TypeCode{TypeCategory::Integer, 4}));
351 static std::int32_t eoshiftVectorExpect[6]{3, 4, 5, 6, 343, 343};
352 for (int j{0}; j < 6; ++j) {
353 EXPECT_EQ(*vectorResult.ZeroBasedIndexedElement<std::int32_t>(j),
354 eoshiftVectorExpect[j]);
355 }
356 vectorResult.Destroy();
357
358 // VECTOR EOSHIFT on input with non zero lower bounds
359 RTNAME(EoshiftVector)
360 (vectorResult, *vectorWithLowerBounds, -2, &vectorBoundary, __FILE__,
361 __LINE__);
362 EXPECT_EQ(vectorResult.type(), array->type());
363 EXPECT_EQ(vectorResult.rank(), 1);
364 EXPECT_EQ(vectorResult.GetDimension(0).LowerBound(), 1);
365 EXPECT_EQ(vectorResult.GetDimension(0).Extent(), 6);
366 EXPECT_EQ(vectorResult.type(), (TypeCode{TypeCategory::Integer, 4}));
367 static std::int32_t eoshiftVectorExpect2[6]{343, 343, 1, 2, 3, 4};
368 for (int j{0}; j < 6; ++j) {
369 EXPECT_EQ(*vectorResult.ZeroBasedIndexedElement<std::int32_t>(j),
370 eoshiftVectorExpect2[j]);
371 }
372 vectorResult.Destroy();
373}
374
375TEST(Transformational, Pack) {
376 // ARRAY 1 3 5
377 // 2 4 6
378 auto array{MakeArray<TypeCategory::Integer, 4>(
379 std::vector<int>{2, 3}, std::vector<std::int32_t>{1, 2, 3, 4, 5, 6})};
380 array->GetDimension(0).SetLowerBound(2); // shouldn't matter
381 array->GetDimension(1).SetLowerBound(-1);
382 auto mask{MakeArray<TypeCategory::Logical, 1>(std::vector<int>{2, 3},
383 std::vector<std::uint8_t>{false, true, true, false, false, true})};
384 mask->GetDimension(0).SetLowerBound(0); // shouldn't matter
385 mask->GetDimension(1).SetLowerBound(2);
386 StaticDescriptor<1, true> statDesc;
387 Descriptor &result{statDesc.descriptor()};
388
389 RTNAME(Pack)(result, *array, *mask, nullptr, __FILE__, __LINE__);
390 EXPECT_EQ(result.type(), array->type());
391 EXPECT_EQ(result.rank(), 1);
392 EXPECT_EQ(result.GetDimension(0).LowerBound(), 1);
393 EXPECT_EQ(result.GetDimension(0).Extent(), 3);
394 static std::int32_t packExpect1[3]{2, 3, 6};
395 for (int j{0}; j < 3; ++j) {
396 EXPECT_EQ(*result.ZeroBasedIndexedElement<std::int32_t>(j), packExpect1[j])
397 << " at " << j;
398 }
399 result.Destroy();
400
401 auto vector{MakeArray<TypeCategory::Integer, 4>(
402 std::vector<int>{5}, std::vector<std::int32_t>{-1, -2, -3, -4, -5})};
403 RTNAME(Pack)(result, *array, *mask, &*vector, __FILE__, __LINE__);
404 EXPECT_EQ(result.type(), array->type());
405 EXPECT_EQ(result.rank(), 1);
406 EXPECT_EQ(result.GetDimension(0).LowerBound(), 1);
407 EXPECT_EQ(result.GetDimension(0).Extent(), 5);
408 static std::int32_t packExpect2[5]{2, 3, 6, -4, -5};
409 for (int j{0}; j < 5; ++j) {
410 EXPECT_EQ(*result.ZeroBasedIndexedElement<std::int32_t>(j), packExpect2[j])
411 << " at " << j;
412 }
413 result.Destroy();
414}
415
416TEST(Transformational, Spread) {
417 auto array{MakeArray<TypeCategory::Integer, 4>(
418 std::vector<int>{3}, std::vector<std::int32_t>{1, 2, 3})};
419 array->GetDimension(0).SetLowerBound(2); // shouldn't matter
420 StaticDescriptor<2, true> statDesc;
421 Descriptor &result{statDesc.descriptor()};
422
423 RTNAME(Spread)(result, *array, 1, 2, __FILE__, __LINE__);
424 EXPECT_EQ(result.type(), array->type());
425 EXPECT_EQ(result.rank(), 2);
426 EXPECT_EQ(result.GetDimension(0).LowerBound(), 1);
427 EXPECT_EQ(result.GetDimension(0).Extent(), 2);
428 EXPECT_EQ(result.GetDimension(1).LowerBound(), 1);
429 EXPECT_EQ(result.GetDimension(1).Extent(), 3);
430 for (int j{0}; j < 6; ++j) {
431 EXPECT_EQ(*result.ZeroBasedIndexedElement<std::int32_t>(j), 1 + j / 2);
432 }
433 result.Destroy();
434
435 RTNAME(Spread)(result, *array, 2, 2, __FILE__, __LINE__);
436 EXPECT_EQ(result.type(), array->type());
437 EXPECT_EQ(result.rank(), 2);
438 EXPECT_EQ(result.GetDimension(0).LowerBound(), 1);
439 EXPECT_EQ(result.GetDimension(0).Extent(), 3);
440 EXPECT_EQ(result.GetDimension(1).LowerBound(), 1);
441 EXPECT_EQ(result.GetDimension(1).Extent(), 2);
442 for (int j{0}; j < 6; ++j) {
443 EXPECT_EQ(*result.ZeroBasedIndexedElement<std::int32_t>(j), 1 + j % 3);
444 }
445 result.Destroy();
446
447 auto scalar{MakeArray<TypeCategory::Integer, 4>(
448 std::vector<int>{}, std::vector<std::int32_t>{1})};
449 RTNAME(Spread)(result, *scalar, 1, 2, __FILE__, __LINE__);
450 EXPECT_EQ(result.type(), array->type());
451 EXPECT_EQ(result.rank(), 1);
452 EXPECT_EQ(result.GetDimension(0).LowerBound(), 1);
453 EXPECT_EQ(result.GetDimension(0).Extent(), 2);
454 for (int j{0}; j < 2; ++j) {
455 EXPECT_EQ(*result.ZeroBasedIndexedElement<std::int32_t>(j), 1);
456 }
457 result.Destroy();
458}
459
460TEST(Transformational, Transpose) {
461 // ARRAY 1 3 5
462 // 2 4 6
463 auto array{MakeArray<TypeCategory::Integer, 4>(
464 std::vector<int>{2, 3}, std::vector<std::int32_t>{1, 2, 3, 4, 5, 6})};
465 array->GetDimension(0).SetLowerBound(2); // shouldn't matter
466 array->GetDimension(1).SetLowerBound(-6);
467 StaticDescriptor<2, true> statDesc;
468 Descriptor &result{statDesc.descriptor()};
469 RTNAME(Transpose)(result, *array, __FILE__, __LINE__);
470 EXPECT_EQ(result.type(), array->type());
471 EXPECT_EQ(result.rank(), 2);
472 EXPECT_EQ(result.GetDimension(0).LowerBound(), 1);
473 EXPECT_EQ(result.GetDimension(0).Extent(), 3);
474 EXPECT_EQ(result.GetDimension(1).LowerBound(), 1);
475 EXPECT_EQ(result.GetDimension(1).Extent(), 2);
476 static std::int32_t expect[6]{1, 3, 5, 2, 4, 6};
477 for (int j{0}; j < 6; ++j) {
478 EXPECT_EQ(*result.ZeroBasedIndexedElement<std::int32_t>(j), expect[j]);
479 }
480 result.Destroy();
481}
482
483TEST(Transformational, Unpack) {
484 auto vector{MakeArray<TypeCategory::Integer, 4>(
485 std::vector<int>{4}, std::vector<std::int32_t>{1, 2, 3, 4})};
486 vector->GetDimension(0).SetLowerBound(2); // shouldn't matter
487 auto mask{MakeArray<TypeCategory::Logical, 1>(std::vector<int>{2, 3},
488 std::vector<std::uint8_t>{false, true, true, false, false, true})};
489 mask->GetDimension(0).SetLowerBound(0); // shouldn't matter
490 mask->GetDimension(1).SetLowerBound(2);
491 auto field{MakeArray<TypeCategory::Integer, 4>(std::vector<int>{2, 3},
492 std::vector<std::int32_t>{-1, -2, -3, -4, -5, -6})};
493 field->GetDimension(0).SetLowerBound(-1); // shouldn't matter
494 StaticDescriptor<2, true> statDesc;
495 Descriptor &result{statDesc.descriptor()};
496 RTNAME(Unpack)(result, *vector, *mask, *field, __FILE__, __LINE__);
497 EXPECT_EQ(result.type(), vector->type());
498 EXPECT_EQ(result.rank(), 2);
499 EXPECT_EQ(result.GetDimension(0).LowerBound(), 1);
500 EXPECT_EQ(result.GetDimension(0).Extent(), 2);
501 EXPECT_EQ(result.GetDimension(1).LowerBound(), 1);
502 EXPECT_EQ(result.GetDimension(1).Extent(), 3);
503 static std::int32_t expect[6]{-1, 1, 2, -4, -5, 3};
504 for (int j{0}; j < 6; ++j) {
505 EXPECT_EQ(*result.ZeroBasedIndexedElement<std::int32_t>(j), expect[j]);
506 }
507 result.Destroy();
508
509 // Test for scalar value of the "field" argument
510 auto scalarField{MakeArray<TypeCategory::Integer, 4>(
511 std::vector<int>{}, std::vector<std::int32_t>{343})};
512 RTNAME(Unpack)(result, *vector, *mask, *scalarField, __FILE__, __LINE__);
513 EXPECT_EQ(result.rank(), 2);
514 EXPECT_EQ(result.GetDimension(0).LowerBound(), 1);
515 EXPECT_EQ(result.GetDimension(0).Extent(), 2);
516 EXPECT_EQ(result.GetDimension(1).LowerBound(), 1);
517 EXPECT_EQ(result.GetDimension(1).Extent(), 3);
518 static std::int32_t scalarExpect[6]{343, 1, 2, 343, 343, 3};
519 for (int j{0}; j < 6; ++j) {
520 EXPECT_EQ(
521 *result.ZeroBasedIndexedElement<std::int32_t>(j), scalarExpect[j]);
522 }
523 result.Destroy();
524}
525
526#if LDBL_MANT_DIG == 64
527// Make sure the destination descriptor is created by the runtime
528// with proper element size, when REAL*10 maps to 'long double'.
529#define Real10CppType long double
530TEST(Transformational, TransposeReal10) {
531 // ARRAY 1 3 5
532 // 2 4 6
533 auto array{MakeArray<TypeCategory::Real, 10>(std::vector<int>{2, 3},
534 std::vector<Real10CppType>{1.0, 2.0, 3.0, 4.0, 5.0, 6.0},
535 sizeof(Real10CppType))};
536 StaticDescriptor<2, true> statDesc;
537 Descriptor &result{statDesc.descriptor()};
538 RTNAME(Transpose)(result, *array, __FILE__, __LINE__);
539 EXPECT_EQ(result.ElementBytes(), sizeof(Real10CppType));
540 EXPECT_EQ(result.type(), array->type());
541 EXPECT_EQ(result.rank(), 2);
542 EXPECT_EQ(result.GetDimension(0).LowerBound(), 1);
543 EXPECT_EQ(result.GetDimension(0).Extent(), 3);
544 EXPECT_EQ(result.GetDimension(1).LowerBound(), 1);
545 EXPECT_EQ(result.GetDimension(1).Extent(), 2);
546 static Real10CppType expect[6]{1.0, 3.0, 5.0, 2.0, 4.0, 6.0};
547 for (int j{0}; j < 6; ++j) {
548 EXPECT_EQ(*result.ZeroBasedIndexedElement<Real10CppType>(j), expect[j]);
549 }
550 result.Destroy();
551}
552#endif
553

source code of flang/unittests/Runtime/Transformational.cpp