Skip to content

[flang] Better IS_CONTIGUOUS folding for substrings #115970

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 14, 2024

Conversation

klausler
Copy link
Contributor

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.

@klausler klausler requested a review from jeanPerier November 13, 2024 00:44
@llvmbot llvmbot added flang Flang issues not falling into any other category flang:fir-hlfir flang:semantics labels Nov 13, 2024
@llvmbot
Copy link
Member

llvmbot commented Nov 13, 2024

@llvm/pr-subscribers-flang-fir-hlfir

Author: Peter Klausler (klausler)

Changes

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.


Full diff: https://github.com/llvm/llvm-project/pull/115970.diff

6 Files Affected:

  • (modified) flang/lib/Evaluate/check-expression.cpp (+33-1)
  • (modified) flang/test/Evaluate/folding09.f90 (+7)
  • (modified) flang/test/Lower/HLFIR/maxloc.f90 (+2-2)
  • (modified) flang/test/Lower/HLFIR/maxval.f90 (+2-2)
  • (modified) flang/test/Lower/HLFIR/minloc.f90 (+2-2)
  • (modified) flang/test/Lower/HLFIR/minval.f90 (+2-2)
diff --git a/flang/lib/Evaluate/check-expression.cpp b/flang/lib/Evaluate/check-expression.cpp
index 38794a2d8aacc7..efc08763aa9ad6 100644
--- a/flang/lib/Evaluate/check-expression.cpp
+++ b/flang/lib/Evaluate/check-expression.cpp
@@ -908,7 +908,39 @@ class IsContiguousHelper
   Result operator()(const ComplexPart &x) const {
     return x.complex().Rank() == 0;
   }
