1352d347aSAlexis Perry //===-- runtime/ISO_Fortran_binding.cpp -----------------------------------===//
2352d347aSAlexis Perry //
3352d347aSAlexis Perry // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4352d347aSAlexis Perry // See https://llvm.org/LICENSE.txt for license information.
5352d347aSAlexis Perry // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6352d347aSAlexis Perry //
7352d347aSAlexis Perry //===----------------------------------------------------------------------===//
8352d347aSAlexis Perry 
9352d347aSAlexis Perry // Implements the required interoperability API from ISO_Fortran_binding.h
10352d347aSAlexis Perry // as specified in section 18.5.5 of Fortran 2018.
11352d347aSAlexis Perry 
12830c0b90SPeter Klausler #include "flang/ISO_Fortran_binding.h"
13830c0b90SPeter Klausler #include "flang/Runtime/descriptor.h"
143b635714Speter klausler #include <cstdlib>
15352d347aSAlexis Perry 
16352d347aSAlexis Perry namespace Fortran::ISO {
17352d347aSAlexis Perry extern "C" {
18352d347aSAlexis Perry 
IsCharacterType(CFI_type_t ty)19352d347aSAlexis Perry static inline constexpr bool IsCharacterType(CFI_type_t ty) {
203d627d6fSpeter klausler   return ty == CFI_type_char || ty == CFI_type_char16_t ||
213d627d6fSpeter klausler       ty == CFI_type_char32_t;
22352d347aSAlexis Perry }
IsAssumedSize(const CFI_cdesc_t * dv)23352d347aSAlexis Perry static inline constexpr bool IsAssumedSize(const CFI_cdesc_t *dv) {
24352d347aSAlexis Perry   return dv->rank > 0 && dv->dim[dv->rank - 1].extent == -1;
25352d347aSAlexis Perry }
26352d347aSAlexis Perry 
CFI_address(const CFI_cdesc_t * descriptor,const CFI_index_t subscripts[])27352d347aSAlexis Perry void *CFI_address(
28352d347aSAlexis Perry     const CFI_cdesc_t *descriptor, const CFI_index_t subscripts[]) {
29352d347aSAlexis Perry   char *p{static_cast<char *>(descriptor->base_addr)};
30352d347aSAlexis Perry   const CFI_rank_t rank{descriptor->rank};
31352d347aSAlexis Perry   const CFI_dim_t *dim{descriptor->dim};
32352d347aSAlexis Perry   for (CFI_rank_t j{0}; j < rank; ++j, ++dim) {
33352d347aSAlexis Perry     p += (subscripts[j] - dim->lower_bound) * dim->sm;
34352d347aSAlexis Perry   }
35352d347aSAlexis Perry   return p;
36352d347aSAlexis Perry }
37352d347aSAlexis Perry 
CFI_allocate(CFI_cdesc_t * descriptor,const CFI_index_t lower_bounds[],const CFI_index_t upper_bounds[],std::size_t elem_len)38352d347aSAlexis Perry int CFI_allocate(CFI_cdesc_t *descriptor, const CFI_index_t lower_bounds[],
39352d347aSAlexis Perry     const CFI_index_t upper_bounds[], std::size_t elem_len) {
40352d347aSAlexis Perry   if (!descriptor) {
41352d347aSAlexis Perry     return CFI_INVALID_DESCRIPTOR;
42352d347aSAlexis Perry   }
43352d347aSAlexis Perry   if (descriptor->version != CFI_VERSION) {
44352d347aSAlexis Perry     return CFI_INVALID_DESCRIPTOR;
45352d347aSAlexis Perry   }
46352d347aSAlexis Perry   if (descriptor->attribute != CFI_attribute_allocatable &&
47352d347aSAlexis Perry       descriptor->attribute != CFI_attribute_pointer) {
48352d347aSAlexis Perry     // Non-interoperable object
49352d347aSAlexis Perry     return CFI_INVALID_ATTRIBUTE;
50352d347aSAlexis Perry   }
51352d347aSAlexis Perry   if (descriptor->attribute == CFI_attribute_allocatable &&
52352d347aSAlexis Perry       descriptor->base_addr) {
53352d347aSAlexis Perry     return CFI_ERROR_BASE_ADDR_NOT_NULL;
54352d347aSAlexis Perry   }
55352d347aSAlexis Perry   if (descriptor->rank > CFI_MAX_RANK) {
56352d347aSAlexis Perry     return CFI_INVALID_RANK;
57352d347aSAlexis Perry   }
58352d347aSAlexis Perry   if (descriptor->type < CFI_type_signed_char ||
5932f901bdSDiana Picus       descriptor->type > CFI_TYPE_LAST) {
60352d347aSAlexis Perry     return CFI_INVALID_TYPE;
61352d347aSAlexis Perry   }
62352d347aSAlexis Perry   if (!IsCharacterType(descriptor->type)) {
63352d347aSAlexis Perry     elem_len = descriptor->elem_len;
64352d347aSAlexis Perry     if (elem_len <= 0) {
65352d347aSAlexis Perry       return CFI_INVALID_ELEM_LEN;
66352d347aSAlexis Perry     }
67352d347aSAlexis Perry   }
68352d347aSAlexis Perry   std::size_t rank{descriptor->rank};
69352d347aSAlexis Perry   CFI_dim_t *dim{descriptor->dim};
70352d347aSAlexis Perry   std::size_t byteSize{elem_len};
71352d347aSAlexis Perry   for (std::size_t j{0}; j < rank; ++j, ++dim) {
72352d347aSAlexis Perry     CFI_index_t lb{lower_bounds[j]};
73352d347aSAlexis Perry     CFI_index_t ub{upper_bounds[j]};
74352d347aSAlexis Perry     CFI_index_t extent{ub >= lb ? ub - lb + 1 : 0};
75*3b61587cSPeter Klausler     dim->lower_bound = extent == 0 ? 1 : lb;
76352d347aSAlexis Perry     dim->extent = extent;
77352d347aSAlexis Perry     dim->sm = byteSize;
78352d347aSAlexis Perry     byteSize *= extent;
79352d347aSAlexis Perry   }
803b635714Speter klausler   void *p{std::malloc(byteSize)};
818df28f0aSpeter klausler   if (!p && byteSize) {
82352d347aSAlexis Perry     return CFI_ERROR_MEM_ALLOCATION;
83352d347aSAlexis Perry   }
84352d347aSAlexis Perry   descriptor->base_addr = p;
85352d347aSAlexis Perry   descriptor->elem_len = elem_len;
86352d347aSAlexis Perry   return CFI_SUCCESS;
87352d347aSAlexis Perry }
88352d347aSAlexis Perry 
CFI_deallocate(CFI_cdesc_t * descriptor)89352d347aSAlexis Perry int CFI_deallocate(CFI_cdesc_t *descriptor) {
90352d347aSAlexis Perry   if (!descriptor) {
91352d347aSAlexis Perry     return CFI_INVALID_DESCRIPTOR;
92352d347aSAlexis Perry   }
93352d347aSAlexis Perry   if (descriptor->version != CFI_VERSION) {
94352d347aSAlexis Perry     return CFI_INVALID_DESCRIPTOR;
95352d347aSAlexis Perry   }
96352d347aSAlexis Perry   if (descriptor->attribute != CFI_attribute_allocatable &&
97352d347aSAlexis Perry       descriptor->attribute != CFI_attribute_pointer) {
98352d347aSAlexis Perry     // Non-interoperable object
99352d347aSAlexis Perry     return CFI_INVALID_DESCRIPTOR;
100352d347aSAlexis Perry   }
101352d347aSAlexis Perry   if (!descriptor->base_addr) {
102352d347aSAlexis Perry     return CFI_ERROR_BASE_ADDR_NULL;
103352d347aSAlexis Perry   }
1043b635714Speter klausler   std::free(descriptor->base_addr);
105352d347aSAlexis Perry   descriptor->base_addr = nullptr;
106352d347aSAlexis Perry   return CFI_SUCCESS;
107352d347aSAlexis Perry }
108352d347aSAlexis Perry 
MinElemLen(CFI_type_t type)109352d347aSAlexis Perry static constexpr std::size_t MinElemLen(CFI_type_t type) {
110352d347aSAlexis Perry   std::size_t minElemLen{0};
111352d347aSAlexis Perry   switch (type) {
1121f879005STim Keith   case CFI_type_signed_char:
1131f879005STim Keith     minElemLen = sizeof(signed char);
1141f879005STim Keith     break;
1151f879005STim Keith   case CFI_type_short:
1161f879005STim Keith     minElemLen = sizeof(short);
1171f879005STim Keith     break;
1181f879005STim Keith   case CFI_type_int:
1191f879005STim Keith     minElemLen = sizeof(int);
1201f879005STim Keith     break;
1211f879005STim Keith   case CFI_type_long:
1221f879005STim Keith     minElemLen = sizeof(long);
1231f879005STim Keith     break;
1241f879005STim Keith   case CFI_type_long_long:
1251f879005STim Keith     minElemLen = sizeof(long long);
1261f879005STim Keith     break;
1271f879005STim Keith   case CFI_type_size_t:
1281f879005STim Keith     minElemLen = sizeof(std::size_t);
1291f879005STim Keith     break;
1301f879005STim Keith   case CFI_type_int8_t:
1311f879005STim Keith     minElemLen = sizeof(std::int8_t);
1321f879005STim Keith     break;
1331f879005STim Keith   case CFI_type_int16_t:
1341f879005STim Keith     minElemLen = sizeof(std::int16_t);
1351f879005STim Keith     break;
1361f879005STim Keith   case CFI_type_int32_t:
1371f879005STim Keith     minElemLen = sizeof(std::int32_t);
1381f879005STim Keith     break;
1391f879005STim Keith   case CFI_type_int64_t:
1401f879005STim Keith     minElemLen = sizeof(std::int64_t);
1411f879005STim Keith     break;
1421f879005STim Keith   case CFI_type_int128_t:
1431f879005STim Keith     minElemLen = 2 * sizeof(std::int64_t);
1441f879005STim Keith     break;
1451f879005STim Keith   case CFI_type_int_least8_t:
1461f879005STim Keith     minElemLen = sizeof(std::int_least8_t);
1471f879005STim Keith     break;
1481f879005STim Keith   case CFI_type_int_least16_t:
1491f879005STim Keith     minElemLen = sizeof(std::int_least16_t);
1501f879005STim Keith     break;
1511f879005STim Keith   case CFI_type_int_least32_t:
1521f879005STim Keith     minElemLen = sizeof(std::int_least32_t);
1531f879005STim Keith     break;
1541f879005STim Keith   case CFI_type_int_least64_t:
1551f879005STim Keith     minElemLen = sizeof(std::int_least64_t);
1561f879005STim Keith     break;
157352d347aSAlexis Perry   case CFI_type_int_least128_t:
158352d347aSAlexis Perry     minElemLen = 2 * sizeof(std::int_least64_t);
159352d347aSAlexis Perry     break;
1601f879005STim Keith   case CFI_type_int_fast8_t:
1611f879005STim Keith     minElemLen = sizeof(std::int_fast8_t);
1621f879005STim Keith     break;
1631f879005STim Keith   case CFI_type_int_fast16_t:
1641f879005STim Keith     minElemLen = sizeof(std::int_fast16_t);
1651f879005STim Keith     break;
1661f879005STim Keith   case CFI_type_int_fast32_t:
1671f879005STim Keith     minElemLen = sizeof(std::int_fast32_t);
1681f879005STim Keith     break;
1691f879005STim Keith   case CFI_type_int_fast64_t:
1701f879005STim Keith     minElemLen = sizeof(std::int_fast64_t);
1711f879005STim Keith     break;
1721f879005STim Keith   case CFI_type_intmax_t:
1731f879005STim Keith     minElemLen = sizeof(std::intmax_t);
1741f879005STim Keith     break;
1751f879005STim Keith   case CFI_type_intptr_t:
1761f879005STim Keith     minElemLen = sizeof(std::intptr_t);
1771f879005STim Keith     break;
1781f879005STim Keith   case CFI_type_ptrdiff_t:
1791f879005STim Keith     minElemLen = sizeof(std::ptrdiff_t);
1801f879005STim Keith     break;
181e43b2e4fSV Donaldson   case CFI_type_half_float:
182e43b2e4fSV Donaldson     minElemLen = 2;
183e43b2e4fSV Donaldson     break;
184e43b2e4fSV Donaldson   case CFI_type_bfloat:
185e43b2e4fSV Donaldson     minElemLen = 2;
186e43b2e4fSV Donaldson     break;
1871f879005STim Keith   case CFI_type_float:
1881f879005STim Keith     minElemLen = sizeof(float);
1891f879005STim Keith     break;
1901f879005STim Keith   case CFI_type_double:
1911f879005STim Keith     minElemLen = sizeof(double);
1921f879005STim Keith     break;
193e43b2e4fSV Donaldson   case CFI_type_extended_double:
194e43b2e4fSV Donaldson     minElemLen = 10;
195e43b2e4fSV Donaldson     break;
1961f879005STim Keith   case CFI_type_long_double:
1971f879005STim Keith     minElemLen = sizeof(long double);
1981f879005STim Keith     break;
199e43b2e4fSV Donaldson   case CFI_type_float128:
200e43b2e4fSV Donaldson     minElemLen = 16;
201e43b2e4fSV Donaldson     break;
202e43b2e4fSV Donaldson   case CFI_type_half_float_Complex:
203e43b2e4fSV Donaldson     minElemLen = 2 * MinElemLen(CFI_type_half_float);
204e43b2e4fSV Donaldson     break;
205e43b2e4fSV Donaldson   case CFI_type_bfloat_Complex:
206e43b2e4fSV Donaldson     minElemLen = 2 * MinElemLen(CFI_type_bfloat);
207e43b2e4fSV Donaldson     break;
2081f879005STim Keith   case CFI_type_float_Complex:
2091f879005STim Keith     minElemLen = 2 * sizeof(float);
2101f879005STim Keith     break;
2111f879005STim Keith   case CFI_type_double_Complex:
2121f879005STim Keith     minElemLen = 2 * sizeof(double);
2131f879005STim Keith     break;
214e43b2e4fSV Donaldson   case CFI_type_extended_double_Complex:
215e43b2e4fSV Donaldson     minElemLen = 2 * MinElemLen(CFI_type_extended_double);
216e43b2e4fSV Donaldson     break;
217352d347aSAlexis Perry   case CFI_type_long_double_Complex:
218352d347aSAlexis Perry     minElemLen = 2 * sizeof(long double);
219352d347aSAlexis Perry     break;
220e43b2e4fSV Donaldson   case CFI_type_float128_Complex:
221e43b2e4fSV Donaldson     minElemLen = 2 * MinElemLen(CFI_type_float128);
222e43b2e4fSV Donaldson     break;
2231f879005STim Keith   case CFI_type_Bool:
2241f879005STim Keith     minElemLen = 1;
2251f879005STim Keith     break;
2261f879005STim Keith   case CFI_type_cptr:
2271f879005STim Keith     minElemLen = sizeof(void *);
2281f879005STim Keith     break;
2293d627d6fSpeter klausler   case CFI_type_char16_t:
2303d627d6fSpeter klausler     minElemLen = sizeof(char16_t);
2313d627d6fSpeter klausler     break;
2323d627d6fSpeter klausler   case CFI_type_char32_t:
2333d627d6fSpeter klausler     minElemLen = sizeof(char32_t);
2343d627d6fSpeter klausler     break;
235352d347aSAlexis Perry   }
236352d347aSAlexis Perry   return minElemLen;
237352d347aSAlexis Perry }
238352d347aSAlexis Perry 
CFI_establish(CFI_cdesc_t * descriptor,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[])239352d347aSAlexis Perry int CFI_establish(CFI_cdesc_t *descriptor, void *base_addr,
240352d347aSAlexis Perry     CFI_attribute_t attribute, CFI_type_t type, std::size_t elem_len,
241352d347aSAlexis Perry     CFI_rank_t rank, const CFI_index_t extents[]) {
242352d347aSAlexis Perry   if (attribute != CFI_attribute_other && attribute != CFI_attribute_pointer &&
243352d347aSAlexis Perry       attribute != CFI_attribute_allocatable) {
244352d347aSAlexis Perry     return CFI_INVALID_ATTRIBUTE;
245352d347aSAlexis Perry   }
246352d347aSAlexis Perry   if (rank > CFI_MAX_RANK) {
247352d347aSAlexis Perry     return CFI_INVALID_RANK;
248352d347aSAlexis Perry   }
249352d347aSAlexis Perry   if (base_addr && attribute == CFI_attribute_allocatable) {
250352d347aSAlexis Perry     return CFI_ERROR_BASE_ADDR_NOT_NULL;
251352d347aSAlexis Perry   }
252352d347aSAlexis Perry   if (rank > 0 && base_addr && !extents) {
253352d347aSAlexis Perry     return CFI_INVALID_EXTENT;
254352d347aSAlexis Perry   }
25532f901bdSDiana Picus   if (type < CFI_type_signed_char || type > CFI_TYPE_LAST) {
256352d347aSAlexis Perry     return CFI_INVALID_TYPE;
257352d347aSAlexis Perry   }
258352d347aSAlexis Perry   if (!descriptor) {
259352d347aSAlexis Perry     return CFI_INVALID_DESCRIPTOR;
260352d347aSAlexis Perry   }
261aaab7040SDiana Picus   if (type == CFI_type_struct || type == CFI_type_other ||
262aaab7040SDiana Picus       IsCharacterType(type)) {
26345cd405dSDiana Picus     if (elem_len <= 0) {
264352d347aSAlexis Perry       return CFI_INVALID_ELEM_LEN;
26545cd405dSDiana Picus     }
266aaab7040SDiana Picus   } else {
267aaab7040SDiana Picus     elem_len = MinElemLen(type);
268aaab7040SDiana Picus     assert(elem_len > 0 && "Unknown element length for type");
269352d347aSAlexis Perry   }
270352d347aSAlexis Perry   descriptor->base_addr = base_addr;
271352d347aSAlexis Perry   descriptor->elem_len = elem_len;
272352d347aSAlexis Perry   descriptor->version = CFI_VERSION;
273352d347aSAlexis Perry   descriptor->rank = rank;
274352d347aSAlexis Perry   descriptor->type = type;
275352d347aSAlexis Perry   descriptor->attribute = attribute;
276352d347aSAlexis Perry   descriptor->f18Addendum = 0;
277352d347aSAlexis Perry   std::size_t byteSize{elem_len};
278352d347aSAlexis Perry   constexpr std::size_t lower_bound{0};
279352d347aSAlexis Perry   if (base_addr) {
280352d347aSAlexis Perry     for (std::size_t j{0}; j < rank; ++j) {
281352d347aSAlexis Perry       descriptor->dim[j].lower_bound = lower_bound;
282352d347aSAlexis Perry       descriptor->dim[j].extent = extents[j];
283352d347aSAlexis Perry       descriptor->dim[j].sm = byteSize;
284352d347aSAlexis Perry       byteSize *= extents[j];
285352d347aSAlexis Perry     }
286352d347aSAlexis Perry   }
287352d347aSAlexis Perry   return CFI_SUCCESS;
288352d347aSAlexis Perry }
289352d347aSAlexis Perry 
CFI_is_contiguous(const CFI_cdesc_t * descriptor)290352d347aSAlexis Perry int CFI_is_contiguous(const CFI_cdesc_t *descriptor) {
291352d347aSAlexis Perry   CFI_index_t bytes = descriptor->elem_len;
292352d347aSAlexis Perry   for (int j{0}; j < descriptor->rank; ++j) {
293352d347aSAlexis Perry     if (bytes != descriptor->dim[j].sm) {
294352d347aSAlexis Perry       return 0;
295352d347aSAlexis Perry     }
296352d347aSAlexis Perry     bytes *= descriptor->dim[j].extent;
297352d347aSAlexis Perry   }
298352d347aSAlexis Perry   return 1;
299352d347aSAlexis Perry }
300352d347aSAlexis Perry 
CFI_section(CFI_cdesc_t * result,const CFI_cdesc_t * source,const CFI_index_t lower_bounds[],const CFI_index_t upper_bounds[],const CFI_index_t strides[])301352d347aSAlexis Perry int CFI_section(CFI_cdesc_t *result, const CFI_cdesc_t *source,
302352d347aSAlexis Perry     const CFI_index_t lower_bounds[], const CFI_index_t upper_bounds[],
303352d347aSAlexis Perry     const CFI_index_t strides[]) {
304352d347aSAlexis Perry   CFI_index_t extent[CFI_MAX_RANK];
305352d347aSAlexis Perry   CFI_index_t actualStride[CFI_MAX_RANK];
306352d347aSAlexis Perry   CFI_rank_t resRank{0};
307352d347aSAlexis Perry 
308352d347aSAlexis Perry   if (!result || !source) {
309352d347aSAlexis Perry     return CFI_INVALID_DESCRIPTOR;
310352d347aSAlexis Perry   }
311352d347aSAlexis Perry   if (source->rank == 0) {
312352d347aSAlexis Perry     return CFI_INVALID_RANK;
313352d347aSAlexis Perry   }
314352d347aSAlexis Perry   if (IsAssumedSize(source) && !upper_bounds) {
315352d347aSAlexis Perry     return CFI_INVALID_DESCRIPTOR;
316352d347aSAlexis Perry   }
317352d347aSAlexis Perry   if ((result->type != source->type) ||
318352d347aSAlexis Perry       (result->elem_len != source->elem_len)) {
319352d347aSAlexis Perry     return CFI_INVALID_DESCRIPTOR;
320352d347aSAlexis Perry   }
321352d347aSAlexis Perry   if (result->attribute == CFI_attribute_allocatable) {
322352d347aSAlexis Perry     return CFI_INVALID_ATTRIBUTE;
323352d347aSAlexis Perry   }
324352d347aSAlexis Perry   if (!source->base_addr) {
325352d347aSAlexis Perry     return CFI_ERROR_BASE_ADDR_NULL;
326352d347aSAlexis Perry   }
327352d347aSAlexis Perry 
328352d347aSAlexis Perry   char *shiftedBaseAddr{static_cast<char *>(source->base_addr)};
329352d347aSAlexis Perry   bool isZeroSized{false};
330352d347aSAlexis Perry   for (int j{0}; j < source->rank; ++j) {
331352d347aSAlexis Perry     const CFI_dim_t &dim{source->dim[j]};
332352d347aSAlexis Perry     const CFI_index_t srcLB{dim.lower_bound};
333352d347aSAlexis Perry     const CFI_index_t srcUB{srcLB + dim.extent - 1};
334352d347aSAlexis Perry     const CFI_index_t lb{lower_bounds ? lower_bounds[j] : srcLB};
335352d347aSAlexis Perry     const CFI_index_t ub{upper_bounds ? upper_bounds[j] : srcUB};
336352d347aSAlexis Perry     const CFI_index_t stride{strides ? strides[j] : 1};
337352d347aSAlexis Perry 
338352d347aSAlexis Perry     if (stride == 0 && lb != ub) {
339352d347aSAlexis Perry       return CFI_ERROR_OUT_OF_BOUNDS;
340352d347aSAlexis Perry     }
341352d347aSAlexis Perry     if ((lb <= ub && stride >= 0) || (lb >= ub && stride < 0)) {
342352d347aSAlexis Perry       if ((lb < srcLB) || (lb > srcUB) || (ub < srcLB) || (ub > srcUB)) {
343352d347aSAlexis Perry         return CFI_ERROR_OUT_OF_BOUNDS;
344352d347aSAlexis Perry       }
345352d347aSAlexis Perry       shiftedBaseAddr += (lb - srcLB) * dim.sm;
346352d347aSAlexis Perry       extent[j] = stride != 0 ? 1 + (ub - lb) / stride : 1;
347352d347aSAlexis Perry     } else {
348352d347aSAlexis Perry       isZeroSized = true;
349352d347aSAlexis Perry       extent[j] = 0;
350352d347aSAlexis Perry     }
351352d347aSAlexis Perry     actualStride[j] = stride;
352352d347aSAlexis Perry     resRank += (stride != 0);
353352d347aSAlexis Perry   }
354352d347aSAlexis Perry   if (resRank != result->rank) {
355352d347aSAlexis Perry     return CFI_INVALID_DESCRIPTOR;
356352d347aSAlexis Perry   }
357352d347aSAlexis Perry 
358352d347aSAlexis Perry   // For zero-sized arrays, base_addr is processor-dependent (see 18.5.3).
359352d347aSAlexis Perry   // We keep it on the source base_addr
360352d347aSAlexis Perry   result->base_addr = isZeroSized ? source->base_addr : shiftedBaseAddr;
361352d347aSAlexis Perry   resRank = 0;
362352d347aSAlexis Perry   for (int j{0}; j < source->rank; ++j) {
363352d347aSAlexis Perry     if (actualStride[j] != 0) {
364352d347aSAlexis Perry       result->dim[resRank].extent = extent[j];
365*3b61587cSPeter Klausler       result->dim[resRank].lower_bound = extent[j] == 0 ? 1
366*3b61587cSPeter Klausler           : lower_bounds                                ? lower_bounds[j]
367*3b61587cSPeter Klausler                          : source->dim[j].lower_bound;
368352d347aSAlexis Perry       result->dim[resRank].sm = actualStride[j] * source->dim[j].sm;
369352d347aSAlexis Perry       ++resRank;
370352d347aSAlexis Perry     }
371352d347aSAlexis Perry   }
372352d347aSAlexis Perry   return CFI_SUCCESS;
373352d347aSAlexis Perry }
374352d347aSAlexis Perry 
CFI_select_part(CFI_cdesc_t * result,const CFI_cdesc_t * source,std::size_t displacement,std::size_t elem_len)375352d347aSAlexis Perry int CFI_select_part(CFI_cdesc_t *result, const CFI_cdesc_t *source,
376352d347aSAlexis Perry     std::size_t displacement, std::size_t elem_len) {
377352d347aSAlexis Perry   if (!result || !source) {
378352d347aSAlexis Perry     return CFI_INVALID_DESCRIPTOR;
379352d347aSAlexis Perry   }
380352d347aSAlexis Perry   if (result->rank != source->rank) {
381352d347aSAlexis Perry     return CFI_INVALID_RANK;
382352d347aSAlexis Perry   }
383352d347aSAlexis Perry   if (result->attribute == CFI_attribute_allocatable) {
384352d347aSAlexis Perry     return CFI_INVALID_ATTRIBUTE;
385352d347aSAlexis Perry   }
386352d347aSAlexis Perry   if (!source->base_addr) {
387352d347aSAlexis Perry     return CFI_ERROR_BASE_ADDR_NULL;
388352d347aSAlexis Perry   }
389352d347aSAlexis Perry   if (IsAssumedSize(source)) {
390352d347aSAlexis Perry     return CFI_INVALID_DESCRIPTOR;
391352d347aSAlexis Perry   }
392352d347aSAlexis Perry 
393352d347aSAlexis Perry   if (!IsCharacterType(result->type)) {
394352d347aSAlexis Perry     elem_len = result->elem_len;
395352d347aSAlexis Perry   }
396352d347aSAlexis Perry   if (displacement + elem_len > source->elem_len) {
397352d347aSAlexis Perry     return CFI_INVALID_ELEM_LEN;
398352d347aSAlexis Perry   }
399352d347aSAlexis Perry 
400352d347aSAlexis Perry   result->base_addr = displacement + static_cast<char *>(source->base_addr);
401352d347aSAlexis Perry   result->elem_len = elem_len;
402352d347aSAlexis Perry   for (int j{0}; j < source->rank; ++j) {
403352d347aSAlexis Perry     result->dim[j].lower_bound = 0;
404352d347aSAlexis Perry     result->dim[j].extent = source->dim[j].extent;
405352d347aSAlexis Perry     result->dim[j].sm = source->dim[j].sm;
406352d347aSAlexis Perry   }
407352d347aSAlexis Perry   return CFI_SUCCESS;
408352d347aSAlexis Perry }
409352d347aSAlexis Perry 
CFI_setpointer(CFI_cdesc_t * result,const CFI_cdesc_t * source,const CFI_index_t lower_bounds[])410352d347aSAlexis Perry int CFI_setpointer(CFI_cdesc_t *result, const CFI_cdesc_t *source,
411352d347aSAlexis Perry     const CFI_index_t lower_bounds[]) {
412352d347aSAlexis Perry   if (!result) {
413352d347aSAlexis Perry     return CFI_INVALID_DESCRIPTOR;
414352d347aSAlexis Perry   }
415352d347aSAlexis Perry   if (result->attribute != CFI_attribute_pointer) {
416352d347aSAlexis Perry     return CFI_INVALID_ATTRIBUTE;
417352d347aSAlexis Perry   }
418352d347aSAlexis Perry   if (!source) {
419352d347aSAlexis Perry     result->base_addr = nullptr;
420352d347aSAlexis Perry     return CFI_SUCCESS;
421352d347aSAlexis Perry   }
422352d347aSAlexis Perry   if (source->rank != result->rank) {
423352d347aSAlexis Perry     return CFI_INVALID_RANK;
424352d347aSAlexis Perry   }
425352d347aSAlexis Perry   if (source->type != result->type) {
426352d347aSAlexis Perry     return CFI_INVALID_TYPE;
427352d347aSAlexis Perry   }
428352d347aSAlexis Perry   if (source->elem_len != result->elem_len) {
429352d347aSAlexis Perry     return CFI_INVALID_ELEM_LEN;
430352d347aSAlexis Perry   }
431352d347aSAlexis Perry   if (!source->base_addr && source->attribute != CFI_attribute_pointer) {
432352d347aSAlexis Perry     return CFI_ERROR_BASE_ADDR_NULL;
433352d347aSAlexis Perry   }
434352d347aSAlexis Perry   if (IsAssumedSize(source)) {
435352d347aSAlexis Perry     return CFI_INVALID_DESCRIPTOR;
436352d347aSAlexis Perry   }
437352d347aSAlexis Perry 
438352d347aSAlexis Perry   const bool copySrcLB{!lower_bounds};
439352d347aSAlexis Perry   result->base_addr = source->base_addr;
440352d347aSAlexis Perry   if (source->base_addr) {
441352d347aSAlexis Perry     for (int j{0}; j < result->rank; ++j) {
442*3b61587cSPeter Klausler       CFI_index_t extent{source->dim[j].extent};
443*3b61587cSPeter Klausler       result->dim[j].extent = extent;
444352d347aSAlexis Perry       result->dim[j].sm = source->dim[j].sm;
445*3b61587cSPeter Klausler       result->dim[j].lower_bound = extent == 0 ? 1
446*3b61587cSPeter Klausler           : copySrcLB                          ? source->dim[j].lower_bound
447*3b61587cSPeter Klausler                                                : lower_bounds[j];
448352d347aSAlexis Perry     }
449352d347aSAlexis Perry   }
450352d347aSAlexis Perry   return CFI_SUCCESS;
451352d347aSAlexis Perry }
452352d347aSAlexis Perry } // extern "C"
4531f879005STim Keith } // namespace Fortran::ISO
454