mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-13 19:24:21 +00:00
[flang] Improve shape & length characterization
Analyze the shape of the result of TRANSFER(ptr,array) correctly when "ptr" is an array of deferred shape. Fixing this bug led to some refactoring and concentration of common code in TypeAndShape member functions with code in general shape and character length analysis, and this led to some regression test failures that have all been cleaned up. Differential Revision: https://reviews.llvm.org/D95744
This commit is contained in:
parent
3fdf2a56dd
commit
6f3d322f25
@ -78,8 +78,6 @@ public:
|
||||
|
||||
static std::optional<TypeAndShape> Characterize(
|
||||
const semantics::Symbol &, FoldingContext &);
|
||||
static std::optional<TypeAndShape> Characterize(
|
||||
const semantics::ObjectEntityDetails &, FoldingContext &);
|
||||
static std::optional<TypeAndShape> Characterize(
|
||||
const semantics::ProcInterface &, FoldingContext &);
|
||||
static std::optional<TypeAndShape> Characterize(
|
||||
@ -87,26 +85,25 @@ public:
|
||||
static std::optional<TypeAndShape> Characterize(
|
||||
const ActualArgument &, FoldingContext &);
|
||||
|
||||
// Handle Expr<T> & Designator<T>
|
||||
template <typename A>
|
||||
static std::optional<TypeAndShape> Characterize(
|
||||
const A &x, FoldingContext &context) {
|
||||
if (const auto *symbol{UnwrapWholeSymbolDataRef(x)}) {
|
||||
if (const auto *symbol{UnwrapWholeSymbolOrComponentDataRef(x)}) {
|
||||
if (auto result{Characterize(*symbol, context)}) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (auto type{x.GetType()}) {
|
||||
if (auto shape{GetShape(context, x)}) {
|
||||
TypeAndShape result{*type, std::move(*shape)};
|
||||
if (type->category() == TypeCategory::Character) {
|
||||
if (const auto *chExpr{UnwrapExpr<Expr<SomeCharacter>>(x)}) {
|
||||
if (auto length{chExpr->LEN()}) {
|
||||
result.set_LEN(std::move(*length));
|
||||
}
|
||||
TypeAndShape result{*type, GetShape(context, x)};
|
||||
if (type->category() == TypeCategory::Character) {
|
||||
if (const auto *chExpr{UnwrapExpr<Expr<SomeCharacter>>(x)}) {
|
||||
if (auto length{chExpr->LEN()}) {
|
||||
result.set_LEN(std::move(*length));
|
||||
}
|
||||
}
|
||||
return std::move(result.Rewrite(context));
|
||||
}
|
||||
return std::move(result.Rewrite(context));
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
@ -162,8 +159,9 @@ private:
|
||||
const semantics::AssocEntityDetails &, FoldingContext &);
|
||||
static std::optional<TypeAndShape> Characterize(
|
||||
const semantics::ProcEntityDetails &, FoldingContext &);
|
||||
void AcquireShape(const semantics::ObjectEntityDetails &);
|
||||
void AcquireAttrs(const semantics::Symbol &);
|
||||
void AcquireLEN();
|
||||
void AcquireLEN(const semantics::Symbol &);
|
||||
|
||||
protected:
|
||||
DynamicType type_;
|
||||
|
@ -330,6 +330,22 @@ template <typename A> const Symbol *UnwrapWholeSymbolDataRef(const A &x) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// If an expression is a whole symbol or a whole component desginator,
|
||||
// extract and return that symbol, else null.
|
||||
template <typename A>
|
||||
const Symbol *UnwrapWholeSymbolOrComponentDataRef(const A &x) {
|
||||
if (auto dataRef{ExtractDataRef(x)}) {
|
||||
if (const SymbolRef * p{std::get_if<SymbolRef>(&dataRef->u)}) {
|
||||
return &p->get();
|
||||
} else if (const Component * c{std::get_if<Component>(&dataRef->u)}) {
|
||||
if (c->base().Rank() == 0) {
|
||||
return &c->GetLastSymbol();
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// GetFirstSymbol(A%B%C[I]%D) -> A
|
||||
template <typename A> const Symbol *GetFirstSymbol(const A &x) {
|
||||
if (auto dataRef{ExtractDataRef(x, true)}) {
|
||||
|
@ -68,17 +68,20 @@ TypeAndShape &TypeAndShape::Rewrite(FoldingContext &context) {
|
||||
|
||||
std::optional<TypeAndShape> TypeAndShape::Characterize(
|
||||
const semantics::Symbol &symbol, FoldingContext &context) {
|
||||
const auto &ultimate{symbol.GetUltimate()};
|
||||
return std::visit(
|
||||
common::visitors{
|
||||
[&](const semantics::ObjectEntityDetails &object) {
|
||||
auto result{Characterize(object, context)};
|
||||
if (result &&
|
||||
result->type().category() == TypeCategory::Character) {
|
||||
if (auto len{DataRef{symbol}.LEN()}) {
|
||||
result->set_LEN(Fold(context, std::move(*len)));
|
||||
}
|
||||
[&](const semantics::ObjectEntityDetails &object)
|
||||
-> std::optional<TypeAndShape> {
|
||||
if (auto type{DynamicType::From(object.type())}) {
|
||||
TypeAndShape result{
|
||||
std::move(*type), GetShape(context, ultimate)};
|
||||
result.AcquireAttrs(ultimate);
|
||||
result.AcquireLEN(ultimate);
|
||||
return std::move(result.Rewrite(context));
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
return result;
|
||||
},
|
||||
[&](const semantics::ProcEntityDetails &proc) {
|
||||
const semantics::ProcInterface &interface{proc.interface()};
|
||||
@ -108,18 +111,7 @@ std::optional<TypeAndShape> TypeAndShape::Characterize(
|
||||
// GetUltimate() used here, not ResolveAssociations(), because
|
||||
// we need the type/rank of an associate entity from TYPE IS,
|
||||
// CLASS IS, or RANK statement.
|
||||
symbol.GetUltimate().details());
|
||||
}
|
||||
|
||||
std::optional<TypeAndShape> TypeAndShape::Characterize(
|
||||
const semantics::ObjectEntityDetails &object, FoldingContext &context) {
|
||||
if (auto type{DynamicType::From(object.type())}) {
|
||||
TypeAndShape result{std::move(*type)};
|
||||
result.AcquireShape(object);
|
||||
return Fold(context, std::move(result));
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
ultimate.details());
|
||||
}
|
||||
|
||||
std::optional<TypeAndShape> TypeAndShape::Characterize(
|
||||
@ -196,35 +188,24 @@ std::optional<Expr<SubscriptInteger>> TypeAndShape::MeasureSizeInBytes(
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void TypeAndShape::AcquireShape(const semantics::ObjectEntityDetails &object) {
|
||||
CHECK(shape_.empty() && !attrs_.test(Attr::AssumedRank));
|
||||
corank_ = object.coshape().Rank();
|
||||
if (object.IsAssumedRank()) {
|
||||
attrs_.set(Attr::AssumedRank);
|
||||
return;
|
||||
}
|
||||
if (object.IsAssumedShape()) {
|
||||
attrs_.set(Attr::AssumedShape);
|
||||
}
|
||||
if (object.IsAssumedSize()) {
|
||||
attrs_.set(Attr::AssumedSize);
|
||||
}
|
||||
if (object.IsDeferredShape()) {
|
||||
attrs_.set(Attr::DeferredShape);
|
||||
}
|
||||
if (object.IsCoarray()) {
|
||||
attrs_.set(Attr::Coarray);
|
||||
}
|
||||
for (const semantics::ShapeSpec &dim : object.shape()) {
|
||||
if (dim.ubound().GetExplicit()) {
|
||||
Expr<SubscriptInteger> extent{*dim.ubound().GetExplicit()};
|
||||
if (auto lbound{dim.lbound().GetExplicit()}) {
|
||||
extent =
|
||||
std::move(extent) + Expr<SubscriptInteger>{1} - std::move(*lbound);
|
||||
}
|
||||
shape_.emplace_back(std::move(extent));
|
||||
} else {
|
||||
shape_.push_back(std::nullopt);
|
||||
void TypeAndShape::AcquireAttrs(const semantics::Symbol &symbol) {
|
||||
if (const auto *object{
|
||||
symbol.GetUltimate().detailsIf<semantics::ObjectEntityDetails>()}) {
|
||||
corank_ = object->coshape().Rank();
|
||||
if (object->IsAssumedRank()) {
|
||||
attrs_.set(Attr::AssumedRank);
|
||||
}
|
||||
if (object->IsAssumedShape()) {
|
||||
attrs_.set(Attr::AssumedShape);
|
||||
}
|
||||
if (object->IsAssumedSize()) {
|
||||
attrs_.set(Attr::AssumedSize);
|
||||
}
|
||||
if (object->IsDeferredShape()) {
|
||||
attrs_.set(Attr::DeferredShape);
|
||||
}
|
||||
if (object->IsCoarray()) {
|
||||
attrs_.set(Attr::Coarray);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -239,6 +220,14 @@ void TypeAndShape::AcquireLEN() {
|
||||
}
|
||||
}
|
||||
|
||||
void TypeAndShape::AcquireLEN(const semantics::Symbol &symbol) {
|
||||
if (type_.category() == TypeCategory::Character) {
|
||||
if (auto len{DataRef{symbol}.LEN()}) {
|
||||
LEN_ = std::move(*len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
llvm::raw_ostream &TypeAndShape::Dump(llvm::raw_ostream &o) const {
|
||||
o << type_.AsFortran(LEN_ ? LEN_->AsFortran() : "");
|
||||
attrs_.Dump(o, EnumToString);
|
||||
@ -278,8 +267,8 @@ static common::Intent GetIntent(const semantics::Attrs &attrs) {
|
||||
|
||||
std::optional<DummyDataObject> DummyDataObject::Characterize(
|
||||
const semantics::Symbol &symbol, FoldingContext &context) {
|
||||
if (const auto *obj{symbol.detailsIf<semantics::ObjectEntityDetails>()}) {
|
||||
if (auto type{TypeAndShape::Characterize(*obj, context)}) {
|
||||
if (symbol.has<semantics::ObjectEntityDetails>()) {
|
||||
if (auto type{TypeAndShape::Characterize(symbol, context)}) {
|
||||
std::optional<DummyDataObject> result{std::move(*type)};
|
||||
using semantics::Attr;
|
||||
CopyAttrs<DummyDataObject, DummyDataObject::Attr>(symbol, *result,
|
||||
@ -522,8 +511,8 @@ bool FunctionResult::operator==(const FunctionResult &that) const {
|
||||
|
||||
std::optional<FunctionResult> FunctionResult::Characterize(
|
||||
const Symbol &symbol, FoldingContext &context) {
|
||||
if (const auto *object{symbol.detailsIf<semantics::ObjectEntityDetails>()}) {
|
||||
if (auto type{TypeAndShape::Characterize(*object, context)}) {
|
||||
if (symbol.has<semantics::ObjectEntityDetails>()) {
|
||||
if (auto type{TypeAndShape::Characterize(symbol, context)}) {
|
||||
FunctionResult result{std::move(*type)};
|
||||
CopyAttrs<FunctionResult, FunctionResult::Attr>(symbol, result,
|
||||
{
|
||||
|
@ -296,27 +296,31 @@ MaybeExtentExpr GetExtent(const NamedEntity &base, int dimension) {
|
||||
CHECK(dimension >= 0);
|
||||
const Symbol &symbol{ResolveAssociations(base.GetLastSymbol())};
|
||||
if (const auto *details{symbol.detailsIf<semantics::ObjectEntityDetails>()}) {
|
||||
if (IsImpliedShape(symbol)) {
|
||||
Shape shape{GetShape(symbol).value()};
|
||||
return std::move(shape.at(dimension));
|
||||
}
|
||||
int j{0};
|
||||
for (const auto &shapeSpec : details->shape()) {
|
||||
if (j++ == dimension) {
|
||||
if (shapeSpec.ubound().isExplicit()) {
|
||||
if (const auto &ubound{shapeSpec.ubound().GetExplicit()}) {
|
||||
if (const auto &lbound{shapeSpec.lbound().GetExplicit()}) {
|
||||
return common::Clone(ubound.value()) -
|
||||
common::Clone(lbound.value()) + ExtentExpr{1};
|
||||
} else {
|
||||
return ubound.value();
|
||||
if (IsImpliedShape(symbol) && details->init()) {
|
||||
if (auto shape{GetShape(symbol)}) {
|
||||
if (dimension < static_cast<int>(shape->size())) {
|
||||
return std::move(shape->at(dimension));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int j{0};
|
||||
for (const auto &shapeSpec : details->shape()) {
|
||||
if (j++ == dimension) {
|
||||
if (shapeSpec.ubound().isExplicit()) {
|
||||
if (const auto &ubound{shapeSpec.ubound().GetExplicit()}) {
|
||||
if (const auto &lbound{shapeSpec.lbound().GetExplicit()}) {
|
||||
return common::Clone(ubound.value()) -
|
||||
common::Clone(lbound.value()) + ExtentExpr{1};
|
||||
} else {
|
||||
return ubound.value();
|
||||
}
|
||||
}
|
||||
} else if (details->IsAssumedSize() && j == symbol.Rank()) {
|
||||
return std::nullopt;
|
||||
} else if (semantics::IsDescriptor(symbol)) {
|
||||
return ExtentExpr{DescriptorInquiry{NamedEntity{base},
|
||||
DescriptorInquiry::Field::Extent, dimension}};
|
||||
}
|
||||
} else if (details->IsAssumedSize() && j == symbol.Rank()) {
|
||||
return std::nullopt;
|
||||
} else if (semantics::IsDescriptor(symbol)) {
|
||||
return ExtentExpr{DescriptorInquiry{
|
||||
NamedEntity{base}, DescriptorInquiry::Field::Extent, dimension}};
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -449,7 +453,7 @@ auto GetShapeHelper::operator()(const Symbol &symbol) const -> Result {
|
||||
return std::visit(
|
||||
common::visitors{
|
||||
[&](const semantics::ObjectEntityDetails &object) {
|
||||
if (IsImpliedShape(symbol)) {
|
||||
if (IsImpliedShape(symbol) && object.init()) {
|
||||
return (*this)(object.init());
|
||||
} else {
|
||||
int n{object.shape().Rank()};
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "flang/Parser/char-block.h"
|
||||
#include "flang/Parser/characters.h"
|
||||
#include "flang/Parser/message.h"
|
||||
#include "flang/Semantics/scope.h"
|
||||
#include "flang/Semantics/symbol.h"
|
||||
#include <type_traits>
|
||||
|
||||
@ -257,8 +258,13 @@ DescriptorInquiry::DescriptorInquiry(NamedEntity &&base, Field field, int dim)
|
||||
}
|
||||
|
||||
// LEN()
|
||||
static std::optional<Expr<SubscriptInteger>> SymbolLEN(const Symbol &sym) {
|
||||
if (auto dyType{DynamicType::From(sym)}) {
|
||||
static std::optional<Expr<SubscriptInteger>> SymbolLEN(const Symbol &symbol) {
|
||||
const Symbol &ultimate{symbol.GetUltimate()};
|
||||
if (const auto *assoc{ultimate.detailsIf<semantics::AssocEntityDetails>()}) {
|
||||
if (const auto *chExpr{UnwrapExpr<Expr<SomeCharacter>>(assoc->expr())}) {
|
||||
return chExpr->LEN();
|
||||
}
|
||||
} else if (auto dyType{DynamicType::From(ultimate)}) {
|
||||
if (const semantics::ParamValue * len{dyType->charLength()}) {
|
||||
if (len->isExplicit()) {
|
||||
if (auto intExpr{len->GetExplicit()}) {
|
||||
@ -267,8 +273,10 @@ static std::optional<Expr<SubscriptInteger>> SymbolLEN(const Symbol &sym) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return Expr<SubscriptInteger>{
|
||||
DescriptorInquiry{NamedEntity{sym}, DescriptorInquiry::Field::Len}};
|
||||
if (IsDescriptor(ultimate) && !ultimate.owner().IsDerivedType()) {
|
||||
return Expr<SubscriptInteger>{DescriptorInquiry{
|
||||
NamedEntity{ultimate}, DescriptorInquiry::Field::Len}};
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
|
@ -272,6 +272,8 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
|
||||
: nullptr};
|
||||
int actualRank{evaluate::GetRank(actualType.shape())};
|
||||
bool actualIsPointer{evaluate::IsObjectPointer(actual, context)};
|
||||
bool dummyIsAssumedRank{dummy.type.attrs().test(
|
||||
characteristics::TypeAndShape::Attr::AssumedRank)};
|
||||
if (dummy.type.attrs().test(
|
||||
characteristics::TypeAndShape::Attr::AssumedShape)) {
|
||||
// 15.5.2.4(16)
|
||||
@ -295,7 +297,8 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
|
||||
if (!IsArrayElement(actual) &&
|
||||
!(actualType.type().category() == TypeCategory::Character &&
|
||||
actualType.type().kind() == 1) &&
|
||||
!(dummy.type.type().IsAssumedType() && dummyIsAssumedSize)) {
|
||||
!(dummy.type.type().IsAssumedType() && dummyIsAssumedSize) &&
|
||||
!dummyIsAssumedRank) {
|
||||
messages.Say(
|
||||
"Whole scalar actual argument may not be associated with a %s array"_err_en_US,
|
||||
dummyName);
|
||||
@ -355,8 +358,6 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
|
||||
bool dummyIsContiguous{
|
||||
dummy.attrs.test(characteristics::DummyDataObject::Attr::Contiguous)};
|
||||
bool actualIsContiguous{IsSimplyContiguous(actual, context)};
|
||||
bool dummyIsAssumedRank{dummy.type.attrs().test(
|
||||
characteristics::TypeAndShape::Attr::AssumedRank)};
|
||||
bool dummyIsAssumedShape{dummy.type.attrs().test(
|
||||
characteristics::TypeAndShape::Attr::AssumedShape)};
|
||||
if ((actualIsAsynchronous || actualIsVolatile) &&
|
||||
|
@ -1847,11 +1847,12 @@ static bool CheckCompatibleArgument(bool isElemental,
|
||||
return std::visit(
|
||||
common::visitors{
|
||||
[&](const characteristics::DummyDataObject &x) {
|
||||
characteristics::TypeAndShape dummyTypeAndShape{x.type};
|
||||
if (!isElemental && actual.Rank() != dummyTypeAndShape.Rank()) {
|
||||
if (!isElemental && actual.Rank() != x.type.Rank() &&
|
||||
!x.type.attrs().test(
|
||||
characteristics::TypeAndShape::Attr::AssumedRank)) {
|
||||
return false;
|
||||
} else if (auto actualType{actual.GetType()}) {
|
||||
return dummyTypeAndShape.type().IsTkCompatibleWith(*actualType);
|
||||
return x.type.type().IsTkCompatibleWith(*actualType);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -616,7 +616,7 @@ evaluate::StructureConstructor RuntimeTableBuilder::DescribeComponent(
|
||||
const std::string &distinctName, const SymbolVector *parameters) {
|
||||
evaluate::StructureConstructorValues values;
|
||||
auto typeAndShape{evaluate::characteristics::TypeAndShape::Characterize(
|
||||
object, context_.foldingContext())};
|
||||
symbol, context_.foldingContext())};
|
||||
CHECK(typeAndShape.has_value());
|
||||
auto dyType{typeAndShape->type()};
|
||||
const auto &shape{typeAndShape->shape()};
|
||||
|
Loading…
Reference in New Issue
Block a user