[flang][runtime] Fix IsContiguous for zero and one element arrays (#68869)

The byte strides in zero and one element array descriptor may not be
perfect multiple of the element size and previous and extents.

IsContiguous and its CFI equivalent should still return true for such
arrays (Fortran 2018 standards says in 8.5.7 that an array is not
contiguous if it has two or more elements and ....).
This commit is contained in:
jeanPerier 2023-10-13 08:34:53 +02:00 committed by GitHub
parent 9bcc094d37
commit 7755cdf03d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 111 additions and 9 deletions

View File

@ -390,14 +390,16 @@ public:
if (leadingDimensions > raw_.rank) {
leadingDimensions = raw_.rank;
}
bool stridesAreContiguous{true};
for (int j{0}; j < leadingDimensions; ++j) {
const Dimension &dim{GetDimension(j)};
if (bytes != dim.ByteStride()) {
return false;
}
stridesAreContiguous &= bytes == dim.ByteStride();
bytes *= dim.Extent();
}
return true;
// One and zero element arrays are contiguous even if the descriptor
// byte strides are not perfect multiples.
return stridesAreContiguous || bytes == 0 ||
bytes == static_cast<SubscriptValue>(ElementBytes());
}
// Establishes a pointer to a section or element.

View File

@ -125,14 +125,19 @@ RT_API_ATTRS int CFI_establish(CFI_cdesc_t *descriptor, void *base_addr,
}
RT_API_ATTRS int CFI_is_contiguous(const CFI_cdesc_t *descriptor) {
bool stridesAreContiguous{true};
CFI_index_t bytes = descriptor->elem_len;
for (int j{0}; j < descriptor->rank; ++j) {
if (bytes != descriptor->dim[j].sm) {
return 0;
}
stridesAreContiguous &= bytes == descriptor->dim[j].sm;
bytes *= descriptor->dim[j].extent;
}
return 1;
// One and zero element arrays are contiguous even if the descriptor
// byte strides are not perfect multiples.
if (stridesAreContiguous || bytes == 0 ||
bytes == static_cast<CFI_index_t>(descriptor->elem_len)) {
return 1;
}
return 0;
}
RT_API_ATTRS int CFI_section(CFI_cdesc_t *result, const CFI_cdesc_t *source,

View File

@ -643,13 +643,108 @@ static void run_CFI_setpointer_tests() {
}
}
static void run_CFI_is_contiguous_tests() {
// INTEGER :: A(0:3,0:3)
constexpr CFI_rank_t rank{2};
CFI_index_t extents[rank] = {4, 4};
CFI_CDESC_T(rank) dv_storage;
CFI_cdesc_t *dv{&dv_storage};
Descriptor *dvDesc{reinterpret_cast<Descriptor *>(dv)};
char base;
void *base_addr{&base};
int retCode{CFI_establish(dv, base_addr, CFI_attribute_other, CFI_type_int,
/*elem_len=*/0, rank, extents)};
MATCH(retCode == CFI_SUCCESS, true);
MATCH(true, CFI_is_contiguous(dv) == 1);
MATCH(true, dvDesc->IsContiguous());
CFI_CDESC_T(rank) sectionDescriptorStorage;
CFI_cdesc_t *section{&sectionDescriptorStorage};
Descriptor *sectionDesc{reinterpret_cast<Descriptor *>(section)};
retCode = CFI_establish(section, base_addr, CFI_attribute_other, CFI_type_int,
/*elem_len=*/0, rank, extents);
MATCH(retCode == CFI_SUCCESS, true);
// Test empty section B = A(0:3:2,0:3:-2) is contiguous.
CFI_index_t lb[rank] = {0, 0};
CFI_index_t ub[rank] = {3, 3};
CFI_index_t strides[rank] = {2, -2};
retCode = CFI_section(section, dv, lb, ub, strides);
MATCH(true, retCode == CFI_SUCCESS);
MATCH(true, CFI_is_contiguous(section) == 1);
MATCH(true, sectionDesc->IsContiguous());
// Test 1 element section B = A(0:1:2,0:1:2) is contiguous.
lb[0] = 0;
lb[1] = 0;
ub[0] = 1;
ub[1] = 1;
strides[0] = 2;
strides[1] = 2;
retCode = CFI_section(section, dv, lb, ub, strides);
MATCH(true, retCode == CFI_SUCCESS);
MATCH(true, CFI_is_contiguous(section) == 1);
MATCH(true, sectionDesc->IsContiguous());
// Test section B = A(0:3:1,0:2:1) is contiguous.
lb[0] = 0;
lb[1] = 0;
ub[0] = 3;
ub[1] = 2;
strides[0] = 1;
strides[1] = 1;
retCode = CFI_section(section, dv, lb, ub, strides);
sectionDesc->Dump();
MATCH(true, retCode == CFI_SUCCESS);
MATCH(true, CFI_is_contiguous(section) == 1);
MATCH(true, sectionDesc->IsContiguous());
// Test section B = A(0:2:1,0:2:1) is not contiguous.
lb[0] = 0;
lb[1] = 0;
ub[0] = 2;
ub[1] = 2;
strides[0] = 1;
strides[1] = 1;
retCode = CFI_section(section, dv, lb, ub, strides);
sectionDesc->Dump();
MATCH(true, retCode == CFI_SUCCESS);
MATCH(true, CFI_is_contiguous(section) == 0);
MATCH(false, sectionDesc->IsContiguous());
// Test section B = A(0:3:2,0:3:1) is not contiguous.
lb[0] = 0;
lb[1] = 0;
ub[0] = 3;
ub[1] = 3;
strides[0] = 2;
strides[1] = 1;
retCode = CFI_section(section, dv, lb, ub, strides);
MATCH(true, retCode == CFI_SUCCESS);
MATCH(true, CFI_is_contiguous(section) == 0);
MATCH(false, sectionDesc->IsContiguous());
// Test section B = A(0:3:1,0:3:2) is not contiguous.
lb[0] = 0;
lb[1] = 0;
ub[0] = 3;
ub[1] = 3;
strides[0] = 1;
strides[1] = 2;
retCode = CFI_section(section, dv, lb, ub, strides);
MATCH(true, retCode == CFI_SUCCESS);
MATCH(true, CFI_is_contiguous(section) == 0);
MATCH(false, sectionDesc->IsContiguous());
}
int main() {
TestCdescMacroForAllRanksSmallerThan<CFI_MAX_RANK>();
run_CFI_establish_tests();
run_CFI_address_tests();
run_CFI_allocate_tests();
// TODO: test CFI_deallocate
// TODO: test CFI_is_contiguous
run_CFI_is_contiguous_tests();
run_CFI_section_tests();
run_CFI_select_part_tests();
run_CFI_setpointer_tests();