[flang-commits] [flang] 449823e - [flang] Fixed IsContiguous check for slices of parameter arrays.

Slava Zakharin via flang-commits flang-commits at lists.llvm.org
Wed Aug 2 10:45:08 PDT 2023


Author: Slava Zakharin
Date: 2023-08-02T10:45:00-07:00
New Revision: 449823e202b421a50bd5ee64b6a4ffbee766fae5

URL: https://github.com/llvm/llvm-project/commit/449823e202b421a50bd5ee64b6a4ffbee766fae5
DIFF: https://github.com/llvm/llvm-project/commit/449823e202b421a50bd5ee64b6a4ffbee766fae5.diff

LOG: [flang] Fixed IsContiguous check for slices of parameter arrays.

A section of a parameter array may be non-contiguous,
so the current !IsVariable(expr) check is too optimistic
to claim contiguity.

This patch fixes issues with incorrect hlfir.designate op generated
during lowering: the lowering queries IsContiguous to decide whether
to use fir.box<fir.array> or plain fir.ref<fir.array> to represent
the designator result.

Reviewed By: klausler

Differential Revision: https://reviews.llvm.org/D156494

Added: 
    flang/test/Lower/HLFIR/designators-parameter-array-slice.f90

Modified: 
    flang/lib/Evaluate/check-expression.cpp
    flang/test/Evaluate/folding09.f90

Removed: 
    


################################################################################
diff  --git a/flang/lib/Evaluate/check-expression.cpp b/flang/lib/Evaluate/check-expression.cpp
index 206e9578a28b8f..cfc67bf70dd0d6 100644
--- a/flang/lib/Evaluate/check-expression.cpp
+++ b/flang/lib/Evaluate/check-expression.cpp
@@ -756,10 +756,16 @@ class IsContiguousHelper
   explicit IsContiguousHelper(FoldingContext &c) : Base{*this}, context_{c} {}
   using Base::operator();
 
+  template <typename T> Result operator()(const Constant<T> &) const {
+    return true;
+  }
+  Result operator()(const StaticDataObject &) const { return true; }
   Result operator()(const semantics::Symbol &symbol) const {
     const auto &ultimate{symbol.GetUltimate()};
     if (ultimate.attrs().test(semantics::Attr::CONTIGUOUS)) {
       return true;
+    } else if (!IsVariable(symbol)) {
+      return true;
     } else if (ultimate.Rank() == 0) {
       // Extension: accept scalars as a degenerate case of
       // simple contiguity to allow their use in contexts like
@@ -853,24 +859,44 @@ class IsContiguousHelper
     // Detect any provably empty dimension in this array section, which would
     // render the whole section empty and therefore vacuously contiguous.
     std::optional<bool> result;
-    for (auto j{subscript.size()}; j-- > 0;) {
+    bool mayBeEmpty{false};
+    auto dims{subscript.size()};
+    std::vector<bool> knownPartialSlice(dims, false);
+    for (auto j{dims}; j-- > 0;) {
+      std::optional<ConstantSubscript> dimLbound;
+      std::optional<ConstantSubscript> dimUbound;
+      std::optional<ConstantSubscript> dimExtent;
+      if (baseLbounds && j < baseLbounds->size()) {
+        if (const auto &lb{baseLbounds->at(j)}) {
+          dimLbound = ToInt64(Fold(context_, Expr<SubscriptInteger>{*lb}));
+        }
+      }
+      if (baseUbounds && j < baseUbounds->size()) {
+        if (const auto &ub{baseUbounds->at(j)}) {
+          dimUbound = ToInt64(Fold(context_, Expr<SubscriptInteger>{*ub}));
+        }
+      }
+      if (dimLbound && dimUbound) {
+        if (*dimLbound <= *dimUbound) {
+          dimExtent = *dimUbound - *dimLbound + 1;
+        } else {
+          // This is an empty dimension.
+          result = true;
+          dimExtent = 0;
+        }
+      }
+
       if (const auto *triplet{std::get_if<Triplet>(&subscript[j].u)}) {
         ++rank;
         if (auto stride{ToInt64(triplet->stride())}) {
           const Expr<SubscriptInteger> *lowerBound{triplet->GetLower()};
-          if (!lowerBound && baseLbounds && j < baseLbounds->size()) {
-            lowerBound = common::GetPtrFromOptional(baseLbounds->at(j));
-          }
           const Expr<SubscriptInteger> *upperBound{triplet->GetUpper()};
-          if (!upperBound && baseUbounds && j < baseUbounds->size()) {
-            upperBound = common::GetPtrFromOptional(baseUbounds->at(j));
-          }
           std::optional<ConstantSubscript> lowerVal{lowerBound
                   ? ToInt64(Fold(context_, Expr<SubscriptInteger>{*lowerBound}))
-                  : std::nullopt};
+                  : dimLbound};
           std::optional<ConstantSubscript> upperVal{upperBound
                   ? ToInt64(Fold(context_, Expr<SubscriptInteger>{*upperBound}))
-                  : std::nullopt};
+                  : dimUbound};
           if (lowerVal && upperVal) {
             if (*lowerVal < *upperVal) {
               if (*stride < 0) {
@@ -886,14 +912,26 @@ class IsContiguousHelper
                   *lowerVal + *stride >= *upperVal) {
                 result = false; // discontiguous if not empty
               }
+            } else {
+              mayBeEmpty = true;
             }
+          } else {
+            mayBeEmpty = true;
           }
+        } else {
+          mayBeEmpty = true;
         }
       } else if (subscript[j].Rank() > 0) {
         ++rank;
         if (!result) {
           result = false; // vector subscript
         }
+        mayBeEmpty = true;
+      } else {
+        // Scalar subscript.
+        if (dimExtent && *dimExtent > 1) {
+          knownPartialSlice[j] = true;
+        }
       }
     }
     if (rank == 0) {
@@ -920,7 +958,13 @@ class IsContiguousHelper
         }
         ++rank;
       } else if (anyTriplet) {
-        return std::nullopt;
+        // If the section cannot be empty, and this dimension's
+        // scalar subscript is known not to cover the whole
+        // dimension, then the array section is provably
+        // discontiguous.
+        return (mayBeEmpty || !knownPartialSlice[j])
+            ? std::nullopt
+            : std::make_optional(false);
       }
     }
     return true; // simply contiguous
