Skip to content

Commit 4490f2d

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 4490f2d

File tree

6 files changed

+48
-9
lines changed

6 files changed

+48
-9
lines changed

flang/lib/Evaluate/check-expression.cpp

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -908,7 +908,39 @@ 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+
auto base{x.GetBaseObject()};
913+
if (x.Rank() == 0) {
914+
return true; // scalar substring always contiguous
915+
}
916+
Result result{(*this)(base)};
917+
if (!result || *result) {
918+
if (auto lower{ToInt64(Fold(context_, x.lower()))}) {
919+
auto upperExpr{x.upper()};
920+
auto lenExpr{base.LEN()};
921+
if (!upperExpr) {
922+
upperExpr = lenExpr;
923+
}
924+
if (!upperExpr) {
925+
return std::nullopt; // could be empty substrings
926+
} else if (auto upper{ToInt64(Fold(context_, std::move(*upperExpr)))}) {
927+
if (*upper < *lower) {
928+
return true; // empty substrings: vacuously contiguous
929+
} else if (*lower > 1) {
930+
return false; // lower > 1
931+
} else if (lenExpr) {
932+
if (auto lenVal{ToInt64(Fold(context_, std::move(*lenExpr)))};
933+
lenVal && *lenVal != *upper) {
934+
return false; // upper < length
935+
}
936+
}
937+
}
938+
} else {
939+
return std::nullopt; // lower bound not known
940+
}
941+
}
942+
return result;
943+
}
912944

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

flang/test/Evaluate/folding09.f90

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ 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)
2425
integer(kind=merge(1,-1, is_contiguous(0))) t01
2526
integer(kind=merge(1,-1, is_contiguous(scalar))) t02
2627
integer(kind=merge(1,-1, is_contiguous(scalar + scalar))) t03
@@ -35,6 +36,12 @@ subroutine test(arr1, arr2, arr3, mat, alloc)
3536
integer(kind=merge(1,-1, .not. is_contiguous(arr3(1:10:2)))) t12
3637
integer(kind=merge(1,-1, is_contiguous(f()))) t13
3738
integer(kind=merge(1,-1, is_contiguous(alloc))) t14
39+
integer(kind=merge(1,-1, is_contiguous(charr(:)(:)))) t15
40+
integer(kind=merge(1,-1, is_contiguous(charr(1)(2:3)))) t16
41+
integer(kind=merge(1,-1, is_contiguous(charr(:)(1:)))) t17
42+
integer(kind=merge(1,-1, is_contiguous(charr(:)(3:2)))) t18
43+
integer(kind=merge(1,-1, is_contiguous(charr(:)(1:5)))) t19
44+
integer(kind=merge(1,-1, .not. is_contiguous(charr(:)(1:4)))) t20
3845
associate (x => arr2)
3946
block
4047
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)