-  Result operator()(const Substring &) const { return std::nullopt; }
+  Result operator()(const Substring &x) const {
+    auto base{x.GetBaseObject()};
+    if (x.Rank() == 0) {
+      return true; // scalar substring always contiguous
+    }
+    Result result{(*this)(base)};
+    if (!result || *result) {
+      if (auto lower{ToInt64(Fold(context_, x.lower()))}) {
+        auto upperExpr{x.upper()};
+        auto lenExpr{base.LEN()};
+        if (!upperExpr) {
+          upperExpr = lenExpr;
+        }
+        if (!upperExpr) {
+          return std::nullopt; // could be empty substrings
+        } else if (auto upper{ToInt64(Fold(context_, std::move(*upperExpr)))}) {
+          if (*upper < *lower) {
+            return true; // empty substrings: vacuously contiguous
+          } else if (*lower > 1) {
+            return false; // lower > 1
+          } else if (lenExpr) {
+            if (auto lenVal{ToInt64(Fold(context_, std::move(*lenExpr)))};
+                lenVal && *lenVal != *upper) {
+              return false; // upper < length
+            }
+          }
+        }
+      } else {
+        return std::nullopt; // lower bound not known
+      }
+    }
+    return result;
+  }
 
   Result operator()(const ProcedureRef &x) const {
     if (auto chars{characteristics::Procedure::Characterize(
diff --git a/flang/test/Evaluate/folding09.f90 b/flang/test/Evaluate/folding09.f90
index 863b5e873a1e5b..b9c00710a086ca 100644
--- a/flang/test/Evaluate/folding09.f90
+++ b/flang/test/Evaluate/folding09.f90
@@ -21,6 +21,7 @@ subroutine test(arr1, arr2, arr3, mat, alloc)
     real, intent(in), contiguous :: arr3(:)
     real, allocatable :: alloc(:)
     real :: scalar
+    character(5) charr(5)
     integer(kind=merge(1,-1,       is_contiguous(0)))               t01
     integer(kind=merge(1,-1,       is_contiguous(scalar)))          t02
     integer(kind=merge(1,-1,       is_contiguous(scalar + scalar))) t03
@@ -35,6 +36,12 @@ subroutine test(arr1, arr2, arr3, mat, alloc)
     integer(kind=merge(1,-1, .not. is_contiguous(arr3(1:10:2))))    t12
     integer(kind=merge(1,-1,       is_contiguous(f())))             t13
     integer(kind=merge(1,-1,       is_contiguous(alloc)))           t14
+    integer(kind=merge(1,-1,       is_contiguous(charr(:)(:))))     t15
+    integer(kind=merge(1,-1,       is_contiguous(charr(1)(2:3))))   t16
+    integer(kind=merge(1,-1,       is_contiguous(charr(:)(1:))))    t17
+    integer(kind=merge(1,-1,       is_contiguous(charr(:)(3:2))))   t18
+    integer(kind=merge(1,-1,       is_contiguous(charr(:)(1:5))))   t19
+    integer(kind=merge(1,-1, .not. is_contiguous(charr(:)(1:4))))   t20
     associate (x => arr2)
       block
         integer(kind=merge(1,-1,is_contiguous(x))) n
diff --git a/flang/test/Lower/HLFIR/maxloc.f90 b/flang/test/Lower/HLFIR/maxloc.f90
index 166a1b9db1724e..539affad2d7df1 100644
--- a/flang/test/Lower/HLFIR/maxloc.f90
+++ b/flang/test/Lower/HLFIR/maxloc.f90
@@ -341,8 +341,8 @@ end subroutine test_unknown_char_len_result
 ! CHECK-DAG:       %[[C1_7:.*]] = arith.constant 1 : index
 ! CHECK-DAG:       %[[C3_8:.*]] = arith.constant 3 : index
 ! CHECK-DAG:       %[[C3_9:.*]] = arith.constant 3 : index
-! 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]]
-! CHECK:           %[[EXPR:.*]] = hlfir.maxloc %[[ARRAY_BOX]] {fastmath = #arith.fastmath<contract>} : (!fir.box<!fir.array<3x3x!fir.char<1,3>>>) -> !hlfir.expr<2xi32>
+! 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>>>
+! CHECK:           %[[EXPR:.*]] = hlfir.maxloc %[[ARRAY_REF]] {fastmath = #arith.fastmath<contract>} : (!fir.ref<!fir.array<3x3x!fir.char<1,3>>>) -> !hlfir.expr<2xi32>
 ! CHECK-NEXT:      hlfir.assign %[[EXPR]] to %[[RES]]#0 : !hlfir.expr<2xi32>, !fir.ref<!fir.array<2xi32>>
 ! CHECK-NEXT:      hlfir.destroy %[[EXPR]]
 ! CHECK-NEXT:      return
diff --git a/flang/test/Lower/HLFIR/maxval.f90 b/flang/test/Lower/HLFIR/maxval.f90
index 5adad286a77d28..32e1a80417a27b 100644
--- a/flang/test/Lower/HLFIR/maxval.f90
+++ b/flang/test/Lower/HLFIR/maxval.f90
@@ -254,8 +254,8 @@ end subroutine test_unknown_char_len_result
 ! CHECK-DAG:       %[[C1_7:.*]] = arith.constant 1 : index
 ! CHECK-DAG:       %[[C3_8:.*]] = arith.constant 3 : index
 ! CHECK-DAG:       %[[C3_9:.*]] = arith.constant 3 : index
-! 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]]
-! 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>>
+! 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>>>
+! 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>>
 ! CHECK-NEXT:      hlfir.assign %[[EXPR]] to %[[RES]]#0 : !hlfir.expr<!fir.char<1,3>>, !fir.ref<!fir.char<1,3>>
 ! CHECK-NEXT:      hlfir.destroy %[[EXPR]]
 ! CHECK-NEXT:      return
diff --git a/flang/test/Lower/HLFIR/minloc.f90 b/flang/test/Lower/HLFIR/minloc.f90
index f835cf54b2a73e..ce149ffcfb54fd 100644
--- a/flang/test/Lower/HLFIR/minloc.f90
+++ b/flang/test/Lower/HLFIR/minloc.f90
@@ -341,8 +341,8 @@ end subroutine test_unknown_char_len_result
 ! CHECK-DAG:       %[[C1_7:.*]] = arith.constant 1 : index
 ! CHECK-DAG:       %[[C3_8:.*]] = arith.constant 3 : index
 ! CHECK-DAG:       %[[C3_9:.*]] = arith.constant 3 : index
-! 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]]
-! CHECK:           %[[EXPR:.*]] = hlfir.minloc %[[ARRAY_BOX]] {fastmath = #arith.fastmath<contract>} : (!fir.box<!fir.array<3x3x!fir.char<1,3>>>) -> !hlfir.expr<2xi32>
+! 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>>>
+! CHECK:           %[[EXPR:.*]] = hlfir.minloc %[[ARRAY_REF]] {fastmath = #arith.fastmath<contract>} : (!fir.ref<!fir.array<3x3x!fir.char<1,3>>>) -> !hlfir.expr<2xi32>
 ! CHECK-NEXT:      hlfir.assign %[[EXPR]] to %[[RES]]#0 : !hlfir.expr<2xi32>, !fir.ref<!fir.array<2xi32>>
 ! CHECK-NEXT:      hlfir.destroy %[[EXPR]]
 ! CHECK-NEXT:      return
diff --git a/flang/test/Lower/HLFIR/minval.f90 b/flang/test/Lower/HLFIR/minval.f90
index 01b0ce77e2d30e..2ac9aba850b6f4 100644
--- a/flang/test/Lower/HLFIR/minval.f90
+++ b/flang/test/Lower/HLFIR/minval.f90
@@ -254,8 +254,8 @@ end subroutine test_unknown_char_len_result
 ! CHECK-DAG:       %[[C1_7:.*]] = arith.constant 1 : index
 ! CHECK-DAG:       %[[C3_8:.*]] = arith.constant 3 : index
 ! CHECK-DAG:       %[[C3_9:.*]] = arith.constant 3 : index
-! 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]]
-! 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>>
+! 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>>>
+! 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>>
 ! CHECK-NEXT:      hlfir.assign %[[EXPR]] to %[[RES]]#0 : !hlfir.expr<!fir.char<1,3>>, !fir.ref<!fir.char<1,3>>
 ! CHECK-NEXT:      hlfir.destroy %[[EXPR]]
 ! CHECK-NEXT:      return

