diff --git a/flang/include/flang/Evaluate/constant.h b/flang/include/flang/Evaluate/constant.h --- a/flang/include/flang/Evaluate/constant.h +++ b/flang/include/flang/Evaluate/constant.h @@ -64,6 +64,7 @@ ~ConstantBounds(); const ConstantSubscripts &shape() const { return shape_; } const ConstantSubscripts &lbounds() const { return lbounds_; } + ConstantSubscripts ComputeUbounds(std::optional dim) const; void set_lbounds(ConstantSubscripts &&); void SetLowerBoundsToOne(); int Rank() const { return GetRank(shape_); } diff --git a/flang/lib/Evaluate/constant.cpp b/flang/lib/Evaluate/constant.cpp --- a/flang/lib/Evaluate/constant.cpp +++ b/flang/lib/Evaluate/constant.cpp @@ -32,6 +32,20 @@ } } +ConstantSubscripts ConstantBounds::ComputeUbounds( + std::optional dim) const { + if (dim) { + CHECK(*dim < Rank()); + return {lbounds_[*dim] + shape_[*dim] - 1}; + } else { + ConstantSubscripts ubounds(Rank()); + for (int i{0}; i < Rank(); ++i) { + ubounds[i] = lbounds_[i] + shape_[i] - 1; + } + return ubounds; + } +} + void ConstantBounds::SetLowerBoundsToOne() { for (auto &n : lbounds_) { n = 1; diff --git a/flang/lib/Evaluate/fold-integer.cpp b/flang/lib/Evaluate/fold-integer.cpp --- a/flang/lib/Evaluate/fold-integer.cpp +++ b/flang/lib/Evaluate/fold-integer.cpp @@ -29,44 +29,66 @@ } } -// Class to retrieve the constant lower bound of an expression which is an +// Class to retrieve the constant bound of an expression which is an // array that devolves to a type of Constant -class GetConstantArrayLboundHelper { +class GetConstantArrayBoundHelper { public: - GetConstantArrayLboundHelper(std::optional dim) - : dim_{dim} {} + template + static Expr GetLbound( + const Expr &array, std::optional dim) { + return PackageConstantBounds( + GetConstantArrayBoundHelper(dim, /*getLbound=*/true).Get(array), + dim.has_value()); + } + + template + static Expr GetUbound( + const Expr &array, std::optional dim) { + return PackageConstantBounds( + GetConstantArrayBoundHelper(dim, /*getLbound=*/false).Get(array), + dim.has_value()); + } + +private: + GetConstantArrayBoundHelper( + std::optional dim, bool getLbound) + : dim_{dim}, getLbound_{getLbound} {} - template ConstantSubscripts GetLbound(const T &) { + template ConstantSubscripts Get(const T &) { // The method is needed for template expansion, but we should never get // here in practice. CHECK(false); return {0}; } - template ConstantSubscripts GetLbound(const Constant &x) { - // Return the lower bound - if (dim_) { - return {x.lbounds().at(*dim_)}; + template ConstantSubscripts Get(const Constant &x) { + if (getLbound_) { + // Return the lower bound + if (dim_) { + return {x.lbounds().at(*dim_)}; + } else { + return x.lbounds(); + } } else { - return x.lbounds(); + return x.ComputeUbounds(dim_); } } - template ConstantSubscripts GetLbound(const Parentheses &x) { + template ConstantSubscripts Get(const Parentheses &x) { // LBOUND for (x) is [1, ..., 1] cause of temp variable inside // parentheses (lower bound is omitted, the default value is 1). return ConstantSubscripts(x.Rank(), ConstantSubscript{1}); } - template ConstantSubscripts GetLbound(const Expr &x) { + template ConstantSubscripts Get(const Expr &x) { // recurse through Expr'a until we hit a constant - return common::visit([&](const auto &inner) { return GetLbound(inner); }, + return common::visit([&](const auto &inner) { return Get(inner); }, // [&](const auto &) { return 0; }, x.u); } -private: - std::optional dim_; + const std::optional dim_; + const bool getLbound_; }; template @@ -112,9 +134,7 @@ } } if (IsActuallyConstant(*array)) { - const ConstantSubscripts bounds{ - GetConstantArrayLboundHelper{dim}.GetLbound(*array)}; - return PackageConstantBounds(std::move(bounds), dim.has_value()); + return GetConstantArrayBoundHelper::GetLbound(*array, dim); } if (lowerBoundsAreOne) { ConstantSubscripts ones(rank, ConstantSubscript{1}); @@ -178,6 +198,9 @@ takeBoundsFromShape = symbol.Rank() == 0; // UBOUND(array%component) } } + if (IsActuallyConstant(*array)) { + return GetConstantArrayBoundHelper::GetUbound(*array, dim); + } if (takeBoundsFromShape) { if (auto shape{GetContextFreeShape(context, *array)}) { if (dim) { diff --git a/flang/test/Evaluate/folding08.f90 b/flang/test/Evaluate/folding08.f90 --- a/flang/test/Evaluate/folding08.f90 +++ b/flang/test/Evaluate/folding08.f90 @@ -77,23 +77,33 @@ end block end associate end subroutine - subroutine test3_lbound_parameter - ! Test lbound with constant arrays + subroutine test3_bound_parameter + ! Test [ul]bound with parameter arrays integer, parameter :: a1(1) = 0 integer, parameter :: lba1(*) = lbound(a1) logical, parameter :: test_lba1 = all(lba1 == [1]) + integer, parameter :: uba1(*) = ubound(a1) + logical, parameter :: test_uba1 = all(lba1 == [1]) integer, parameter :: a2(0:1) = 0 integer, parameter :: lba2(*) = lbound(a2) logical, parameter :: test_lba2 = all(lba2 == [0]) + integer, parameter :: uba2(*) = ubound(a2) + logical, parameter :: test_uba2 = all(uba2 == [1]) integer, parameter :: a3(-10:-5,1,4:6) = 0 integer, parameter :: lba3(*) = lbound(a3) logical, parameter :: test_lba3 = all(lba3 == [-10, 1, 4]) + integer, parameter :: uba3(*) = ubound(a3) + logical, parameter :: test_uba3 = all(uba3 == [-5, 1, 6]) + ! Exercise with DIM= logical, parameter :: test_lba3_dim = lbound(a3, 1) == -10 .and. & lbound(a3, 2) == 1 .and. & lbound(a3, 3) == 4 + logical, parameter :: test_uba3_dim = ubound(a3, 1) == -5 .and. & + ubound(a3, 2) == 1 .and. & + ubound(a3, 3) == 6 end subroutine subroutine test4_lbound_parentheses ! Test lbound with (x) expressions