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