forked from OSchip/llvm-project
[flang] Resolve known problems in shape analysis
Original-commit: flang-compiler/f18@ed2e4842d3 Reviewed-on: https://github.com/flang-compiler/f18/pull/1061
This commit is contained in:
parent
771c21c19f
commit
f7432ca7a6
|
@ -53,6 +53,8 @@ std::optional<ConstantSubscripts> AsConstantExtents(
|
||||||
|
|
||||||
inline int GetRank(const Shape &s) { return static_cast<int>(s.size()); }
|
inline int GetRank(const Shape &s) { return static_cast<int>(s.size()); }
|
||||||
|
|
||||||
|
template<typename A> std::optional<Shape> GetShape(FoldingContext &, const A &);
|
||||||
|
|
||||||
// The dimension argument to these inquiries is zero-based,
|
// The dimension argument to these inquiries is zero-based,
|
||||||
// unlike the DIM= arguments to many intrinsics.
|
// unlike the DIM= arguments to many intrinsics.
|
||||||
ExtentExpr GetLowerBound(FoldingContext &, const NamedEntity &, int dimension);
|
ExtentExpr GetLowerBound(FoldingContext &, const NamedEntity &, int dimension);
|
||||||
|
@ -80,16 +82,13 @@ MaybeExtentExpr GetSize(Shape &&);
|
||||||
// Utility predicate: does an expression reference any implied DO index?
|
// Utility predicate: does an expression reference any implied DO index?
|
||||||
bool ContainsAnyImpliedDoIndex(const ExtentExpr &);
|
bool ContainsAnyImpliedDoIndex(const ExtentExpr &);
|
||||||
|
|
||||||
// GetShape()
|
|
||||||
template<typename A> std::optional<Shape> GetShape(FoldingContext &, const A &);
|
|
||||||
|
|
||||||
class GetShapeHelper
|
class GetShapeHelper
|
||||||
: public AnyTraverse<GetShapeHelper, std::optional<Shape>> {
|
: public AnyTraverse<GetShapeHelper, std::optional<Shape>> {
|
||||||
public:
|
public:
|
||||||
using Result = std::optional<Shape>;
|
using Result = std::optional<Shape>;
|
||||||
using Base = AnyTraverse<GetShapeHelper, Result>;
|
using Base = AnyTraverse<GetShapeHelper, Result>;
|
||||||
using Base::operator();
|
using Base::operator();
|
||||||
GetShapeHelper(FoldingContext &c) : Base{*this}, context_{c} {}
|
explicit GetShapeHelper(FoldingContext &c) : Base{*this}, context_{c} {}
|
||||||
|
|
||||||
Result operator()(const ImpliedDoIndex &) const { return Scalar(); }
|
Result operator()(const ImpliedDoIndex &) const { return Scalar(); }
|
||||||
Result operator()(const DescriptorInquiry &) const { return Scalar(); }
|
Result operator()(const DescriptorInquiry &) const { return Scalar(); }
|
||||||
|
|
|
@ -177,52 +177,84 @@ bool ContainsAnyImpliedDoIndex(const ExtentExpr &expr) {
|
||||||
return MyVisitor{}(expr);
|
return MyVisitor{}(expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
ExtentExpr GetLowerBound(
|
// Determines lower bound on a dimension. This can be other than 1 only
|
||||||
FoldingContext &context, const NamedEntity &base, int dimension) {
|
// for a reference to a whole array object or component. (See LBOUND, 16.9.109).
|
||||||
const Symbol &symbol{ResolveAssociations(base.GetLastSymbol())};
|
// ASSOCIATE construct entities may require tranversal of their referents.
|
||||||
|
class GetLowerBoundHelper : public Traverse<GetLowerBoundHelper, ExtentExpr> {
|
||||||
|
public:
|
||||||
|
using Result = ExtentExpr;
|
||||||
|
using Base = Traverse<GetLowerBoundHelper, ExtentExpr>;
|
||||||
|
using Base::operator();
|
||||||
|
GetLowerBoundHelper(FoldingContext &c, int d)
|
||||||
|
: Base{*this}, context_{c}, dimension_{d} {}
|
||||||
|
static ExtentExpr Default() { return ExtentExpr{1}; }
|
||||||
|
static ExtentExpr Combine(Result &&, Result &&) { return Default(); }
|
||||||
|
ExtentExpr operator()(const Symbol &);
|
||||||
|
ExtentExpr operator()(const Component &);
|
||||||
|
|
||||||
|
private:
|
||||||
|
FoldingContext &context_;
|
||||||
|
int dimension_;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto GetLowerBoundHelper::operator()(const Symbol &symbol0) -> Result {
|
||||||
|
const Symbol &symbol{symbol0.GetUltimate()};
|
||||||
if (const auto *details{symbol.detailsIf<semantics::ObjectEntityDetails>()}) {
|
if (const auto *details{symbol.detailsIf<semantics::ObjectEntityDetails>()}) {
|
||||||
int j{0};
|
int j{0};
|
||||||
for (const auto &shapeSpec : details->shape()) {
|
for (const auto &shapeSpec : details->shape()) {
|
||||||
if (j++ == dimension) {
|
if (j++ == dimension_) {
|
||||||
if (const auto &bound{shapeSpec.lbound().GetExplicit()}) {
|
if (const auto &bound{shapeSpec.lbound().GetExplicit()}) {
|
||||||
return Fold(context, common::Clone(*bound));
|
return Fold(context_, common::Clone(*bound));
|
||||||
} else if (semantics::IsDescriptor(symbol)) {
|
} else if (semantics::IsDescriptor(symbol)) {
|
||||||
return ExtentExpr{DescriptorInquiry{
|
return ExtentExpr{DescriptorInquiry{NamedEntity{symbol0},
|
||||||
base, DescriptorInquiry::Field::LowerBound, dimension}};
|
DescriptorInquiry::Field::LowerBound, dimension_}};
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (const auto *assoc{
|
||||||
|
symbol.detailsIf<semantics::AssocEntityDetails>()}) {
|
||||||
|
return (*this)(assoc->expr());
|
||||||
}
|
}
|
||||||
// When we don't know that we don't know the lower bound at compilation
|
return Default();
|
||||||
// time, then we do know it, and it's one. (See LBOUND, 16.9.109).
|
}
|
||||||
return ExtentExpr{1};
|
|
||||||
|
auto GetLowerBoundHelper::operator()(const Component &component) -> Result {
|
||||||
|
if (component.base().Rank() == 0) {
|
||||||
|
const Symbol &symbol{component.GetLastSymbol().GetUltimate()};
|
||||||
|
if (const auto *details{
|
||||||
|
symbol.detailsIf<semantics::ObjectEntityDetails>()}) {
|
||||||
|
int j{0};
|
||||||
|
for (const auto &shapeSpec : details->shape()) {
|
||||||
|
if (j++ == dimension_) {
|
||||||
|
if (const auto &bound{shapeSpec.lbound().GetExplicit()}) {
|
||||||
|
return Fold(context_, common::Clone(*bound));
|
||||||
|
} else if (semantics::IsDescriptor(symbol)) {
|
||||||
|
return ExtentExpr{
|
||||||
|
DescriptorInquiry{NamedEntity{common::Clone(component)},
|
||||||
|
DescriptorInquiry::Field::LowerBound, dimension_}};
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Default();
|
||||||
|
}
|
||||||
|
|
||||||
|
ExtentExpr GetLowerBound(
|
||||||
|
FoldingContext &context, const NamedEntity &base, int dimension) {
|
||||||
|
return GetLowerBoundHelper{context, dimension}(base);
|
||||||
}
|
}
|
||||||
|
|
||||||
Shape GetLowerBounds(FoldingContext &context, const NamedEntity &base) {
|
Shape GetLowerBounds(FoldingContext &context, const NamedEntity &base) {
|
||||||
const Symbol &symbol{ResolveAssociations(base.GetLastSymbol())};
|
|
||||||
Shape result;
|
Shape result;
|
||||||
if (const auto *details{symbol.detailsIf<semantics::ObjectEntityDetails>()}) {
|
int rank{base.Rank()};
|
||||||
int dim{0};
|
for (int dim{0}; dim < rank; ++dim) {
|
||||||
for (const auto &shapeSpec : details->shape()) {
|
result.emplace_back(GetLowerBound(context, base, dim));
|
||||||
if (const auto &bound{shapeSpec.lbound().GetExplicit()}) {
|
|
||||||
result.emplace_back(Fold(context, common::Clone(*bound)));
|
|
||||||
} else if (semantics::IsDescriptor(symbol)) {
|
|
||||||
result.emplace_back(ExtentExpr{DescriptorInquiry{
|
|
||||||
base, DescriptorInquiry::Field::LowerBound, dim}});
|
|
||||||
} else {
|
|
||||||
result.emplace_back(std::nullopt);
|
|
||||||
}
|
|
||||||
++dim;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
int rank{base.Rank()};
|
|
||||||
for (int dim{0}; dim < rank; ++dim) {
|
|
||||||
result.emplace_back(ExtentExpr{1});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
CHECK(GetRank(result) == symbol.Rank());
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -327,7 +359,9 @@ MaybeExtentExpr GetUpperBound(
|
||||||
symbol.detailsIf<semantics::AssocEntityDetails>()}) {
|
symbol.detailsIf<semantics::AssocEntityDetails>()}) {
|
||||||
if (auto shape{GetShape(context, assoc->expr())}) {
|
if (auto shape{GetShape(context, assoc->expr())}) {
|
||||||
if (dimension < static_cast<int>(shape->size())) {
|
if (dimension < static_cast<int>(shape->size())) {
|
||||||
return std::move(shape->at(dimension));
|
return ComputeUpperBound(context,
|
||||||
|
GetLowerBound(context, base, dimension),
|
||||||
|
std::move(shape->at(dimension)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue