1 #include "testing.h" 2 #include "../../include/flang/ISO_Fortran_binding.h" 3 #include "../../runtime/descriptor.h" 4 #include "llvm/Support/raw_ostream.h" 5 #include <type_traits> 6 7 using namespace Fortran::runtime; 8 using namespace Fortran::ISO; 9 10 // CFI_CDESC_T test helpers 11 template <int rank> class Test_CFI_CDESC_T { 12 public: 13 Test_CFI_CDESC_T() {} 14 ~Test_CFI_CDESC_T() {} 15 void Check() { 16 // Test CFI_CDESC_T macro defined in section 18.5.4 of F2018 standard 17 // CFI_CDESC_T must give storage that is: 18 using type = decltype(dvStorage_); 19 // unqualified 20 MATCH(false, std::is_const<type>::value); 21 MATCH(false, std::is_volatile<type>::value); 22 // suitable in size 23 if (rank > 0) { 24 MATCH(sizeof(dvStorage_), Descriptor::SizeInBytes(rank_, false)); 25 } else { // C++ implementation over-allocates for rank=0 by 24bytes. 26 MATCH(true, sizeof(dvStorage_) >= Descriptor::SizeInBytes(rank_, false)); 27 } 28 // suitable in alignment 29 MATCH(0, 30 reinterpret_cast<std::uintptr_t>(&dvStorage_) & 31 (alignof(CFI_cdesc_t) - 1)); 32 } 33 34 private: 35 static constexpr int rank_{rank}; 36 CFI_CDESC_T(rank) dvStorage_; 37 }; 38 39 template <int rank> static void TestCdescMacroForAllRanksSmallerThan() { 40 static_assert(rank > 0, "rank<0!"); 41 Test_CFI_CDESC_T<rank> obj; 42 obj.Check(); 43 TestCdescMacroForAllRanksSmallerThan<rank - 1>(); 44 } 45 46 template <> void TestCdescMacroForAllRanksSmallerThan<0>() { 47 Test_CFI_CDESC_T<0> obj; 48 obj.Check(); 49 } 50 51 // CFI_establish test helper 52 static void AddNoiseToCdesc(CFI_cdesc_t *dv, CFI_rank_t rank) { 53 static const int trap{0}; 54 dv->rank = 16; 55 // This address is not supposed to be used. Any write attempt should trigger 56 // program termination 57 dv->base_addr = const_cast<int *>(&trap); 58 dv->elem_len = 320; 59 dv->type = CFI_type_struct; 60 dv->attribute = CFI_attribute_pointer; 61 for (int i{0}; i < rank; i++) { 62 dv->dim[i].extent = -42; 63 dv->dim[i].lower_bound = -42; 64 dv->dim[i].sm = -42; 65 } 66 } 67 68 #ifdef VERBOSE 69 static void DumpTestWorld(const void *bAddr, CFI_attribute_t attr, 70 CFI_type_t ty, std::size_t eLen, CFI_rank_t rank, 71 const CFI_index_t *eAddr) { 72 llvm::outs() << " base_addr: "; 73 llvm::outs().write_hex(reinterpret_cast<std::intptr_t>(bAddr)) 74 << " attribute: " << static_cast<int>(attr) 75 << " type: " << static_cast<int>(ty) << " elem_len: " << eLen 76 << " rank: " << static_cast<int>(rank) << " extent: "; 77 llvm::outs().write_hex(reinterpret_cast<std::intptr_t>(eAddr)) << '\n'; 78 llvm::outs().flush(); 79 } 80 #endif 81 82 static void check_CFI_establish(CFI_cdesc_t *dv, void *base_addr, 83 CFI_attribute_t attribute, CFI_type_t type, std::size_t elem_len, 84 CFI_rank_t rank, const CFI_index_t extents[]) { 85 #ifdef VERBOSE 86 DumpTestWorld(base_addr, attribute, type, elem_len, rank, extent); 87 #endif 88 // CFI_establish reqs from F2018 section 18.5.5 89 int retCode{ 90 CFI_establish(dv, base_addr, attribute, type, elem_len, rank, extents)}; 91 Descriptor *res{reinterpret_cast<Descriptor *>(dv)}; 92 if (retCode == CFI_SUCCESS) { 93 res->Check(); 94 MATCH((attribute == CFI_attribute_pointer), res->IsPointer()); 95 MATCH((attribute == CFI_attribute_allocatable), res->IsAllocatable()); 96 MATCH(rank, res->rank()); 97 MATCH(reinterpret_cast<std::intptr_t>(dv->base_addr), 98 reinterpret_cast<std::intptr_t>(base_addr)); 99 MATCH(true, dv->version == CFI_VERSION); 100 if (base_addr != nullptr) { 101 MATCH(true, res->IsContiguous()); 102 for (int i{0}; i < rank; ++i) { 103 MATCH(extents[i], res->GetDimension(i).Extent()); 104 } 105 } 106 if (attribute == CFI_attribute_allocatable) { 107 MATCH(res->IsAllocated(), false); 108 } 109 if (attribute == CFI_attribute_pointer) { 110 if (base_addr != nullptr) { 111 for (int i{0}; i < rank; ++i) { 112 MATCH(0, res->GetDimension(i).LowerBound()); 113 } 114 } 115 } 116 if (type == CFI_type_struct || type == CFI_type_char || 117 type == CFI_type_other) { 118 MATCH(elem_len, res->ElementBytes()); 119 } 120 } 121 // Checking failure/success according to combination of args forbidden by the 122 // standard: 123 int numErr{0}; 124 int expectedRetCode{CFI_SUCCESS}; 125 if (base_addr != nullptr && attribute == CFI_attribute_allocatable) { 126 ++numErr; 127 expectedRetCode = CFI_ERROR_BASE_ADDR_NOT_NULL; 128 } 129 if (rank > CFI_MAX_RANK) { 130 ++numErr; 131 expectedRetCode = CFI_INVALID_RANK; 132 } 133 if (type < 0 || type > CFI_TYPE_LAST) { 134 ++numErr; 135 expectedRetCode = CFI_INVALID_TYPE; 136 } 137 138 if ((type == CFI_type_struct || type == CFI_type_char || 139 type == CFI_type_other) && 140 elem_len <= 0) { 141 ++numErr; 142 expectedRetCode = CFI_INVALID_ELEM_LEN; 143 } 144 if (rank > 0 && base_addr != nullptr && extents == nullptr) { 145 ++numErr; 146 expectedRetCode = CFI_INVALID_EXTENT; 147 } 148 if (numErr > 1) { 149 MATCH(true, retCode != CFI_SUCCESS); 150 } else { 151 MATCH(retCode, expectedRetCode); 152 } 153 } 154 155 static void run_CFI_establish_tests() { 156 // Testing CFI_establish defined in section 18.5.5 157 CFI_index_t extents[CFI_MAX_RANK]; 158 for (int i{0}; i < CFI_MAX_RANK; ++i) { 159 extents[i] = i + 66; 160 } 161 CFI_CDESC_T(CFI_MAX_RANK) dv_storage; 162 CFI_cdesc_t *dv{&dv_storage}; 163 char base; 164 void *dummyAddr{&base}; 165 // Define test space 166 CFI_attribute_t attrCases[]{ 167 CFI_attribute_pointer, CFI_attribute_allocatable, CFI_attribute_other}; 168 CFI_type_t typeCases[]{CFI_type_int, CFI_type_struct, CFI_type_double, 169 CFI_type_char, CFI_type_other, CFI_TYPE_LAST + 1}; 170 CFI_index_t *extentCases[]{extents, nullptr}; 171 void *baseAddrCases[]{dummyAddr, nullptr}; 172 CFI_rank_t rankCases[]{0, 1, CFI_MAX_RANK, CFI_MAX_RANK + 1}; 173 std::size_t lenCases[]{0, 42}; 174 175 for (CFI_attribute_t attribute : attrCases) { 176 for (void *base_addr : baseAddrCases) { 177 for (CFI_index_t *extent : extentCases) { 178 for (CFI_rank_t rank : rankCases) { 179 for (CFI_type_t type : typeCases) { 180 for (size_t elem_len : lenCases) { 181 AddNoiseToCdesc(dv, CFI_MAX_RANK); 182 check_CFI_establish( 183 dv, base_addr, attribute, type, elem_len, rank, extent); 184 } 185 } 186 } 187 } 188 } 189 } 190 // If base_addr is null, extents shall be ignored even if rank !=0 191 const int rank3d{3}; 192 CFI_CDESC_T(rank3d) dv3darrayStorage; 193 CFI_cdesc_t *dv_3darray{&dv3darrayStorage}; 194 AddNoiseToCdesc(dv_3darray, rank3d); // => dv_3darray->dim[2].extent = -42 195 check_CFI_establish(dv_3darray, nullptr, CFI_attribute_other, CFI_type_int, 4, 196 rank3d, extents); 197 MATCH(false, 198 dv_3darray->dim[2].extent == 2 + 66); // extents was read 199 } 200 201 static void check_CFI_address( 202 const CFI_cdesc_t *dv, const CFI_index_t subscripts[]) { 203 // 18.5.5.2 204 void *addr{CFI_address(dv, subscripts)}; 205 const Descriptor *desc{reinterpret_cast<const Descriptor *>(dv)}; 206 void *addrCheck{desc->Element<void>(subscripts)}; 207 MATCH(true, addr == addrCheck); 208 } 209 210 // Helper function to set lower bound of descriptor 211 static void EstablishLowerBounds(CFI_cdesc_t *dv, CFI_index_t *sub) { 212 for (int i{0}; i < dv->rank; ++i) { 213 dv->dim[i].lower_bound = sub[i]; 214 } 215 } 216 217 // Helper to get size without making internal compiler functions accessible 218 static std::size_t ByteSize(CFI_type_t ty, std::size_t size) { 219 CFI_CDESC_T(0) storage; 220 CFI_cdesc_t *dv{&storage}; 221 int retCode{ 222 CFI_establish(dv, nullptr, CFI_attribute_other, ty, size, 0, nullptr)}; 223 return retCode == CFI_SUCCESS ? dv->elem_len : 0; 224 } 225 226 static void run_CFI_address_tests() { 227 // Test CFI_address defined in 18.5.5.2 228 // Create test world 229 CFI_index_t extents[CFI_MAX_RANK]; 230 CFI_CDESC_T(CFI_MAX_RANK) dv_storage; 231 CFI_cdesc_t *dv{&dv_storage}; 232 char base; 233 void *dummyAddr{&base}; 234 CFI_attribute_t attrCases[]{ 235 CFI_attribute_pointer, CFI_attribute_allocatable, CFI_attribute_other}; 236 CFI_type_t validTypeCases[]{ 237 CFI_type_int, CFI_type_struct, CFI_type_double, CFI_type_char}; 238 CFI_index_t subscripts[CFI_MAX_RANK]; 239 CFI_index_t negativeLowerBounds[CFI_MAX_RANK]; 240 CFI_index_t zeroLowerBounds[CFI_MAX_RANK]; 241 CFI_index_t positiveLowerBounds[CFI_MAX_RANK]; 242 CFI_index_t *lowerBoundCases[]{ 243 negativeLowerBounds, zeroLowerBounds, positiveLowerBounds}; 244 for (int i{0}; i < CFI_MAX_RANK; ++i) { 245 negativeLowerBounds[i] = -1; 246 zeroLowerBounds[i] = 0; 247 positiveLowerBounds[i] = 1; 248 extents[i] = i + 2; 249 subscripts[i] = i + 1; 250 } 251 252 // test for scalar 253 for (CFI_attribute_t attribute : attrCases) { 254 for (CFI_type_t type : validTypeCases) { 255 CFI_establish(dv, dummyAddr, attribute, type, 42, 0, nullptr); 256 check_CFI_address(dv, nullptr); 257 } 258 } 259 // test for arrays 260 CFI_establish(dv, dummyAddr, CFI_attribute_other, CFI_type_int, 0, 261 CFI_MAX_RANK, extents); 262 for (CFI_index_t *lowerBounds : lowerBoundCases) { 263 EstablishLowerBounds(dv, lowerBounds); 264 for (CFI_type_t type : validTypeCases) { 265 for (bool contiguous : {true, false}) { 266 std::size_t size{ByteSize(type, 12)}; 267 dv->elem_len = size; 268 for (int i{0}; i < dv->rank; ++i) { 269 dv->dim[i].sm = size + (contiguous ? 0 : dv->elem_len); 270 size = dv->dim[i].sm * dv->dim[i].extent; 271 } 272 for (CFI_attribute_t attribute : attrCases) { 273 dv->attribute = attribute; 274 check_CFI_address(dv, subscripts); 275 } 276 } 277 } 278 } 279 // Test on an assumed size array. 280 CFI_establish( 281 dv, dummyAddr, CFI_attribute_other, CFI_type_int, 0, 3, extents); 282 dv->dim[2].extent = -1; 283 check_CFI_address(dv, subscripts); 284 } 285 286 static void check_CFI_allocate(CFI_cdesc_t *dv, 287 const CFI_index_t lower_bounds[], const CFI_index_t upper_bounds[], 288 std::size_t elem_len) { 289 // 18.5.5.3 290 // Backup descriptor data for future checks 291 const CFI_rank_t rank{dv->rank}; 292 const std::size_t desc_elem_len{dv->elem_len}; 293 const CFI_attribute_t attribute{dv->attribute}; 294 const CFI_type_t type{dv->type}; 295 const void *base_addr{dv->base_addr}; 296 const int version{dv->version}; 297 #ifdef VERBOSE 298 DumpTestWorld(base_addr, attribute, type, elem_len, rank, nullptr); 299 #endif 300 int retCode{CFI_allocate(dv, lower_bounds, upper_bounds, elem_len)}; 301 Descriptor *desc = reinterpret_cast<Descriptor *>(dv); 302 if (retCode == CFI_SUCCESS) { 303 // check res properties from 18.5.5.3 par 3 304 MATCH(true, dv->base_addr != nullptr); 305 for (int i{0}; i < rank; ++i) { 306 MATCH(lower_bounds[i], dv->dim[i].lower_bound); 307 MATCH(upper_bounds[i], dv->dim[i].extent + dv->dim[i].lower_bound - 1); 308 } 309 if (type == CFI_type_char) { 310 MATCH(elem_len, dv->elem_len); 311 } else { 312 MATCH(true, desc_elem_len == dv->elem_len); 313 } 314 MATCH(true, desc->IsContiguous()); 315 } else { 316 MATCH(true, base_addr == dv->base_addr); 317 } 318 319 // Below dv members shall not be altered by CFI_allocate regardless of 320 // success/failure 321 MATCH(true, attribute == dv->attribute); 322 MATCH(true, rank == dv->rank); 323 MATCH(true, type == dv->type); 324 MATCH(true, version == dv->version); 325 326 // Success/failure according to standard 327 int numErr{0}; 328 int expectedRetCode{CFI_SUCCESS}; 329 if (rank > CFI_MAX_RANK) { 330 ++numErr; 331 expectedRetCode = CFI_INVALID_RANK; 332 } 333 if (type < 0 || type > CFI_TYPE_LAST) { 334 ++numErr; 335 expectedRetCode = CFI_INVALID_TYPE; 336 } 337 if (base_addr != nullptr && attribute == CFI_attribute_allocatable) { 338 // This is less restrictive than 18.5.5.3 arg req for which pointers arg 339 // shall be unassociated. However, this match ALLOCATE behavior 340 // (9.7.3/9.7.4) 341 ++numErr; 342 expectedRetCode = CFI_ERROR_BASE_ADDR_NOT_NULL; 343 } 344 if (attribute != CFI_attribute_pointer && 345 attribute != CFI_attribute_allocatable) { 346 ++numErr; 347 expectedRetCode = CFI_INVALID_ATTRIBUTE; 348 } 349 if (rank > 0 && (lower_bounds == nullptr || upper_bounds == nullptr)) { 350 ++numErr; 351 expectedRetCode = CFI_INVALID_EXTENT; 352 } 353 354 // Memory allocation failures are unpredictable in this test. 355 if (numErr == 0 && retCode != CFI_SUCCESS) { 356 MATCH(true, retCode == CFI_ERROR_MEM_ALLOCATION); 357 } else if (numErr > 1) { 358 MATCH(true, retCode != CFI_SUCCESS); 359 } else { 360 MATCH(expectedRetCode, retCode); 361 } 362 // clean-up 363 if (retCode == CFI_SUCCESS) { 364 CFI_deallocate(dv); 365 } 366 } 367 368 static void run_CFI_allocate_tests() { 369 // 18.5.5.3 370 // create test world 371 CFI_CDESC_T(CFI_MAX_RANK) dv_storage; 372 CFI_cdesc_t *dv{&dv_storage}; 373 char base; 374 void *dummyAddr{&base}; 375 CFI_attribute_t attrCases[]{ 376 CFI_attribute_pointer, CFI_attribute_allocatable, CFI_attribute_other}; 377 CFI_type_t typeCases[]{CFI_type_int, CFI_type_struct, CFI_type_double, 378 CFI_type_char, CFI_type_other, CFI_TYPE_LAST + 1}; 379 void *baseAddrCases[]{dummyAddr, nullptr}; 380 CFI_rank_t rankCases[]{0, 1, CFI_MAX_RANK, CFI_MAX_RANK + 1}; 381 std::size_t lenCases[]{0, 42}; 382 CFI_index_t lb1[CFI_MAX_RANK]; 383 CFI_index_t ub1[CFI_MAX_RANK]; 384 for (int i{0}; i < CFI_MAX_RANK; ++i) { 385 lb1[i] = -1; 386 ub1[i] = 0; 387 } 388 389 check_CFI_establish( 390 dv, nullptr, CFI_attribute_other, CFI_type_int, 0, 0, nullptr); 391 for (CFI_type_t type : typeCases) { 392 std::size_t ty_len{ByteSize(type, 12)}; 393 for (CFI_attribute_t attribute : attrCases) { 394 for (void *base_addr : baseAddrCases) { 395 for (CFI_rank_t rank : rankCases) { 396 for (size_t elem_len : lenCases) { 397 dv->base_addr = base_addr; 398 dv->rank = rank; 399 dv->attribute = attribute; 400 dv->type = type; 401 dv->elem_len = ty_len; 402 check_CFI_allocate(dv, lb1, ub1, elem_len); 403 } 404 } 405 } 406 } 407 } 408 } 409 410 static void run_CFI_section_tests() { 411 // simple tests 412 bool testPreConditions{true}; 413 constexpr CFI_index_t m{5}, n{6}, o{7}; 414 constexpr CFI_rank_t rank{3}; 415 long long array[o][n][m]; // Fortran A(m,n,o) 416 long long counter{1}; 417 418 for (CFI_index_t k{0}; k < o; ++k) { 419 for (CFI_index_t j{0}; j < n; ++j) { 420 for (CFI_index_t i{0}; i < m; ++i) { 421 array[k][j][i] = counter++; // Fortran A(i,j,k) 422 } 423 } 424 } 425 CFI_CDESC_T(rank) sourceStorage; 426 CFI_cdesc_t *source{&sourceStorage}; 427 CFI_index_t extent[rank] = {m, n, o}; 428 int retCode{CFI_establish(source, &array, CFI_attribute_other, 429 CFI_type_long_long, 0, rank, extent)}; 430 testPreConditions &= (retCode == CFI_SUCCESS); 431 432 CFI_index_t lb[rank] = {2, 5, 4}; 433 CFI_index_t ub[rank] = {4, 5, 6}; 434 CFI_index_t strides[rank] = {2, 0, 2}; 435 constexpr CFI_rank_t resultRank{rank - 1}; 436 437 CFI_CDESC_T(resultRank) resultStorage; 438 CFI_cdesc_t *result{&resultStorage}; 439 retCode = CFI_establish(result, nullptr, CFI_attribute_other, 440 CFI_type_long_long, 0, resultRank, nullptr); 441 testPreConditions &= (retCode == CFI_SUCCESS); 442 443 if (!testPreConditions) { 444 MATCH(true, testPreConditions); 445 return; 446 } 447 448 retCode = CFI_section( 449 result, source, lb, ub, strides); // Fortran B = A(2:4:2, 5:5:0, 4:6:2) 450 MATCH(true, retCode == CFI_SUCCESS); 451 452 const CFI_index_t lbs0{source->dim[0].lower_bound}; 453 const CFI_index_t lbs1{source->dim[1].lower_bound}; 454 const CFI_index_t lbs2{source->dim[2].lower_bound}; 455 456 CFI_index_t resJ{result->dim[1].lower_bound}; 457 for (CFI_index_t k{lb[2]}; k <= ub[2]; k += strides[2]) { 458 for (CFI_index_t j{lb[1]}; j <= ub[1]; j += strides[1] ? strides[1] : 1) { 459 CFI_index_t resI{result->dim[0].lower_bound}; 460 for (CFI_index_t i{lb[0]}; i <= ub[0]; i += strides[0]) { 461 // check A(i,j,k) == B(resI, resJ) == array[k-1][j-1][i-1] 462 const CFI_index_t resSubcripts[]{resI, resJ}; 463 const CFI_index_t srcSubcripts[]{i, j, k}; 464 MATCH(true, 465 CFI_address(source, srcSubcripts) == 466 CFI_address(result, resSubcripts)); 467 MATCH(true, 468 CFI_address(source, srcSubcripts) == 469 &array[k - lbs2][j - lbs1][i - lbs0]); 470 ++resI; 471 } 472 } 473 ++resJ; 474 } 475 476 strides[0] = -1; 477 lb[0] = 4; 478 ub[0] = 2; 479 retCode = CFI_section( 480 result, source, lb, ub, strides); // Fortran B = A(4:2:-1, 5:5:0, 4:6:2) 481 MATCH(true, retCode == CFI_SUCCESS); 482 483 resJ = result->dim[1].lower_bound; 484 for (CFI_index_t k{lb[2]}; k <= ub[2]; k += strides[2]) { 485 for (CFI_index_t j{lb[1]}; j <= ub[1]; j += 1) { 486 CFI_index_t resI{result->dim[1].lower_bound + result->dim[0].extent - 1}; 487 for (CFI_index_t i{2}; i <= 4; ++i) { 488 // check A(i,j,k) == B(resI, resJ) == array[k-1][j-1][i-1] 489 const CFI_index_t resSubcripts[]{resI, resJ}; 490 const CFI_index_t srcSubcripts[]{i, j, k}; 491 MATCH(true, 492 CFI_address(source, srcSubcripts) == 493 CFI_address(result, resSubcripts)); 494 MATCH(true, 495 CFI_address(source, srcSubcripts) == 496 &array[k - lbs2][j - lbs1][i - lbs0]); 497 --resI; 498 } 499 } 500 ++resJ; 501 } 502 } 503 504 static void run_CFI_select_part_tests() { 505 constexpr std::size_t name_len{5}; 506 typedef struct { 507 double distance; 508 int stars; 509 char name[name_len]; 510 } Galaxy; 511 512 const CFI_rank_t rank{2}; 513 constexpr CFI_index_t universeSize[]{2, 3}; 514 Galaxy universe[universeSize[1]][universeSize[0]]; 515 516 for (int i{0}; i < universeSize[1]; ++i) { 517 for (int j{0}; j < universeSize[0]; ++j) { 518 // Initializing Fortran var universe(j,i) 519 universe[i][j].distance = j + i * 32; 520 universe[i][j].stars = j * 2 + i * 64; 521 universe[i][j].name[2] = static_cast<char>(j); 522 universe[i][j].name[3] = static_cast<char>(i); 523 } 524 } 525 526 CFI_CDESC_T(rank) resStorage, srcStorage; 527 CFI_cdesc_t *result{&resStorage}; 528 CFI_cdesc_t *source{&srcStorage}; 529 530 bool testPreConditions{true}; 531 int retCode{CFI_establish(result, nullptr, CFI_attribute_other, CFI_type_int, 532 sizeof(int), rank, nullptr)}; 533 testPreConditions &= (retCode == CFI_SUCCESS); 534 retCode = CFI_establish(source, &universe, CFI_attribute_other, 535 CFI_type_struct, sizeof(Galaxy), rank, universeSize); 536 testPreConditions &= (retCode == CFI_SUCCESS); 537 if (!testPreConditions) { 538 MATCH(true, testPreConditions); 539 return; 540 } 541 542 std::size_t displacement{offsetof(Galaxy, stars)}; 543 std::size_t elem_len{0}; // ignored 544 retCode = CFI_select_part(result, source, displacement, elem_len); 545 MATCH(CFI_SUCCESS, retCode); 546 547 bool baseAddrShiftedOk{ 548 static_cast<char *>(source->base_addr) + displacement == 549 result->base_addr}; 550 MATCH(true, baseAddrShiftedOk); 551 if (!baseAddrShiftedOk) { 552 return; 553 } 554 555 MATCH(sizeof(int), result->elem_len); 556 for (CFI_index_t j{0}; j < universeSize[1]; ++j) { 557 for (CFI_index_t i{0}; i < universeSize[0]; ++i) { 558 CFI_index_t subscripts[]{ 559 result->dim[0].lower_bound + i, result->dim[1].lower_bound + j}; 560 MATCH( 561 i * 2 + j * 64, *static_cast<int *>(CFI_address(result, subscripts))); 562 } 563 } 564 565 // Test for Fortran character type 566 retCode = CFI_establish( 567 result, nullptr, CFI_attribute_other, CFI_type_char, 2, rank, nullptr); 568 testPreConditions &= (retCode == CFI_SUCCESS); 569 if (!testPreConditions) { 570 MATCH(true, testPreConditions); 571 return; 572 } 573 574 displacement = offsetof(Galaxy, name) + 2; 575 elem_len = 2; // not ignored this time 576 retCode = CFI_select_part(result, source, displacement, elem_len); 577 MATCH(CFI_SUCCESS, retCode); 578 579 baseAddrShiftedOk = static_cast<char *>(source->base_addr) + displacement == 580 result->base_addr; 581 MATCH(true, baseAddrShiftedOk); 582 if (!baseAddrShiftedOk) { 583 return; 584 } 585 586 MATCH(elem_len, result->elem_len); 587 for (CFI_index_t j{0}; j < universeSize[1]; ++j) { 588 for (CFI_index_t i{0}; i < universeSize[0]; ++i) { 589 CFI_index_t subscripts[]{ 590 result->dim[0].lower_bound + i, result->dim[1].lower_bound + j}; 591 MATCH(static_cast<char>(i), 592 static_cast<char *>(CFI_address(result, subscripts))[0]); 593 MATCH(static_cast<char>(j), 594 static_cast<char *>(CFI_address(result, subscripts))[1]); 595 } 596 } 597 } 598 599 static void run_CFI_setpointer_tests() { 600 constexpr CFI_rank_t rank{3}; 601 CFI_CDESC_T(rank) resStorage, srcStorage; 602 CFI_cdesc_t *result{&resStorage}; 603 CFI_cdesc_t *source{&srcStorage}; 604 CFI_index_t lower_bounds[rank]; 605 CFI_index_t extents[rank]; 606 for (int i{0}; i < rank; ++i) { 607 lower_bounds[i] = i; 608 extents[i] = 2; 609 } 610 611 char target; 612 char *dummyBaseAddress{&target}; 613 bool testPreConditions{true}; 614 CFI_type_t type{CFI_type_int}; 615 std::size_t elem_len{ByteSize(type, 42)}; 616 int retCode{CFI_establish( 617 result, nullptr, CFI_attribute_pointer, type, elem_len, rank, nullptr)}; 618 testPreConditions &= (retCode == CFI_SUCCESS); 619 retCode = CFI_establish(source, dummyBaseAddress, CFI_attribute_other, type, 620 elem_len, rank, extents); 621 testPreConditions &= (retCode == CFI_SUCCESS); 622 if (!testPreConditions) { 623 MATCH(true, testPreConditions); 624 return; 625 } 626 627 retCode = CFI_setpointer(result, source, lower_bounds); 628 MATCH(CFI_SUCCESS, retCode); 629 630 // The following members must be invariant 631 MATCH(rank, result->rank); 632 MATCH(elem_len, result->elem_len); 633 MATCH(type, result->type); 634 // check pointer association 635 MATCH(true, result->base_addr == source->base_addr); 636 for (int j{0}; j < rank; ++j) { 637 MATCH(source->dim[j].extent, result->dim[j].extent); 638 MATCH(source->dim[j].sm, result->dim[j].sm); 639 MATCH(lower_bounds[j], result->dim[j].lower_bound); 640 } 641 } 642 643 int main() { 644 TestCdescMacroForAllRanksSmallerThan<CFI_MAX_RANK>(); 645 run_CFI_establish_tests(); 646 run_CFI_address_tests(); 647 run_CFI_allocate_tests(); 648 // TODO: test CFI_deallocate 649 // TODO: test CFI_is_contiguous 650 run_CFI_section_tests(); 651 run_CFI_select_part_tests(); 652 run_CFI_setpointer_tests(); 653 return testing::Complete(); 654 } 655