[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