[flang] Don't duplicate impure function call for UBOUND() (#153648)
Because the per-dimension information in a descriptor holds an extent and a lower bound, but not an upper bound, the calculation of the upper bound sometimes requires that the extent and lower bound be extracted from a descriptor and added together, minus 1. This shouldn't be attempted when the NamedEntity of the descriptor is something that shouldn't be duplicated and used twice; specifically, it shouldn't apply to NamedEntities containing references to impure functions as parts of subscript expressions. Fixes https://github.com/llvm/llvm-project/issues/153031.
This commit is contained in:
parent
48232594a0
commit
2cf982c0f5
@ -1144,15 +1144,14 @@ std::optional<std::string> FindImpureCall(
|
|||||||
std::optional<std::string> FindImpureCall(
|
std::optional<std::string> FindImpureCall(
|
||||||
FoldingContext &, const ProcedureRef &);
|
FoldingContext &, const ProcedureRef &);
|
||||||
|
|
||||||
// Predicate: is a scalar expression suitable for naive scalar expansion
|
// Predicate: does an expression contain anything that would prevent it from
|
||||||
// in the flattening of an array expression?
|
// being duplicated so that two instances of it then appear in the same
|
||||||
// TODO: capture such scalar expansions in temporaries, flatten everything
|
// expression?
|
||||||
class UnexpandabilityFindingVisitor
|
class UnsafeToCopyVisitor : public AnyTraverse<UnsafeToCopyVisitor> {
|
||||||
: public AnyTraverse<UnexpandabilityFindingVisitor> {
|
|
||||||
public:
|
public:
|
||||||
using Base = AnyTraverse<UnexpandabilityFindingVisitor>;
|
using Base = AnyTraverse<UnsafeToCopyVisitor>;
|
||||||
using Base::operator();
|
using Base::operator();
|
||||||
explicit UnexpandabilityFindingVisitor(bool admitPureCall)
|
explicit UnsafeToCopyVisitor(bool admitPureCall)
|
||||||
: Base{*this}, admitPureCall_{admitPureCall} {}
|
: Base{*this}, admitPureCall_{admitPureCall} {}
|
||||||
template <typename T> bool operator()(const FunctionRef<T> &procRef) {
|
template <typename T> bool operator()(const FunctionRef<T> &procRef) {
|
||||||
return !admitPureCall_ || !procRef.proc().IsPure();
|
return !admitPureCall_ || !procRef.proc().IsPure();
|
||||||
@ -1163,14 +1162,22 @@ private:
|
|||||||
bool admitPureCall_{false};
|
bool admitPureCall_{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename A>
|
||||||
|
bool IsSafelyCopyable(const A &x, bool admitPureCall = false) {
|
||||||
|
return !UnsafeToCopyVisitor{admitPureCall}(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Predicate: is a scalar expression suitable for naive scalar expansion
|
||||||
|
// in the flattening of an array expression?
|
||||||
|
// TODO: capture such scalar expansions in temporaries, flatten everything
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool IsExpandableScalar(const Expr<T> &expr, FoldingContext &context,
|
bool IsExpandableScalar(const Expr<T> &expr, FoldingContext &context,
|
||||||
const Shape &shape, bool admitPureCall = false) {
|
const Shape &shape, bool admitPureCall = false) {
|
||||||
if (UnexpandabilityFindingVisitor{admitPureCall}(expr)) {
|
if (IsSafelyCopyable(expr, admitPureCall)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
auto extents{AsConstantExtents(context, shape)};
|
auto extents{AsConstantExtents(context, shape)};
|
||||||
return extents && !HasNegativeExtent(*extents) && GetSize(*extents) == 1;
|
return extents && !HasNegativeExtent(*extents) && GetSize(*extents) == 1;
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -623,7 +623,7 @@ MaybeExtentExpr GetRawUpperBound(
|
|||||||
} else if (semantics::IsAssumedSizeArray(symbol) &&
|
} else if (semantics::IsAssumedSizeArray(symbol) &&
|
||||||
dimension + 1 == symbol.Rank()) {
|
dimension + 1 == symbol.Rank()) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
} else {
|
} else if (IsSafelyCopyable(base, /*admitPureCall=*/true)) {
|
||||||
return ComputeUpperBound(
|
return ComputeUpperBound(
|
||||||
GetRawLowerBound(base, dimension), GetExtent(base, dimension));
|
GetRawLowerBound(base, dimension), GetExtent(base, dimension));
|
||||||
}
|
}
|
||||||
@ -678,11 +678,13 @@ static MaybeExtentExpr GetUBOUND(FoldingContext *context,
|
|||||||
} else if (semantics::IsAssumedSizeArray(symbol) &&
|
} else if (semantics::IsAssumedSizeArray(symbol) &&
|
||||||
dimension + 1 == symbol.Rank()) {
|
dimension + 1 == symbol.Rank()) {
|
||||||
return std::nullopt; // UBOUND() folding replaces with -1
|
return std::nullopt; // UBOUND() folding replaces with -1
|
||||||
} else if (auto lb{GetLBOUND(base, dimension, invariantOnly)}) {
|
} else if (IsSafelyCopyable(base, /*admitPureCall=*/true)) {
|
||||||
|
if (auto lb{GetLBOUND(base, dimension, invariantOnly)}) {
|
||||||
return ComputeUpperBound(
|
return ComputeUpperBound(
|
||||||
std::move(*lb), GetExtent(base, dimension, invariantOnly));
|
std::move(*lb), GetExtent(base, dimension, invariantOnly));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else if (const auto *assoc{
|
} else if (const auto *assoc{
|
||||||
symbol.detailsIf<semantics::AssocEntityDetails>()}) {
|
symbol.detailsIf<semantics::AssocEntityDetails>()}) {
|
||||||
if (assoc->IsAssumedSize() || assoc->IsAssumedRank()) {
|
if (assoc->IsAssumedSize() || assoc->IsAssumedRank()) {
|
||||||
|
18
flang/test/Evaluate/bug153031.f90
Normal file
18
flang/test/Evaluate/bug153031.f90
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
! RUN: %flang_fc1 -fdebug-unparse %s 2>&1 | FileCheck %s
|
||||||
|
! Ensure that UBOUND() calculation from LBOUND()+SIZE() isn't applied to
|
||||||
|
! variables containing references to impure functions.
|
||||||
|
type t
|
||||||
|
real, allocatable :: a(:)
|
||||||
|
end type
|
||||||
|
interface
|
||||||
|
pure integer function pure(n)
|
||||||
|
integer, intent(in) :: n
|
||||||
|
end
|
||||||
|
end interface
|
||||||
|
type(t) :: x(10)
|
||||||
|
allocate(x(1)%a(2))
|
||||||
|
!CHECK: PRINT *, ubound(x(int(impure(1_4),kind=8))%a,dim=1_4)
|
||||||
|
print *, ubound(x(impure(1))%a, dim=1)
|
||||||
|
!CHECK: PRINT *, int(size(x(int(pure(1_4),kind=8))%a,dim=1,kind=8)+lbound(x(int(pure(1_4),kind=8))%a,dim=1,kind=8)-1_8,kind=4)
|
||||||
|
print *, ubound(x(pure(1))%a, dim=1)
|
||||||
|
end
|
Loading…
x
Reference in New Issue
Block a user