Skip to content

Commit bef3e8e

Browse files
authored
[flang][runtime] Fix another IsContiguous edge case (#69199)
A recent PR addressed zero and one element edge cases but did not cover another case where the descriptors of arrays with more than two elements may have byte strides that are not perfect multiples, like when creating a descriptor for A(:, 1:1:2). In general, the byte stride in a dimension is only meaningful if that dimension has more than one element. Update IsContiguous and CFI_is_contiguous to reflect that.
1 parent 8e674e8 commit bef3e8e

File tree

3 files changed

+43
-8
lines changed

3 files changed

+43
-8
lines changed

flang/include/flang/Runtime/descriptor.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -393,13 +393,17 @@ class Descriptor {
393393
bool stridesAreContiguous{true};
394394
for (int j{0}; j < leadingDimensions; ++j) {
395395
const Dimension &dim{GetDimension(j)};
396-
stridesAreContiguous &= bytes == dim.ByteStride();
396+
stridesAreContiguous &= (bytes == dim.ByteStride()) | (dim.Extent() == 1);
397397
bytes *= dim.Extent();
398398
}
399399
// One and zero element arrays are contiguous even if the descriptor
400400
// byte strides are not perfect multiples.
401-
return stridesAreContiguous || bytes == 0 ||
402-
bytes == static_cast<SubscriptValue>(ElementBytes());
401+
// Arrays with more than 2 elements may also be contiguous even if a
402+
// byte stride in one dimension is not a perfect multiple, as long as
403+
// this is the last dimension, or if the dimension has one extent and
404+
// the following dimension have either one extents or contiguous byte
405+
// strides.
406+
return stridesAreContiguous || bytes == 0;
403407
}
404408

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

flang/runtime/ISO_Fortran_binding.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -125,16 +125,15 @@ 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+
// See Descriptor::IsContiguous for the rationale.
128129
bool stridesAreContiguous{true};
129130
CFI_index_t bytes = descriptor->elem_len;
130131
for (int j{0}; j < descriptor->rank; ++j) {
131-
stridesAreContiguous &= bytes == descriptor->dim[j].sm;
132+
stridesAreContiguous &=
133+
(bytes == descriptor->dim[j].sm) | (descriptor->dim[j].extent == 1);
132134
bytes *= descriptor->dim[j].extent;
133135
}
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)) {
136+
if (stridesAreContiguous || bytes == 0) {
138137
return 1;
139138
}
140139
return 0;

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

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -736,6 +736,38 @@ static void run_CFI_is_contiguous_tests() {
736736
MATCH(true, retCode == CFI_SUCCESS);
737737
MATCH(true, CFI_is_contiguous(section) == 0);
738738
MATCH(false, sectionDesc->IsContiguous());
739+
740+
// Test section B = A(0:3:1,0:0:2) is contiguous.
741+
lb[0] = 0;
742+
lb[1] = 0;
743+
ub[0] = 3;
744+
ub[1] = 0;
745+
strides[0] = 1;
746+
strides[1] = 2;
747+
retCode = CFI_section(section, dv, lb, ub, strides);
748+
MATCH(true, retCode == CFI_SUCCESS);
749+
MATCH(true, CFI_is_contiguous(section) == 1);
750+
MATCH(true, sectionDesc->IsContiguous());
751+
752+
// INTEGER :: C(0:0, 0:3)
753+
CFI_index_t c_extents[rank] = {1, 4};
754+
CFI_CDESC_T(rank) c_dv_storage;
755+
CFI_cdesc_t *cdv{&c_dv_storage};
756+
retCode = CFI_establish(cdv, base_addr, CFI_attribute_other, CFI_type_int,
757+
/*elem_len=*/0, rank, c_extents);
758+
MATCH(retCode == CFI_SUCCESS, true);
759+
760+
// Test section B = C(0:0:2, 0:3:1) is contiguous.
761+
lb[0] = 0;
762+
lb[1] = 0;
763+
ub[0] = 0;
764+
ub[1] = 3;
765+
strides[0] = 2;
766+
strides[1] = 1;
767+
retCode = CFI_section(section, cdv, lb, ub, strides);
768+
MATCH(true, retCode == CFI_SUCCESS);
769+
MATCH(true, CFI_is_contiguous(section) == 1);
770+
MATCH(true, sectionDesc->IsContiguous());
739771
}
740772

741773
int main() {

0 commit comments

Comments
 (0)