Skip to content

Commit 7755cdf

Browse files
authored
[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 ....).
1 parent 9bcc094 commit 7755cdf

File tree

3 files changed

+111
-9
lines changed

3 files changed

+111
-9
lines changed

flang/include/flang/Runtime/descriptor.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -390,14 +390,16 @@ class Descriptor {
390390
if (leadingDimensions > raw_.rank) {
391391
leadingDimensions = raw_.rank;
392392
}
393+
bool stridesAreContiguous{true};
393394
for (int j{0}; j < leadingDimensions; ++j) {
394395
const Dimension &dim{GetDimension(j)};
395-
if (bytes != dim.ByteStride()) {
396-
return false;
397-
}
396+
stridesAreContiguous &= bytes == dim.ByteStride();
398397
bytes *= dim.Extent();
399398
}
400-
return true;
399+
// One and zero element arrays are contiguous even if the descriptor
400+
// byte strides are not perfect multiples.
401+
return stridesAreContiguous || bytes == 0 ||
402+
bytes == static_cast<SubscriptValue>(ElementBytes());
401403
}
402404

403405
// Establishes a pointer to a section or element.

flang/runtime/ISO_Fortran_binding.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -125,14 +125,19 @@ RT_API_ATTRS int CFI_establish(CFI_cdesc_t *descriptor, void *base_addr,
125125
}
126126

127127
RT_API_ATTRS int CFI_is_contiguous(const CFI_cdesc_t *descriptor) {
128+
bool stridesAreContiguous{true};
128129
CFI_index_t bytes = descriptor->elem_len;
129130
for (int j{0}; j < descriptor->rank; ++j) {
130-
if (bytes != descriptor->dim[j].sm) {
131-
return 0;
132-
}
131+
stridesAreContiguous &= bytes == descriptor->dim[j].sm;
133132
bytes *= descriptor->dim[j].extent;
134133
}
135-
return 1;
134+
// One and zero element arrays are contiguous even if the descriptor
135+
// byte strides are not perfect multiples.
136+
if (stridesAreContiguous || bytes == 0 ||
137+
bytes == static_cast<CFI_index_t>(descriptor->elem_len)) {
138+
return 1;
139+
}
140+
return 0;
136141
}
137142

138143
RT_API_ATTRS int CFI_section(CFI_cdesc_t *result, const CFI_cdesc_t *source,

flang/unittests/Evaluate/ISO-Fortran-binding.cpp

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -643,13 +643,108 @@ static void run_CFI_setpointer_tests() {
643643
}
644644
}
645645

