Skip to content

Commit 17daa84

Browse files
authored
[flang] Better IS_CONTIGUOUS folding for substrings (#115970)
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 d68332d commit 17daa84

File tree

6 files changed

+77
-11
lines changed

6 files changed

+77
-11
lines changed

flang/lib/Evaluate/check-expression.cpp

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -908,7 +908,58 @@ 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+
std::optional<std::int64_t> upper;
930+
bool upperIsLen{false};
931+
if (auto upperExpr{x.upper()}) {
932+
upper = ToInt64(Fold(context_, common::Clone(*upperExpr)));
933+
if (upper) {
934+
if (*upper < 1) {
935+
return true; // substring(n:0) empty
936+
}
937+
upperIsLen = len && *upper >= *len;
938+
} else if (const auto *inquiry{
939+
UnwrapConvertedExpr<DescriptorInquiry>(*upperExpr)};
940+
inquiry && inquiry->field() == DescriptorInquiry::Field::Len) {
941+
upperIsLen =
942+
&parentDataRef.GetLastSymbol() == &inquiry->base().GetLastSymbol();
943+
}
944+
} else {
945+
upperIsLen = true; // substring(n:)
946+
}
947+
if (auto lower{ToInt64(Fold(context_, x.lower()))}) {
948+
if (*lower == 1 && upperIsLen) {
949+
// known complete substring; is base contiguous?
950+
return (*this)(parentDataRef);
951+
} else if (upper) {
952+
if (*upper < *lower) {
953+
return true; // empty substring(3:2)
954+
} else if (*lower > 1) {
955+
return false; // known incomplete substring
956+
} else if (len && *upper < *len) {
957+
return false; // known incomplete substring
958+
}
959+
}
960+
}
961+
return std::nullopt; // contiguity not known
962+
}
912963

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

flang/test/Evaluate/folding09.f90

Lines changed: 17 additions & 2 deletions
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))
@@ -16,11 +16,15 @@ function f()
1616
real, pointer, contiguous :: f(:)
1717
f => hosted
1818
end function
19-
subroutine test(arr1, arr2, arr3, mat, alloc)
19+
subroutine test(arr1, arr2, arr3, mat, alloc, alch)
2020
real, intent(in) :: arr1(:), arr2(10), mat(10, 10)
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)
27+
character(*) alch(5)
2428
integer(kind=merge(1,-1, is_contiguous(0))) t01
2529
integer(kind=merge(1,-1, is_contiguous(scalar))) t02
2630
integer(kind=merge(1,-1, is_contiguous(scalar + scalar))) t03
@@ -35,6 +39,17 @@ subroutine test(arr1, arr2, arr3, mat, alloc)
3539
integer(kind=merge(1,-1, .not. is_contiguous(arr3(1:10:2)))) t12
3640
integer(kind=merge(1,-1, is_contiguous(f()))) t13
3741
integer(kind=merge(1,-1, is_contiguous(alloc))) t14
42+
integer(kind=merge(1,-1, is_contiguous(charr(:)(:)))) t15
43+
integer(kind=merge(1,-1, is_contiguous(charr(1)(2:3)))) t16
44+
integer(kind=merge(1,-1, is_contiguous(charr(:)(1:)))) t17
45+
integer(kind=merge(1,-1, is_contiguous(charr(:)(3:2)))) t18
46+
integer(kind=merge(1,-1, is_contiguous(charr(:)(1:5)))) t19
47+
integer(kind=merge(1,-1, .not. is_contiguous(charr(:)(1:4)))) t20
48+
integer(kind=merge(1,-1, is_contiguous(char1(:)(n:m)))) t21
49+
integer(kind=merge(1,-1, .not. is_contiguous(char1(1:5:2)(n:m)))) t22
50+
integer(kind=merge(1,-1, is_contiguous(char0(:)(n:m)))) t23
51+
integer(kind=merge(1,-1, is_contiguous(char0(1:5:2)(n:m)))) t24
52+
integer(kind=merge(1,-1, is_contiguous(alch(:)(:)))) t25
3853
associate (x => arr2)
3954
block
4055
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)