@@ -931,11 +975,7 @@ class IsContiguousHelper
 
 template <typename A>
 std::optional<bool> IsContiguous(const A &x, FoldingContext &context) {
-  if (IsVariable(x)) {
-    return IsContiguousHelper{context}(x);
-  } else {
-    return true; // not a variable
-  }
+  return IsContiguousHelper{context}(x);
 }
 
 template std::optional<bool> IsContiguous(

diff  --git a/flang/test/Evaluate/folding09.f90 b/flang/test/Evaluate/folding09.f90
index 055cdaf1619159..e796ed3d5169ba 100644
--- a/flang/test/Evaluate/folding09.f90
+++ b/flang/test/Evaluate/folding09.f90
@@ -3,6 +3,14 @@
 
 module m
   real, target :: hosted(2)
+  integer, parameter :: cst(2,2) = reshape([1, 2, 3, 4], shape(cst))
+  integer, parameter :: empty_cst(2,0) = reshape([1], shape(empty_cst))
+  integer :: n
+  logical, parameter :: test_param1 = is_contiguous(cst(:,1))
+  logical, parameter :: test_param2 = is_contiguous(cst(1,:))
+  logical, parameter :: test_param3 = is_contiguous(cst(:,n))
+  logical, parameter :: test_param4 = .not. is_contiguous(cst(n,:))
+  logical, parameter :: test_param5 = is_contiguous(empty_cst(n,-1:n:2))
  contains
   function f()
     real, pointer, contiguous :: f(:)

diff  --git a/flang/test/Lower/HLFIR/designators-parameter-array-slice.f90 b/flang/test/Lower/HLFIR/designators-parameter-array-slice.f90
new file mode 100644
index 00000000000000..3bf19923453352
--- /dev/null
+++ b/flang/test/Lower/HLFIR/designators-parameter-array-slice.f90
@@ -0,0 +1,11 @@
+! Test non-contiguous slice of parameter array.
+! RUN: bbc -emit-hlfir --polymorphic-type -o - %s | FileCheck %s
+subroutine test2(i)
+  integer, parameter :: a(*,*) = reshape( [ 1,2,3,4 ], [ 2,2 ])
+  integer :: x(2)
+  x = a(i,:)
+end subroutine test2
+! Check that the result type of the designate operation
+! is a box (as opposed to !fir.ref<!fir.array<>>) that is able
+! to represent non-contiguous array section:
+! CHECK: hlfir.designate {{.*}} shape {{.*}} : (!fir.ref<!fir.array<2x2xi32>>, i64, index, index, index, !fir.shape<1>) -> !fir.box<!fir.array<2xi32>>


        


More information about the flang-commits mailing list