@llvmbot
Copy link
Member

llvmbot commented Nov 13, 2024

@llvm/pr-subscribers-flang-semantics

Author: Peter Klausler (klausler)

Changes

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.


Full diff: https://github.com/llvm/llvm-project/pull/115970.diff

6 Files Affected:

  • (modified) flang/lib/Evaluate/check-expression.cpp (+33-1)
  • (modified) flang/test/Evaluate/folding09.f90 (+7)
  • (modified) flang/test/Lower/HLFIR/maxloc.f90 (+2-2)
  • (modified) flang/test/Lower/HLFIR/maxval.f90 (+2-2)
  • (modified) flang/test/Lower/HLFIR/minloc.f90 (+2-2)
  • (modified) flang/test/Lower/HLFIR/minval.f90 (+2-2)
diff --git a/flang/lib/Evaluate/check-expression.cpp b/flang/lib/Evaluate/check-expression.cpp
index 38794a2d8aacc7..efc08763aa9ad6 100644
--- a/flang/lib/Evaluate/check-expression.cpp
+++ b/flang/lib/Evaluate/check-expression.cpp
@@ -908,7 +908,39 @@ class IsContiguousHelper
   Result operator()(const ComplexPart &x) const {
     return x.complex().Rank() == 0;
   }
-  Result operator()(const Substring &) const { return std::nullopt; }
+  Result operator()(const Substring &x) const {
+    auto base{x.GetBaseObject()};
+    if (x.Rank() == 0) {
+      return true; // scalar substring always contiguous
+    }
+    Result result{(*this)(base)};
+    if (!result || *result) {
+      if (auto lower{ToInt64(Fold(context_, x.lower()))}) {
+        auto upperExpr{x.upper()};
+        auto lenExpr{base.LEN()};
+        if (!upperExpr) {
+          upperExpr = lenExpr;
+        }
+        if (!upperExpr) {
+          return std::nullopt; // could be empty substrings
+        } else if (auto upper{ToInt64(Fold(context_, std::move(*upperExpr)))}) {
+          if (*upper < *lower) {
+            return true; // empty substrings: vacuously contiguous
+          } else if (*lower > 1) {
+            return false; // lower > 1
+          } else if (lenExpr) {
+            if (auto lenVal{ToInt64(Fold(context_, std::move(*lenExpr)))};
+                lenVal && *lenVal != *upper) {
+              return false; // upper < length
+            }
+          }
+        }
+      } else {
+        return std::nullopt; // lower bound not known
+      }
+    }
+    return result;
+  }
 
   Result operator()(const ProcedureRef &x) const {
     if (auto chars{characteristics::Procedure::Characterize(
diff --git a/flang/test/Evaluate/folding09.f90 b/flang/test/Evaluate/folding09.f90
index 863b5e873a1e5b..b9c00710a086ca 100644
--- a/flang/test/Evaluate/folding09.f90
+++ b/flang/test/Evaluate/folding09.f90
@@ -21,6 +21,7 @@ subroutine test(arr1, arr2, arr3, mat, alloc)
     real, intent(in), contiguous :: arr3(:)
     real, allocatable :: alloc(:)
     real :: scalar
+    character(5) charr(5)
     integer(kind=merge(1,-1,       is_contiguous(0)))               t01
     integer(kind=merge(1,-1,       is_contiguous(scalar)))          t02
     integer(kind=merge(1,-1,       is_contiguous(scalar + scalar))) t03
@@ -35,6 +36,12 @@ subroutine test(arr1, arr2, arr3, mat, alloc)
     integer(kind=merge(1,-1, .not. is_contiguous(arr3(1:10:2))))    t12
     integer(kind=merge(1,-1,       is_contiguous(f())))             t13
     integer(kind=merge(1,-1,       is_contiguous(alloc)))           t14
+    integer(kind=merge(1,-1,       is_contiguous(charr(:)(:))))     t15
+    integer(kind=merge(1,-1,       is_contiguous(charr(1)(2:3))))   t16
+    integer(kind=merge(1,-1,       is_contiguous(charr(:)(1:))))    t17
+    integer(kind=merge(1,-1,       is_contiguous(charr(:)(3:2))))   t18
+    integer(kind=merge(1,-1,       is_contiguous(charr(:)(1:5))))   t19
+    integer(kind=merge(1,-1, .not. is_contiguous(charr(:)(1:4))))   t20
     associate (x => arr2)
       block
         integer(kind=merge(1,-1,is_contiguous(x))) n
diff --git a/flang/test/Lower/HLFIR/maxloc.f90 b/flang/test/Lower/HLFIR/maxloc.f90
index 166a1b9db1724e..539affad2d7df1 100644
--- a/flang/test/Lower/HLFIR/maxloc.f90
+++ b/flang/test/Lower/HLFIR/maxloc.f90
@@ -341,8 +341,8 @@ end subroutine test_unknown_char_len_result
 ! CHECK-DAG:       %[[C1_7:.*]] = arith.constant 1 : index
 ! CHECK-DAG:       %[[C3_8:.*]] = arith.constant 3 : index
 ! CHECK-DAG:       %[[C3_9:.*]] = arith.constant 3 : index
-! 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]]
-! CHECK:           %[[EXPR:.*]] = hlfir.maxloc %[[ARRAY_BOX]] {fastmath = #arith.fastmath<contract>} : (!fir.box<!fir.array<3x3x!fir.char<1,3>>>) -> !hlfir.expr<2xi32>
+! 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>>>
+! CHECK:           %[[EXPR:.*]] = hlfir.maxloc %[[ARRAY_REF]] {fastmath = #arith.fastmath<contract>} : (!fir.ref<!fir.array<3x3x!fir.char<1,3>>>) -> !hlfir.expr<2xi32>
 ! CHECK-NEXT:      hlfir.assign %[[EXPR]] to %[[RES]]#0 : !hlfir.expr<2xi32>, !fir.ref<!fir.array<2xi32>>
 ! CHECK-NEXT:      hlfir.destroy %[[EXPR]]
 ! CHECK-NEXT:      return
diff --git a/flang/test/Lower/HLFIR/maxval.f90 b/flang/test/Lower/HLFIR/maxval.f90
index 5adad286a77d28..32e1a80417a27b 100644
--- a/flang/test/Lower/HLFIR/maxval.f90
+++ b/flang/test/Lower/HLFIR/maxval.f90
@@ -254,8 +254,8 @@ end subroutine test_unknown_char_len_result
 ! CHECK-DAG:       %[[C1_7:.*]] = arith.constant 1 : index
 ! CHECK-DAG:       %[[C3_8:.*]] = arith.constant 3 : index
 ! CHECK-DAG:       %[[C3_9:.*]] = arith.constant 3 : index
-! 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]]
-! 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>>
+! 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>>>
+! 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>>
 ! CHECK-NEXT:      hlfir.assign %[[EXPR]] to %[[RES]]#0 : !hlfir.expr<!fir.char<1,3>>, !fir.ref<!fir.char<1,3>>
 ! CHECK-NEXT:      hlfir.destroy %[[EXPR]]
 ! CHECK-NEXT:      return
diff --git a/flang/test/Lower/HLFIR/minloc.f90 b/flang/test/Lower/HLFIR/minloc.f90
index f835cf54b2a73e..ce149ffcfb54fd 100644
--- a/flang/test/Lower/HLFIR/minloc.f90
+++ b/flang/test/Lower/HLFIR/minloc.f90
@@ -341,8 +341,8 @@ end subroutine test_unknown_char_len_result
 ! CHECK-DAG:       %[[C1_7:.*]] = arith.constant 1 : index
 ! CHECK-DAG:       %[[C3_8:.*]] = arith.constant 3 : index
 ! CHECK-DAG:       %[[C3_9:.*]] = arith.constant 3 : index
-! 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]]
-! CHECK:           %[[EXPR:.*]] = hlfir.minloc %[[ARRAY_BOX]] {fastmath = #arith.fastmath<contract>} : (!fir.box<!fir.array<3x3x!fir.char<1,3>>>) -> !hlfir.expr<2xi32>
+! 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>>>
+! CHECK:           %[[EXPR:.*]] = hlfir.minloc %[[ARRAY_REF]] {fastmath = #arith.fastmath<contract>} : (!fir.ref<!fir.array<3x3x!fir.char<1,3>>>) -> !hlfir.expr<2xi32>
 ! CHECK-NEXT:      hlfir.assign %[[EXPR]] to %[[RES]]#0 : !hlfir.expr<2xi32>, !fir.ref<!fir.array<2xi32>>
 ! CHECK-NEXT:      hlfir.destroy %[[EXPR]]
 ! CHECK-NEXT:      return
diff --git a/flang/test/Lower/HLFIR/minval.f90 b/flang/test/Lower/HLFIR/minval.f90
index 01b0ce77e2d30e..2ac9aba850b6f4 100644
--- a/flang/test/Lower/HLFIR/minval.f90
+++ b/flang/test/Lower/HLFIR/minval.f90
@@ -254,8 +254,8 @@ end subroutine test_unknown_char_len_result
 ! CHECK-DAG:       %[[C1_7:.*]] = arith.constant 1 : index
 ! CHECK-DAG:       %[[C3_8:.*]] = arith.constant 3 : index
 ! CHECK-DAG:       %[[C3_9:.*]] = arith.constant 3 : index
-! 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]]
-! 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>>
+! 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>>>
+! 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>>
 ! CHECK-NEXT:      hlfir.assign %[[EXPR]] to %[[RES]]#0 : !hlfir.expr<!fir.char<1,3>>, !fir.ref<!fir.char<1,3>>
 ! CHECK-NEXT:      hlfir.destroy %[[EXPR]]
 ! CHECK-NEXT:      return

