Skip to content

Commit 38e1b63

Browse files
committed
[flang] Better IS_CONTIGUOUS folding for substrings
At present, the compiler doesn't analyze substring references for contiguity. But there are cases where substrings can be known to be contiguous (scalar base, empty substring, or complete substring) or can be known to be discontiguous, and references to the intrinsic function IS_CONTIGUOUS in those cases may appear in constant expressions. Fixes #115675.
1 parent fef4c8a commit 38e1b63

File tree

6 files changed

+70
-10
lines changed

6 files changed

+70
-10
lines changed

flang/lib/Evaluate/check-expression.cpp

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -908,7 +908,54 @@ class IsContiguousHelper
908908
Result operator()(const ComplexPart &x) const {
909909
return x.complex().Rank() == 0;
910910
}
911-
Result operator()(const Substring &) const { return std::nullopt; }
911+
Result operator()(const Substring &x) const {
912+
if (x.Rank() == 0) {
913+
return true; // scalar substring always contiguous
914+
}
915+
// Substrings with rank must have DataRefs as their parents
916+
const DataRef &parentDataRef{DEREF(x.GetParentIf<DataRef>())};
917+
std::optional<std::int64_t> len;
918+
if (auto lenExpr{parentDataRef.LEN()}) {
919+
len = ToInt64(Fold(context_, std::move(*lenExpr)));
920+
if (len) {
921+
if (*len <= 0) {
922+
return true; // empty substrings
923+
} else if (*len == 1) {
924+
// Substrings can't be incomplete; is base array contiguous?
925+
return (*this)(parentDataRef);
926+
}
927+
}
928+
}
929+
auto upperExpr{x.upper()};
930+
std::optional<std::int64_t> upper;
931+
bool upperIsLen{false};
932+
if (upperExpr) {
933+
upper = ToInt64(Fold(context_, std::move(*upperExpr)));
934+
if (upper) {
935+
if (*upper < 1) {
936+
return true; // substring(n:0) empty
937+
}
938+
upperIsLen = len && *upper >= *len;
939+
}
940+
} else {
941+
upperIsLen = true; // substring(n:)
942+
}
943+
if (auto lower{ToInt64(Fold(context_, x.lower()))}) {
944+
if (*lower == 1 && upperIsLen) {
945+
// known complete substring; is base contiguous?
946+
return (*this)(parentDataRef);
947+
} else if (upper) {
948+
if (*upper < *lower) {
949+
return true; // empty substring(3:2)
950+
} else if (*lower > 1) {
951+
return false; // known incomplete substring
952+
} else if (len && *upper < *len) {
953+
return false; // known incomplete substring
954+
}
955+
}
956+
}
957+
return std::nullopt; // contiguity not known
958+
}
912959

