[flang-commits] [flang] 9489699 - [flang] Fold IS_CONTIGUOUS() to .FALSE. when it is known to be
Peter Klausler via flang-commits
flang-commits at lists.llvm.org
Fri Sep 23 14:16:41 PDT 2022
Author: Peter Klausler
Date: 2022-09-23T14:16:26-07:00
New Revision: 94896994386d2a6a9e7bc310de83ee1491f194ef
URL: https://github.com/llvm/llvm-project/commit/94896994386d2a6a9e7bc310de83ee1491f194ef
DIFF: https://github.com/llvm/llvm-project/commit/94896994386d2a6a9e7bc310de83ee1491f194ef.diff
LOG: [flang] Fold IS_CONTIGUOUS() to .FALSE. when it is known to be
At present, IS_CONTIGUOUS() can only either fold to .TRUE. or
remain unknown. The underlying analysis, however, is capable
of returning a tri-state result (true, false, or unknown).
Extend and expose it to folding so that IS_CONTIGUOUS() can
fold to .FALSE. as well as to .TRUE. when contiguity is
known.
Differential Revision: https://reviews.llvm.org/D134466
Added:
Modified:
flang/include/flang/Evaluate/check-expression.h
flang/include/flang/Evaluate/variable.h
flang/lib/Evaluate/check-expression.cpp
flang/lib/Evaluate/fold-logical.cpp
flang/lib/Evaluate/variable.cpp
flang/test/Semantics/assign03.f90
Removed:
################################################################################
diff --git a/flang/include/flang/Evaluate/check-expression.h b/flang/include/flang/Evaluate/check-expression.h
index 810a8c9c7f7d..31c8adacd5f3 100644
--- a/flang/include/flang/Evaluate/check-expression.h
+++ b/flang/include/flang/Evaluate/check-expression.h
@@ -95,10 +95,15 @@ extern template void CheckSpecificationExpr(
const std::optional<Expr<SubscriptInteger>> &x, const semantics::Scope &,
FoldingContext &);
-// Simple contiguity (9.5.4)
-template <typename A> bool IsSimplyContiguous(const A &, FoldingContext &);
-extern template bool IsSimplyContiguous(
+// Contiguity & "simple contiguity" (9.5.4)
+template <typename A>
+std::optional<bool> IsContiguous(const A &, FoldingContext &);
+extern template std::optional<bool> IsContiguous(
const Expr<SomeType> &, FoldingContext &);
+template <typename A>
+bool IsSimplyContiguous(const A &x, FoldingContext &context) {
+ return IsContiguous(x, context).value_or(false);
+}
template <typename A> bool IsErrorExpr(const A &);
extern template bool IsErrorExpr(const Expr<SomeType> &);
diff --git a/flang/include/flang/Evaluate/variable.h b/flang/include/flang/Evaluate/variable.h
index dac51edf2f42..b353050b781b 100644
--- a/flang/include/flang/Evaluate/variable.h
+++ b/flang/include/flang/Evaluate/variable.h
@@ -174,7 +174,7 @@ class Triplet {
Triplet &set_stride(Expr<SubscriptInteger> &&);
bool operator==(const Triplet &) const;
- bool IsStrideOne() const;
+ std::optional<bool> IsStrideOne() const;
llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
private:
diff --git a/flang/lib/Evaluate/check-expression.cpp b/flang/lib/Evaluate/check-expression.cpp
index 814785c79365..4d5fd0ba9fab 100644
--- a/flang/lib/Evaluate/check-expression.cpp
+++ b/flang/lib/Evaluate/check-expression.cpp
@@ -690,14 +690,13 @@ template void CheckSpecificationExpr(
const std::optional<Expr<SubscriptInteger>> &, const semantics::Scope &,
FoldingContext &);
-// IsSimplyContiguous() -- 9.5.4
-class IsSimplyContiguousHelper
- : public AnyTraverse<IsSimplyContiguousHelper, std::optional<bool>> {
+// IsContiguous() -- 9.5.4
+class IsContiguousHelper
+ : public AnyTraverse<IsContiguousHelper, std::optional<bool>> {
public:
using Result = std::optional<bool>; // tri-state
- using Base = AnyTraverse<IsSimplyContiguousHelper, Result>;
- explicit IsSimplyContiguousHelper(FoldingContext &c)
- : Base{*this}, context_{c} {}
+ using Base = AnyTraverse<IsContiguousHelper, Result>;
+ explicit IsContiguousHelper(FoldingContext &c) : Base{*this}, context_{c} {}
using Base::operator();
Result operator()(const semantics::Symbol &symbol) const {
@@ -711,43 +710,48 @@ class IsSimplyContiguousHelper
return true;
} else if (semantics::IsPointer(ultimate) ||
semantics::IsAssumedShape(ultimate)) {
- return false;
+ return std::nullopt;
} else if (const auto *details{
ultimate.detailsIf<semantics::ObjectEntityDetails>()}) {
return !details->IsAssumedRank();
- } else if (auto assoc{Base::operator()(ultimate)}) {
- return assoc;
} else {
- return false;
+ return Base::operator()(ultimate);
}
}
Result operator()(const ArrayRef &x) const {
- const auto &symbol{x.GetLastSymbol()};
- if (!(*this)(symbol).has_value()) {
- return false;
- } else if (auto rank{CheckSubscripts(x.subscript())}) {
- if (x.Rank() == 0) {
- return true;
- } else if (*rank > 0) {
- // a(1)%b(:,:) is contiguous if an only if a(1)%b is contiguous.
- return (*this)(x.base());
- } else {
- // a(:)%b(1,1) is not contiguous.
- return false;
- }
+ if (x.Rank() == 0) {
+ return true; // scalars considered contiguous
+ }
+ int subscriptRank{0};
+ auto subscripts{CheckSubscripts(x.subscript(), subscriptRank)};
+ if (!subscripts.value_or(false)) {
+ return subscripts; // subscripts not known to be contiguous
+ } else if (subscriptRank > 0) {
+ // a(1)%b(:,:) is contiguous if and only if a(1)%b is contiguous.
+ return (*this)(x.base());
} else {
- return false;
+ // a(:)%b(1,1) is (probably) not contiguous.
+ return std::nullopt;
}
}
Result operator()(const CoarrayRef &x) const {
- return CheckSubscripts(x.subscript()).has_value();
+ int rank{0};
+ return CheckSubscripts(x.subscript(), rank).has_value();
}
Result operator()(const Component &x) const {
- return x.base().Rank() == 0 && (*this)(x.GetLastSymbol()).value_or(false);
+ if (x.base().Rank() == 0) {
+ return (*this)(x.GetLastSymbol());
+ } else {
+ // TODO could be true if base contiguous and this is only component, or
+ // if base has only one element?
+ return std::nullopt;
+ }
}
- Result operator()(const ComplexPart &) const { return false; }
- Result operator()(const Substring &) const { return false; }
+ Result operator()(const ComplexPart &x) const {
+ return x.complex().Rank() == 0;
+ }
+ Result operator()(const Substring &) const { return std::nullopt; }
Result operator()(const ProcedureRef &x) const {
if (auto chars{
@@ -760,23 +764,25 @@ class IsSimplyContiguousHelper
characteristics::FunctionResult::Attr::Contiguous);
}
}
- return false;
+ return std::nullopt;
}
+ Result operator()(const NullPointer &) const { return true; }
+
private:
- // If the subscripts can possibly be on a simply-contiguous array reference,
- // return the rank.
- static std::optional<int> CheckSubscripts(
- const std::vector<Subscript> &subscript) {
+ static std::optional<bool> CheckSubscripts(
+ const std::vector<Subscript> &subscript, int &rank) {
bool anyTriplet{false};
- int rank{0};
+ rank = 0;
for (auto j{subscript.size()}; j-- > 0;) {
if (const auto *triplet{std::get_if<Triplet>(&subscript[j].u)}) {
- if (!triplet->IsStrideOne()) {
- return std::nullopt;
+ auto isStride1{triplet->IsStrideOne()};
+ if (!isStride1.value_or(false)) {
+ return isStride1;
} else if (anyTriplet) {
if (triplet->lower() || triplet->upper()) {
- // all triplets before the last one must be just ":"
+ // all triplets before the last one must be just ":" for
+ // simple contiguity
return std::nullopt;
}
} else {
@@ -784,26 +790,26 @@ class IsSimplyContiguousHelper
}
++rank;
} else if (anyTriplet || subscript[j].Rank() > 0) {
- return std::nullopt;
+ return false;
}
}
- return rank;
+ return true;
}
FoldingContext &context_;
};
template <typename A>
-bool IsSimplyContiguous(const A &x, FoldingContext &context) {
+std::optional<bool> IsContiguous(const A &x, FoldingContext &context) {
if (IsVariable(x)) {
- auto known{IsSimplyContiguousHelper{context}(x)};
- return known && *known;
+ return IsContiguousHelper{context}(x);
} else {
return true; // not a variable
}
}
-template bool IsSimplyContiguous(const Expr<SomeType> &, FoldingContext &);
+template std::optional<bool> IsContiguous(
+ const Expr<SomeType> &, FoldingContext &);
// IsErrorExpr()
struct IsErrorExprHelper : public AnyTraverse<IsErrorExprHelper, bool> {
diff --git a/flang/lib/Evaluate/fold-logical.cpp b/flang/lib/Evaluate/fold-logical.cpp
index 052fe62bbd5d..8adf632c4c56 100644
--- a/flang/lib/Evaluate/fold-logical.cpp
+++ b/flang/lib/Evaluate/fold-logical.cpp
@@ -180,8 +180,8 @@ Expr<Type<TypeCategory::Logical, KIND>> FoldIntrinsicFunction(
} else if (name == "is_contiguous") {
if (args.at(0)) {
if (auto *expr{args[0]->UnwrapExpr()}) {
- if (IsSimplyContiguous(*expr, context)) {
- return Expr<T>{true};
+ if (auto contiguous{IsContiguous(*expr, context)}) {
+ return Expr<T>{*contiguous};
}
}
}
diff --git a/flang/lib/Evaluate/variable.cpp b/flang/lib/Evaluate/variable.cpp
index 2de0de668d85..6ddc495a3f2c 100644
--- a/flang/lib/Evaluate/variable.cpp
+++ b/flang/lib/Evaluate/variable.cpp
@@ -69,11 +69,11 @@ Triplet &Triplet::set_stride(Expr<SubscriptInteger> &&expr) {
return *this;
}
-bool Triplet::IsStrideOne() const {
+std::optional<bool> Triplet::IsStrideOne() const {
if (auto stride{ToInt64(stride_.value())}) {
return stride == 1;
} else {
- return false;
+ return std::nullopt;
}
}
diff --git a/flang/test/Semantics/assign03.f90 b/flang/test/Semantics/assign03.f90
index 46de668a706a..3e4868157721 100644
--- a/flang/test/Semantics/assign03.f90
+++ b/flang/test/Semantics/assign03.f90
@@ -269,10 +269,10 @@ subroutine s11
end
! Check is_contiguous, which is usually the same as when pointer bounds
- ! remapping is used. If it's not simply contiguous it's not constant so
- ! an error is reported.
+ ! remapping is used.
subroutine s12
integer, pointer :: p(:)
+ integer, pointer, contiguous :: pc(:)
type :: t
integer :: a(4, 4)
integer :: b
@@ -280,16 +280,20 @@ subroutine s12
type(t), target :: x
type(t), target :: y(10,10)
integer :: v(10)
- logical, parameter :: l1 = is_contiguous(x%a(:,:))
- logical, parameter :: l2 = is_contiguous(y(1,1)%a(1,1))
+ logical(kind=merge(1,-1,is_contiguous(x%a(:,:)))) :: l1 ! known true
+ logical(kind=merge(1,-1,is_contiguous(y(1,1)%a(1,1)))) :: l2 ! known true
!ERROR: Must be a constant value
- logical, parameter :: l3 = is_contiguous(y(:,1)%a(1,1))
+ logical(kind=merge(-1,-2,is_contiguous(y(:,1)%a(1,1)))) :: l3 ! unknown
!ERROR: Must be a constant value
- logical, parameter :: l4 = is_contiguous(x%a(:,v))
+ logical(kind=merge(-1,-2,is_contiguous(y(:,1)%a(1,1)))) :: l4 ! unknown
+ logical(kind=merge(-1,1,is_contiguous(x%a(:,v)))) :: l5 ! known false
!ERROR: Must be a constant value
- logical, parameter :: l5 = is_contiguous(y(v,1)%a(1,1))
+ logical(kind=merge(-1,-2,is_contiguous(y(v,1)%a(1,1)))) :: l6 ! unknown
!ERROR: Must be a constant value
- logical, parameter :: l6 = is_contiguous(p(:))
+ logical(kind=merge(-1,-2,is_contiguous(p(:)))) :: l7 ! unknown
+ logical(kind=merge(1,-1,is_contiguous(pc(:)))) :: l8 ! known true
+ logical(kind=merge(-1,1,is_contiguous(pc(1:10:2)))) :: l9 ! known false
+ logical(kind=merge(-1,1,is_contiguous(pc(10:1:-1)))) :: l10 ! known false
end
subroutine test3(b)
integer, intent(inout) :: b(..)
More information about the flang-commits
mailing list