1 //===-- flang/unittests/RuntimeGTest/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/Runtime/type-code.h" 13 14 using namespace Fortran::runtime; 15 using Fortran::common::TypeCategory; 16 17 TEST(Transformational, Shifts) { 18 // ARRAY 1 3 5 19 // 2 4 6 20 auto array{MakeArray<TypeCategory::Integer, 4>( 21 std::vector<int>{2, 3}, std::vector<std::int32_t>{1, 2, 3, 4, 5, 6})}; 22 array->GetDimension(0).SetLowerBound(0); // shouldn't matter 23 array->GetDimension(1).SetLowerBound(-1); 24 StaticDescriptor<2, true> statDesc; 25 Descriptor &result{statDesc.descriptor()}; 26 27 auto shift3{MakeArray<TypeCategory::Integer, 8>( 28 std::vector<int>{3}, std::vector<std::int64_t>{1, -1, 2})}; 29 RTNAME(Cshift)(result, *array, *shift3, 1, __FILE__, __LINE__); 30 EXPECT_EQ(result.type(), array->type()); 31 EXPECT_EQ(result.rank(), 2); 32 EXPECT_EQ(result.GetDimension(0).LowerBound(), 1); 33 EXPECT_EQ(result.GetDimension(0).Extent(), 2); 34 EXPECT_EQ(result.GetDimension(1).LowerBound(), 1); 35 EXPECT_EQ(result.GetDimension(1).Extent(), 3); 36 EXPECT_EQ(result.type(), (TypeCode{TypeCategory::Integer, 4})); 37 static std::int32_t cshiftExpect1[6]{2, 1, 4, 3, 5, 6}; 38 for (int j{0}; j < 6; ++j) { 39 EXPECT_EQ( 40 *result.ZeroBasedIndexedElement<std::int32_t>(j), cshiftExpect1[j]); 41 } 42 result.Destroy(); 43 44 auto shift2{MakeArray<TypeCategory::Integer, 1>( 45 std::vector<int>{2}, std::vector<std::int8_t>{1, -1})}; 46 shift2->GetDimension(0).SetLowerBound(-1); // shouldn't matter 47 shift2->GetDimension(1).SetLowerBound(2); 48 RTNAME(Cshift)(result, *array, *shift2, 2, __FILE__, __LINE__); 49 EXPECT_EQ(result.type(), array->type()); 50 EXPECT_EQ(result.rank(), 2); 51 EXPECT_EQ(result.GetDimension(0).LowerBound(), 1); 52 EXPECT_EQ(result.GetDimension(0).Extent(), 2); 53 EXPECT_EQ(result.GetDimension(1).LowerBound(), 1); 54 EXPECT_EQ(result.GetDimension(1).Extent(), 3); 55 EXPECT_EQ(result.type(), (TypeCode{TypeCategory::Integer, 4})); 56 static std::int32_t cshiftExpect2[6]{3, 6, 5, 2, 1, 4}; 57 for (int j{0}; j < 6; ++j) { 58 EXPECT_EQ( 59 *result.ZeroBasedIndexedElement<std::int32_t>(j), cshiftExpect2[j]); 60 } 61 result.Destroy(); 62 63 // VECTOR 1 3 5 2 4 6 64 auto vector{MakeArray<TypeCategory::Integer, 4>( 65 std::vector<int>{6}, std::vector<std::int32_t>{1, 2, 3, 4, 5, 6})}; 66 vector->GetDimension(0).SetLowerBound(0); 67 StaticDescriptor<1, true> vectorDesc; 68 Descriptor &vectorResult{vectorDesc.descriptor()}; 69 70 RTNAME(CshiftVector)(vectorResult, *vector, 2, __FILE__, __LINE__); 71 EXPECT_EQ(vectorResult.type(), array->type()); 72 EXPECT_EQ(vectorResult.rank(), 1); 73 EXPECT_EQ(vectorResult.GetDimension(0).LowerBound(), 1); 74 EXPECT_EQ(vectorResult.GetDimension(0).Extent(), 6); 75 EXPECT_EQ(vectorResult.type(), (TypeCode{TypeCategory::Integer, 4})); 76 static std::int32_t cshiftExpect3[6]{3, 4, 5, 6, 1, 2}; 77 for (int j{0}; j < 6; ++j) { 78 EXPECT_EQ(*vectorResult.ZeroBasedIndexedElement<std::int32_t>(j), 79 cshiftExpect3[j]); 80 } 81 vectorResult.Destroy(); 82 83 RTNAME(CshiftVector)(vectorResult, *vector, -2, __FILE__, __LINE__); 84 EXPECT_EQ(vectorResult.type(), array->type()); 85 EXPECT_EQ(vectorResult.rank(), 1); 86 EXPECT_EQ(vectorResult.GetDimension(0).LowerBound(), 1); 87 EXPECT_EQ(vectorResult.GetDimension(0).Extent(), 6); 88 EXPECT_EQ(vectorResult.type(), (TypeCode{TypeCategory::Integer, 4})); 89 static std::int32_t cshiftExpect4[6]{5, 6, 1, 2, 3, 4}; 90 for (int j{0}; j < 6; ++j) { 91 EXPECT_EQ(*vectorResult.ZeroBasedIndexedElement<std::int32_t>(j), 92 cshiftExpect4[j]); 93 } 94 vectorResult.Destroy(); 95 96 // VECTOR 1 3 5 2 4 6 WITH non zero lower bound in a negative cshift. 97 auto vectorWithLowerBounds{MakeArray<TypeCategory::Integer, 4>( 98 std::vector<int>{6}, std::vector<std::int32_t>{1, 2, 3, 4, 5, 6})}; 99 vectorWithLowerBounds->GetDimension(0).SetLowerBound(2); 100 101 RTNAME(CshiftVector) 102 (vectorResult, *vectorWithLowerBounds, -2, __FILE__, __LINE__); 103 EXPECT_EQ(vectorResult.type(), array->type()); 104 EXPECT_EQ(vectorResult.rank(), 1); 105 EXPECT_EQ(vectorResult.GetDimension(0).LowerBound(), 1); 106 EXPECT_EQ(vectorResult.GetDimension(0).Extent(), 6); 107 EXPECT_EQ(vectorResult.type(), (TypeCode{TypeCategory::Integer, 4})); 108 static std::int32_t cshiftExpect5[6]{5, 6, 1, 2, 3, 4}; 109 for (int j{0}; j < 6; ++j) { 110 EXPECT_EQ(*vectorResult.ZeroBasedIndexedElement<std::int32_t>(j), 111 cshiftExpect5[j]); 112 } 113 vectorResult.Destroy(); 114 115 auto boundary{MakeArray<TypeCategory::Integer, 4>( 116 std::vector<int>{3}, std::vector<std::int32_t>{-1, -2, -3})}; 117 boundary->GetDimension(0).SetLowerBound(9); // shouldn't matter 118 RTNAME(Eoshift)(result, *array, *shift3, &*boundary, 1, __FILE__, __LINE__); 119 EXPECT_EQ(result.type(), array->type()); 120 EXPECT_EQ(result.rank(), 2); 121 EXPECT_EQ(result.GetDimension(0).LowerBound(), 1); 122 EXPECT_EQ(result.GetDimension(0).Extent(), 2); 123 EXPECT_EQ(result.GetDimension(1).LowerBound(), 1); 124 EXPECT_EQ(result.GetDimension(1).Extent(), 3); 125 EXPECT_EQ(result.type(), (TypeCode{TypeCategory::Integer, 4})); 126 static std::int32_t eoshiftExpect1[6]{2, -1, -2, 3, -3, -3}; 127 for (int j{0}; j < 6; ++j) { 128 EXPECT_EQ( 129 *result.ZeroBasedIndexedElement<std::int32_t>(j), eoshiftExpect1[j]); 130 } 131 result.Destroy(); 132 133 // VECTOR EOSHIFT 134 StaticDescriptor<0> boundaryDescriptor; 135 Descriptor vectorBoundary{boundaryDescriptor.descriptor()}; 136 std::int32_t boundaryValue{343}; 137 vectorBoundary.Establish(TypeCategory::Integer, 4, 138 const_cast<void *>(reinterpret_cast<const void *>(&boundaryValue)), 0); 139 RTNAME(EoshiftVector) 140 (vectorResult, *vector, 2, &vectorBoundary, __FILE__, __LINE__); 141 EXPECT_EQ(vectorResult.type(), array->type()); 142 EXPECT_EQ(vectorResult.rank(), 1); 143 EXPECT_EQ(vectorResult.GetDimension(0).LowerBound(), 1); 144 EXPECT_EQ(vectorResult.GetDimension(0).Extent(), 6); 145 EXPECT_EQ(vectorResult.type(), (TypeCode{TypeCategory::Integer, 4})); 146 static std::int32_t eoshiftVectorExpect[6]{3, 4, 5, 6, 343, 343}; 147 for (int j{0}; j < 6; ++j) { 148 EXPECT_EQ(*vectorResult.ZeroBasedIndexedElement<std::int32_t>(j), 149 eoshiftVectorExpect[j]); 150 } 151 vectorResult.Destroy(); 152 153 // VECTOR EOSHIFT on input with non zero lower bounds 154 RTNAME(EoshiftVector) 155 (vectorResult, *vectorWithLowerBounds, -2, &vectorBoundary, __FILE__, 156 __LINE__); 157 EXPECT_EQ(vectorResult.type(), array->type()); 158 EXPECT_EQ(vectorResult.rank(), 1); 159 EXPECT_EQ(vectorResult.GetDimension(0).LowerBound(), 1); 160 EXPECT_EQ(vectorResult.GetDimension(0).Extent(), 6); 161 EXPECT_EQ(vectorResult.type(), (TypeCode{TypeCategory::Integer, 4})); 162 static std::int32_t eoshiftVectorExpect2[6]{343, 343, 1, 2, 3, 4}; 163 for (int j{0}; j < 6; ++j) { 164 EXPECT_EQ(*vectorResult.ZeroBasedIndexedElement<std::int32_t>(j), 165 eoshiftVectorExpect2[j]); 166 } 167 vectorResult.Destroy(); 168 } 169 170 TEST(Transformational, Pack) { 171 // ARRAY 1 3 5 172 // 2 4 6 173 auto array{MakeArray<TypeCategory::Integer, 4>( 174 std::vector<int>{2, 3}, std::vector<std::int32_t>{1, 2, 3, 4, 5, 6})}; 175 array->GetDimension(0).SetLowerBound(2); // shouldn't matter 176 array->GetDimension(1).SetLowerBound(-1); 177 auto mask{MakeArray<TypeCategory::Logical, 1>(std::vector<int>{2, 3}, 178 std::vector<std::uint8_t>{false, true, true, false, false, true})}; 179 mask->GetDimension(0).SetLowerBound(0); // shouldn't matter 180 mask->GetDimension(1).SetLowerBound(2); 181 StaticDescriptor<1, true> statDesc; 182 Descriptor &result{statDesc.descriptor()}; 183 184 RTNAME(Pack)(result, *array, *mask, nullptr, __FILE__, __LINE__); 185 EXPECT_EQ(result.type(), array->type()); 186 EXPECT_EQ(result.rank(), 1); 187 EXPECT_EQ(result.GetDimension(0).LowerBound(), 1); 188 EXPECT_EQ(result.GetDimension(0).Extent(), 3); 189 static std::int32_t packExpect1[3]{2, 3, 6}; 190 for (int j{0}; j < 3; ++j) { 191 EXPECT_EQ(*result.ZeroBasedIndexedElement<std::int32_t>(j), packExpect1[j]) 192 << " at " << j; 193 } 194 result.Destroy(); 195 196 auto vector{MakeArray<TypeCategory::Integer, 4>( 197 std::vector<int>{5}, std::vector<std::int32_t>{-1, -2, -3, -4, -5})}; 198 RTNAME(Pack)(result, *array, *mask, &*vector, __FILE__, __LINE__); 199 EXPECT_EQ(result.type(), array->type()); 200 EXPECT_EQ(result.rank(), 1); 201 EXPECT_EQ(result.GetDimension(0).LowerBound(), 1); 202 EXPECT_EQ(result.GetDimension(0).Extent(), 5); 203 static std::int32_t packExpect2[5]{2, 3, 6, -4, -5}; 204 for (int j{0}; j < 5; ++j) { 205 EXPECT_EQ(*result.ZeroBasedIndexedElement<std::int32_t>(j), packExpect2[j]) 206 << " at " << j; 207 } 208 result.Destroy(); 209 } 210 211 TEST(Transformational, Spread) { 212 auto array{MakeArray<TypeCategory::Integer, 4>( 213 std::vector<int>{3}, std::vector<std::int32_t>{1, 2, 3})}; 214 array->GetDimension(0).SetLowerBound(2); // shouldn't matter 215 StaticDescriptor<2, true> statDesc; 216 Descriptor &result{statDesc.descriptor()}; 217 218 RTNAME(Spread)(result, *array, 1, 2, __FILE__, __LINE__); 219 EXPECT_EQ(result.type(), array->type()); 220 EXPECT_EQ(result.rank(), 2); 221 EXPECT_EQ(result.GetDimension(0).LowerBound(), 1); 222 EXPECT_EQ(result.GetDimension(0).Extent(), 2); 223 EXPECT_EQ(result.GetDimension(1).LowerBound(), 1); 224 EXPECT_EQ(result.GetDimension(1).Extent(), 3); 225 for (int j{0}; j < 6; ++j) { 226 EXPECT_EQ(*result.ZeroBasedIndexedElement<std::int32_t>(j), 1 + j / 2); 227 } 228 result.Destroy(); 229 230 RTNAME(Spread)(result, *array, 2, 2, __FILE__, __LINE__); 231 EXPECT_EQ(result.type(), array->type()); 232 EXPECT_EQ(result.rank(), 2); 233 EXPECT_EQ(result.GetDimension(0).LowerBound(), 1); 234 EXPECT_EQ(result.GetDimension(0).Extent(), 3); 235 EXPECT_EQ(result.GetDimension(1).LowerBound(), 1); 236 EXPECT_EQ(result.GetDimension(1).Extent(), 2); 237 for (int j{0}; j < 6; ++j) { 238 EXPECT_EQ(*result.ZeroBasedIndexedElement<std::int32_t>(j), 1 + j % 3); 239 } 240 result.Destroy(); 241 242 auto scalar{MakeArray<TypeCategory::Integer, 4>( 243 std::vector<int>{}, std::vector<std::int32_t>{1})}; 244 RTNAME(Spread)(result, *scalar, 1, 2, __FILE__, __LINE__); 245 EXPECT_EQ(result.type(), array->type()); 246 EXPECT_EQ(result.rank(), 1); 247 EXPECT_EQ(result.GetDimension(0).LowerBound(), 1); 248 EXPECT_EQ(result.GetDimension(0).Extent(), 2); 249 for (int j{0}; j < 2; ++j) { 250 EXPECT_EQ(*result.ZeroBasedIndexedElement<std::int32_t>(j), 1); 251 } 252 result.Destroy(); 253 } 254 255 TEST(Transformational, Transpose) { 256 // ARRAY 1 3 5 257 // 2 4 6 258 auto array{MakeArray<TypeCategory::Integer, 4>( 259 std::vector<int>{2, 3}, std::vector<std::int32_t>{1, 2, 3, 4, 5, 6})}; 260 array->GetDimension(0).SetLowerBound(2); // shouldn't matter 261 array->GetDimension(1).SetLowerBound(-6); 262 StaticDescriptor<2, true> statDesc; 263 Descriptor &result{statDesc.descriptor()}; 264 RTNAME(Transpose)(result, *array, __FILE__, __LINE__); 265 EXPECT_EQ(result.type(), array->type()); 266 EXPECT_EQ(result.rank(), 2); 267 EXPECT_EQ(result.GetDimension(0).LowerBound(), 1); 268 EXPECT_EQ(result.GetDimension(0).Extent(), 3); 269 EXPECT_EQ(result.GetDimension(1).LowerBound(), 1); 270 EXPECT_EQ(result.GetDimension(1).Extent(), 2); 271 static std::int32_t expect[6]{1, 3, 5, 2, 4, 6}; 272 for (int j{0}; j < 6; ++j) { 273 EXPECT_EQ(*result.ZeroBasedIndexedElement<std::int32_t>(j), expect[j]); 274 } 275 result.Destroy(); 276 } 277 278 TEST(Transformational, Unpack) { 279 auto vector{MakeArray<TypeCategory::Integer, 4>( 280 std::vector<int>{4}, std::vector<std::int32_t>{1, 2, 3, 4})}; 281 vector->GetDimension(0).SetLowerBound(2); // shouldn't matter 282 auto mask{MakeArray<TypeCategory::Logical, 1>(std::vector<int>{2, 3}, 283 std::vector<std::uint8_t>{false, true, true, false, false, true})}; 284 mask->GetDimension(0).SetLowerBound(0); // shouldn't matter 285 mask->GetDimension(1).SetLowerBound(2); 286 auto field{MakeArray<TypeCategory::Integer, 4>(std::vector<int>{2, 3}, 287 std::vector<std::int32_t>{-1, -2, -3, -4, -5, -6})}; 288 field->GetDimension(0).SetLowerBound(-1); // shouldn't matter 289 StaticDescriptor<2, true> statDesc; 290 Descriptor &result{statDesc.descriptor()}; 291 RTNAME(Unpack)(result, *vector, *mask, *field, __FILE__, __LINE__); 292 EXPECT_EQ(result.type(), vector->type()); 293 EXPECT_EQ(result.rank(), 2); 294 EXPECT_EQ(result.GetDimension(0).LowerBound(), 1); 295 EXPECT_EQ(result.GetDimension(0).Extent(), 2); 296 EXPECT_EQ(result.GetDimension(1).LowerBound(), 1); 297 EXPECT_EQ(result.GetDimension(1).Extent(), 3); 298 static std::int32_t expect[6]{-1, 1, 2, -4, -5, 3}; 299 for (int j{0}; j < 6; ++j) { 300 EXPECT_EQ(*result.ZeroBasedIndexedElement<std::int32_t>(j), expect[j]); 301 } 302 result.Destroy(); 303 304 // Test for scalar value of the "field" argument 305 auto scalarField{MakeArray<TypeCategory::Integer, 4>( 306 std::vector<int>{}, std::vector<std::int32_t>{343})}; 307 RTNAME(Unpack)(result, *vector, *mask, *scalarField, __FILE__, __LINE__); 308 EXPECT_EQ(result.rank(), 2); 309 EXPECT_EQ(result.GetDimension(0).LowerBound(), 1); 310 EXPECT_EQ(result.GetDimension(0).Extent(), 2); 311 EXPECT_EQ(result.GetDimension(1).LowerBound(), 1); 312 EXPECT_EQ(result.GetDimension(1).Extent(), 3); 313 static std::int32_t scalarExpect[6]{343, 1, 2, 343, 343, 3}; 314 for (int j{0}; j < 6; ++j) { 315 EXPECT_EQ( 316 *result.ZeroBasedIndexedElement<std::int32_t>(j), scalarExpect[j]); 317 } 318 result.Destroy(); 319 } 320