646+
static void run_CFI_is_contiguous_tests() {
647+
// INTEGER :: A(0:3,0:3)
648+
constexpr CFI_rank_t rank{2};
649+
CFI_index_t extents[rank] = {4, 4};
650+
CFI_CDESC_T(rank) dv_storage;
651+
CFI_cdesc_t *dv{&dv_storage};
652+
Descriptor *dvDesc{reinterpret_cast<Descriptor *>(dv)};
653+
char base;
654+
void *base_addr{&base};
655+
int retCode{CFI_establish(dv, base_addr, CFI_attribute_other, CFI_type_int,
656+
/*elem_len=*/0, rank, extents)};
657+
MATCH(retCode == CFI_SUCCESS, true);
658+
659+
MATCH(true, CFI_is_contiguous(dv) == 1);
660+
MATCH(true, dvDesc->IsContiguous());
661+
662+
CFI_CDESC_T(rank) sectionDescriptorStorage;
663+
CFI_cdesc_t *section{&sectionDescriptorStorage};
664+
Descriptor *sectionDesc{reinterpret_cast<Descriptor *>(section)};
665+
retCode = CFI_establish(section, base_addr, CFI_attribute_other, CFI_type_int,
666+
/*elem_len=*/0, rank, extents);
667+
MATCH(retCode == CFI_SUCCESS, true);
668+
669+
// Test empty section B = A(0:3:2,0:3:-2) is contiguous.
670+
CFI_index_t lb[rank] = {0, 0};
671+
CFI_index_t ub[rank] = {3, 3};
672+
CFI_index_t strides[rank] = {2, -2};
673+
retCode = CFI_section(section, dv, lb, ub, strides);
674+
MATCH(true, retCode == CFI_SUCCESS);
675+
MATCH(true, CFI_is_contiguous(section) == 1);
676+
MATCH(true, sectionDesc->IsContiguous());
677+
678+
// Test 1 element section B = A(0:1:2,0:1:2) is contiguous.
679+
lb[0] = 0;
680+
lb[1] = 0;
681+
ub[0] = 1;
682+
ub[1] = 1;
683+
strides[0] = 2;
684+
strides[1] = 2;
685+
retCode = CFI_section(section, dv, lb, ub, strides);
686+
MATCH(true, retCode == CFI_SUCCESS);
687+
MATCH(true, CFI_is_contiguous(section) == 1);
688+
MATCH(true, sectionDesc->IsContiguous());
689+
690+
// Test section B = A(0:3:1,0:2:1) is contiguous.
691+
lb[0] = 0;
692+
lb[1] = 0;
693+
ub[0] = 3;
694+
ub[1] = 2;
695+
strides[0] = 1;
696+
strides[1] = 1;
697+
retCode = CFI_section(section, dv, lb, ub, strides);
698+
sectionDesc->Dump();
699+
MATCH(true, retCode == CFI_SUCCESS);
700+
MATCH(true, CFI_is_contiguous(section) == 1);
701+
MATCH(true, sectionDesc->IsContiguous());
702+
703+
// Test section B = A(0:2:1,0:2:1) is not contiguous.
704+
lb[0] = 0;
705+
lb[1] = 0;
706+
ub[0] = 2;
707+
ub[1] = 2;
708+
strides[0] = 1;
709+
strides[1] = 1;
710+
retCode = CFI_section(section, dv, lb, ub, strides);
711+
sectionDesc->Dump();
712+
MATCH(true, retCode == CFI_SUCCESS);
713+
MATCH(true, CFI_is_contiguous(section) == 0);
714+
MATCH(false, sectionDesc->IsContiguous());
715+
716+
// Test section B = A(0:3:2,0:3:1) is not contiguous.
717+
lb[0] = 0;
718+
lb[1] = 0;
719+
ub[0] = 3;
720+
ub[1] = 3;
721+
strides[0] = 2;
722+
strides[1] = 1;
723+
retCode = CFI_section(section, dv, lb, ub, strides);
724+
MATCH(true, retCode == CFI_SUCCESS);
725+
MATCH(true, CFI_is_contiguous(section) == 0);
726+
MATCH(false, sectionDesc->IsContiguous());
727+
728+
// Test section B = A(0:3:1,0:3:2) is not contiguous.
729+
lb[0] = 0;
730+
lb[1] = 0;
731+
ub[0] = 3;
732+
ub[1] = 3;
733+
strides[0] = 1;
734+
strides[1] = 2;
735+
retCode = CFI_section(section, dv, lb, ub, strides);
736+
MATCH(true, retCode == CFI_SUCCESS);
737+
MATCH(true, CFI_is_contiguous(section) == 0);
738+
MATCH(false, sectionDesc->IsContiguous());
739+
}
740+
646741
int main() {
647742
TestCdescMacroForAllRanksSmallerThan<CFI_MAX_RANK>();
648743
run_CFI_establish_tests();
649744
run_CFI_address_tests();
650745
run_CFI_allocate_tests();
651746
// TODO: test CFI_deallocate
652-
// TODO: test CFI_is_contiguous
747+
run_CFI_is_contiguous_tests();
653748
run_CFI_section_tests();
654749
run_CFI_select_part_tests();
655750
run_CFI_setpointer_tests();

0 commit comments

Comments
 (0)