@klausler
Copy link
Contributor Author

klausler commented Nov 13, 2024 via email

upperIsLen = len && *upper >= *len;
}
} else {
upperIsLen = true; // substring(n:)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that some previous folding step may already have expended the absent upper into the length, blurring the information here for cases where the length is not a compile time constant:

subroutine test(charr)
  character(*) :: charr(5)
  print *, is_contiguous(charr(:)(1:))
end subroutine

Folds to is_contiguous(charr(::1_8)(1_8:int(charr%len,kind=8))) while it could be folded to true.

However, folding this may not be required by the standard, so this may be fine.

I do not find the standard very clear regarding the appearance of IS_CONTIGUOUS in constant expressions. As I understand it, it falls into the 10.1.12 (6) case since IS_CONTIGUOUS is an inquiry function. I am not sure how to read "a variable whose properties inquired about are not assumed, deferred, or defined by an expression that is not a constant expression" when the "property" is the contiguity.

Copy link
Contributor

@jeanPerier jeanPerier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question about one case, LGTM otherwise. Thanks for the update.

Copy link

github-actions bot commented Nov 14, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

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 llvm#115675.
@klausler klausler merged commit 17daa84 into llvm:main Nov 14, 2024
8 checks passed
@klausler klausler deleted the bug115675 branch November 14, 2024 22:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
flang:fir-hlfir flang:semantics flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Flang] Compilation error when is_contiguous intrinsic procedure is used to define a variable
3 participants