[flang-commits] [flang] 6f3d322 - [flang] Improve shape & length characterization

peter klausler via flang-commits flang-commits at lists.llvm.org
Sat Jan 30 16:14:40 PST 2021


Author: peter klausler
Date: 2021-01-30T16:14:27-08:00
New Revision: 6f3d322f250d2381370b256e648cbb76c6de0135

URL: https://github.com/llvm/llvm-project/commit/6f3d322f250d2381370b256e648cbb76c6de0135
DIFF: https://github.com/llvm/llvm-project/commit/6f3d322f250d2381370b256e648cbb76c6de0135.diff

LOG: [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

Added: 
    

Modified: 
    flang/include/flang/Evaluate/characteristics.h
    flang/include/flang/Evaluate/tools.h
    flang/lib/Evaluate/characteristics.cpp
    flang/lib/Evaluate/shape.cpp
    flang/lib/Evaluate/variable.cpp
    flang/lib/Semantics/check-call.cpp
    flang/lib/Semantics/expression.cpp
    flang/lib/Semantics/runtime-type-info.cpp

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Evaluate/characteristics.h b/flang/include/flang/Evaluate/characteristics.h
index 6b7b2f5408e4..f18a220be350 100644
--- a/flang/include/flang/Evaluate/characteristics.h
+++ b/flang/include/flang/Evaluate/characteristics.h
@@ -78,8 +78,6 @@ class TypeAndShape {
 
   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 @@ class TypeAndShape {
   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 @@ class TypeAndShape {
       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_;

diff  --git a/flang/include/flang/Evaluate/tools.h b/flang/include/flang/Evaluate/tools.h
index 3210ab50cdfe..5ad999c550e3 100644
--- a/flang/include/flang/Evaluate/tools.h
+++ b/flang/include/flang/Evaluate/tools.h
@@ -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)}) {

diff  --git a/flang/lib/Evaluate/characteristics.cpp b/flang/lib/Evaluate/characteristics.cpp
index 92ecdd6fe153..e53058abfb3a 100644
--- a/flang/lib/Evaluate/characteristics.cpp
+++ b/flang/lib/Evaluate/characteristics.cpp
@@ -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,
           {

diff  --git a/flang/lib/Evaluate/shape.cpp b/flang/lib/Evaluate/shape.cpp
index a899d9647075..9652d0ca65a8 100644
--- a/flang/lib/Evaluate/shape.cpp
+++ b/flang/lib/Evaluate/shape.cpp
@@ -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()};

diff  --git a/flang/lib/Evaluate/variable.cpp b/flang/lib/Evaluate/variable.cpp
index c81f2b175ed5..f26b76fda859 100644
--- a/flang/lib/Evaluate/variable.cpp
+++ b/flang/lib/Evaluate/variable.cpp
@@ -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;

diff  --git a/flang/lib/Semantics/check-call.cpp b/flang/lib/Semantics/check-call.cpp
index 996cdf298d85..924b7c86ae9c 100644
--- a/flang/lib/Semantics/check-call.cpp
+++ b/flang/lib/Semantics/check-call.cpp
@@ -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) &&

diff  --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp
index 56a26d7e9bd8..37207e6fde2f 100644
--- a/flang/lib/Semantics/expression.cpp
+++ b/flang/lib/Semantics/expression.cpp
@@ -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;
             }

diff  --git a/flang/lib/Semantics/runtime-type-info.cpp b/flang/lib/Semantics/runtime-type-info.cpp
index dd47aa8eef27..13b2ea745e0c 100644
--- a/flang/lib/Semantics/runtime-type-info.cpp
+++ b/flang/lib/Semantics/runtime-type-info.cpp
@@ -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()};


        


More information about the flang-commits mailing list