913960
Result operator()(const ProcedureRef &x) const {
914961
if (auto chars{characteristics::Procedure::Characterize(

flang/test/Evaluate/folding09.f90

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ module m
55
real, target :: hosted(2)
66
integer, parameter :: cst(2,2) = reshape([1, 2, 3, 4], shape(cst))
77
integer, parameter :: empty_cst(2,0) = reshape([1], shape(empty_cst))
8-
integer :: n
8+
integer :: n, m
99
logical, parameter :: test_param1 = is_contiguous(cst(:,1))
1010
logical, parameter :: test_param2 = is_contiguous(cst(1,:))
1111
logical, parameter :: test_param3 = is_contiguous(cst(:,n))
@@ -21,6 +21,9 @@ subroutine test(arr1, arr2, arr3, mat, alloc)
2121
real, intent(in), contiguous :: arr3(:)
2222
real, allocatable :: alloc(:)
2323
real :: scalar
24+
character(5) charr(5)
25+
character(1) char1(5)
26+
character(0) char0(5)
2427
integer(kind=merge(1,-1, is_contiguous(0))) t01
2528
integer(kind=merge(1,-1, is_contiguous(scalar))) t02
2629
integer(kind=merge(1,-1, is_contiguous(scalar + scalar))) t03
@@ -35,6 +38,16 @@ subroutine test(arr1, arr2, arr3, mat, alloc)
3538
integer(kind=merge(1,-1, .not. is_contiguous(arr3(1:10:2)))) t12
3639
integer(kind=merge(1,-1, is_contiguous(f()))) t13
3740
integer(kind=merge(1,-1, is_contiguous(alloc))) t14
41+
integer(kind=merge(1,-1, is_contiguous(charr(:)(:)))) t15
42+
integer(kind=merge(1,-1, is_contiguous(charr(1)(2:3)))) t16
43+
integer(kind=merge(1,-1, is_contiguous(charr(:)(1:)))) t17
44+
integer(kind=merge(1,-1, is_contiguous(charr(:)(3:2)))) t18
45+
integer(kind=merge(1,-1, is_contiguous(charr(:)(1:5)))) t19
46+
integer(kind=merge(1,-1, .not. is_contiguous(charr(:)(1:4)))) t20
47+
integer(kind=merge(1,-1, is_contiguous(char1(:)(n:m)))) t21
48+
integer(kind=merge(1,-1, .not. is_contiguous(char1(1:5:2)(n:m)))) t22
49+
integer(kind=merge(1,-1, is_contiguous(char0(:)(n:m)))) t23
50+
integer(kind=merge(1,-1, is_contiguous(char0(1:5:2)(n:m)))) t24
3851
associate (x => arr2)
3952
block
4053
integer(kind=merge(1,-1,is_contiguous(x))) n

flang/test/Lower/HLFIR/maxloc.f90

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -341,8 +341,8 @@ end subroutine test_unknown_char_len_result
341341
! CHECK-DAG: %[[C1_7:.*]] = arith.constant 1 : index
342342
! CHECK-DAG: %[[C3_8:.*]] = arith.constant 3 : index
343343
! CHECK-DAG: %[[C3_9:.*]] = arith.constant 3 : index
344-
! CHECK-DAG: %[[ARRAY_BOX:.*]] = hlfir.designate %[[ARRAY]]#0 (%[[C1]]:%[[C3_0]]:%[[C1_3]], %[[C1]]:%[[C3_1]]:%[[C1_5]]) substr %[[C1_7]], %[[C3_8]] shape %[[SHAPE]] typeparams %[[C3_9]]
345-
! CHECK: %[[EXPR:.*]] = hlfir.maxloc %[[ARRAY_BOX]] {fastmath = #arith.fastmath<contract>} : (!fir.box<!fir.array<3x3x!fir.char<1,3>>>) -> !hlfir.expr<2xi32>
344+
! CHECK-DAG: %[[ARRAY_REF:.*]] = hlfir.designate %[[ARRAY]]#0 (%[[C1]]:%[[C3_0]]:%[[C1_3]], %[[C1]]:%[[C3_1]]:%[[C1_5]]) substr %[[C1_7]], %[[C3_8]] shape %[[SHAPE]] typeparams %[[C3_9]] : (!fir.ref<!fir.array<3x3x!fir.char<1,3>>>, index, index, index, index, index, index, index, index, !fir.shape<2>, index) -> !fir.ref<!fir.array<3x3x!fir.char<1,3>>>
345+
! CHECK: %[[EXPR:.*]] = hlfir.maxloc %[[ARRAY_REF]] {fastmath = #arith.fastmath<contract>} : (!fir.ref<!fir.array<3x3x!fir.char<1,3>>>) -> !hlfir.expr<2xi32>
346346
! CHECK-NEXT: hlfir.assign %[[EXPR]] to %[[RES]]#0 : !hlfir.expr<2xi32>, !fir.ref<!fir.array<2xi32>>
347347
! CHECK-NEXT: hlfir.destroy %[[EXPR]]
348348
! CHECK-NEXT: return

flang/test/Lower/HLFIR/maxval.f90

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -254,8 +254,8 @@ end subroutine test_unknown_char_len_result
254254
! CHECK-DAG: %[[C1_7:.*]] = arith.constant 1 : index
255255
! CHECK-DAG: %[[C3_8:.*]] = arith.constant 3 : index
256256
! CHECK-DAG: %[[C3_9:.*]] = arith.constant 3 : index
257-
! CHECK-DAG: %[[ARRAY_BOX:.*]] = hlfir.designate %[[ARRAY]]#0 (%[[C1]]:%[[C3_0]]:%[[C1_3]], %[[C1]]:%[[C3_1]]:%[[C1_5]]) substr %[[C1_7]], %[[C3_8]] shape %[[SHAPE]] typeparams %[[C3_9]]
258-
! CHECK: %[[EXPR:.*]] = hlfir.maxval %[[ARRAY_BOX]] {fastmath = #arith.fastmath<contract>} : (!fir.box<!fir.array<3x3x!fir.char<1,3>>>) -> !hlfir.expr<!fir.char<1,3>>
257+
! CHECK-DAG: %[[ARRAY_REF:.*]] = hlfir.designate %[[ARRAY]]#0 (%[[C1]]:%[[C3_0]]:%[[C1_3]], %[[C1]]:%[[C3_1]]:%[[C1_5]]) substr %[[C1_7]], %[[C3_8]] shape %[[SHAPE]] typeparams %[[C3_9]] : (!fir.ref<!fir.array<3x3x!fir.char<1,3>>>, index, index, index, index, index, index, index, index, !fir.shape<2>, index) -> !fir.ref<!fir.array<3x3x!fir.char<1,3>>>
258+
! CHECK: %[[EXPR:.*]] = hlfir.maxval %[[ARRAY_REF]] {fastmath = #arith.fastmath<contract>} : (!fir.ref<!fir.array<3x3x!fir.char<1,3>>>) -> !hlfir.expr<!fir.char<1,3>>
259259
! CHECK-NEXT: hlfir.assign %[[EXPR]] to %[[RES]]#0 : !hlfir.expr<!fir.char<1,3>>, !fir.ref<!fir.char<1,3>>
260260
! CHECK-NEXT: hlfir.destroy %[[EXPR]]
261261
! CHECK-NEXT: return

flang/test/Lower/HLFIR/minloc.f90

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -341,8 +341,8 @@ end subroutine test_unknown_char_len_result
341341
! CHECK-DAG: %[[C1_7:.*]] = arith.constant 1 : index
342342
! CHECK-DAG: %[[C3_8:.*]] = arith.constant 3 : index
343343
! CHECK-DAG: %[[C3_9:.*]] = arith.constant 3 : index
344-
! CHECK-DAG: %[[ARRAY_BOX:.*]] = hlfir.designate %[[ARRAY]]#0 (%[[C1]]:%[[C3_0]]:%[[C1_3]], %[[C1]]:%[[C3_1]]:%[[C1_5]]) substr %[[C1_7]], %[[C3_8]] shape %[[SHAPE]] typeparams %[[C3_9]]
345-
! CHECK: %[[EXPR:.*]] = hlfir.minloc %[[ARRAY_BOX]] {fastmath = #arith.fastmath<contract>} : (!fir.box<!fir.array<3x3x!fir.char<1,3>>>) -> !hlfir.expr<2xi32>
344+
! CHECK-DAG: %[[ARRAY_REF:.*]] = hlfir.designate %[[ARRAY]]#0 (%[[C1]]:%[[C3_0]]:%[[C1_3]], %[[C1]]:%[[C3_1]]:%[[C1_5]]) substr %[[C1_7]], %[[C3_8]] shape %[[SHAPE]] typeparams %[[C3_9]] : (!fir.ref<!fir.array<3x3x!fir.char<1,3>>>, index, index, index, index, index, index, index, index, !fir.shape<2>, index) -> !fir.ref<!fir.array<3x3x!fir.char<1,3>>>
345+
! CHECK: %[[EXPR:.*]] = hlfir.minloc %[[ARRAY_REF]] {fastmath = #arith.fastmath<contract>} : (!fir.ref<!fir.array<3x3x!fir.char<1,3>>>) -> !hlfir.expr<2xi32>
346346
! CHECK-NEXT: hlfir.assign %[[EXPR]] to %[[RES]]#0 : !hlfir.expr<2xi32>, !fir.ref<!fir.array<2xi32>>
347347
! CHECK-NEXT: hlfir.destroy %[[EXPR]]
348348
! CHECK-NEXT: return

flang/test/Lower/HLFIR/minval.f90

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -254,8 +254,8 @@ end subroutine test_unknown_char_len_result
254254
! CHECK-DAG: %[[C1_7:.*]] = arith.constant 1 : index
255255
! CHECK-DAG: %[[C3_8:.*]] = arith.constant 3 : index
256256
! CHECK-DAG: %[[C3_9:.*]] = arith.constant 3 : index
257-
! CHECK-DAG: %[[ARRAY_BOX:.*]] = hlfir.designate %[[ARRAY]]#0 (%[[C1]]:%[[C3_0]]:%[[C1_3]], %[[C1]]:%[[C3_1]]:%[[C1_5]]) substr %[[C1_7]], %[[C3_8]] shape %[[SHAPE]] typeparams %[[C3_9]]
258-
! CHECK: %[[EXPR:.*]] = hlfir.minval %[[ARRAY_BOX]] {fastmath = #arith.fastmath<contract>} : (!fir.box<!fir.array<3x3x!fir.char<1,3>>>) -> !hlfir.expr<!fir.char<1,3>>
257+
! CHECK-DAG: %[[ARRAY_REF:.*]] = hlfir.designate %[[ARRAY]]#0 (%[[C1]]:%[[C3_0]]:%[[C1_3]], %[[C1]]:%[[C3_1]]:%[[C1_5]]) substr %[[C1_7]], %[[C3_8]] shape %[[SHAPE]] typeparams %[[C3_9]] : (!fir.ref<!fir.array<3x3x!fir.char<1,3>>>, index, index, index, index, index, index, index, index, !fir.shape<2>, index) -> !fir.ref<!fir.array<3x3x!fir.char<1,3>>>
258+
! CHECK: %[[EXPR:.*]] = hlfir.minval %[[ARRAY_REF]] {fastmath = #arith.fastmath<contract>} : (!fir.ref<!fir.array<3x3x!fir.char<1,3>>>) -> !hlfir.expr<!fir.char<1,3>>
259259
! CHECK-NEXT: hlfir.assign %[[EXPR]] to %[[RES]]#0 : !hlfir.expr<!fir.char<1,3>>, !fir.ref<!fir.char<1,3>>
260260
! CHECK-NEXT: hlfir.destroy %[[EXPR]]
261261
! CHECK-NEXT: return

0 commit comments

Comments
 (0)