[llvm-branch-commits] [flang] 07f1e1f - [flang] Correct shape analysis for transformational intrinsic functions

peter klausler via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Fri Jan 22 10:53:50 PST 2021


Author: peter klausler
Date: 2021-01-22T10:48:58-08:00
New Revision: 07f1e1f44c87d1ee84caf13d6e5aa64eb7e1b068

URL: https://github.com/llvm/llvm-project/commit/07f1e1f44c87d1ee84caf13d6e5aa64eb7e1b068
DIFF: https://github.com/llvm/llvm-project/commit/07f1e1f44c87d1ee84caf13d6e5aa64eb7e1b068.diff

LOG: [flang] Correct shape analysis for transformational intrinsic functions

Correct the analysis of references to transformational intrinsic
functions that have different semantics based on the presence or
absence of a DIM= argument; add shape analysis for UNPACK().

Differential Revision: https://reviews.llvm.org/D94716

Added: 
    

Modified: 
    flang/lib/Evaluate/intrinsics.cpp
    flang/lib/Evaluate/shape.cpp

Removed: 
    


################################################################################
diff  --git a/flang/lib/Evaluate/intrinsics.cpp b/flang/lib/Evaluate/intrinsics.cpp
index 3de43fd88d7e..98fbe92e2815 100644
--- a/flang/lib/Evaluate/intrinsics.cpp
+++ b/flang/lib/Evaluate/intrinsics.cpp
@@ -181,12 +181,13 @@ ENUM_CLASS(Rank,
     conformable, // scalar, or array of same rank & shape as "array" argument
     reduceOperation, // a pure function with constraints for REDUCE
     dimReduced, // scalar if no DIM= argument, else rank(array)-1
-    dimRemoved, // scalar, or rank(array)-1
+    dimRemovedOrScalar, // rank(array)-1 (less DIM) or scalar
+    locReduced, // vector(1:rank) if no DIM= argument, else rank(array)-1
     rankPlus1, // rank(known)+1
     shaped, // rank is length of SHAPE vector
 )
 
-ENUM_CLASS(Optionality, required, optional,
+ENUM_CLASS(Optionality, required, optional, missing,
     defaultsToSameKind, // for MatchingDefaultKIND
     defaultsToDefaultForResult, // for DefaultingKIND
     defaultsToSizeKind, // for SizeDefaultKIND
@@ -227,6 +228,9 @@ static constexpr IntrinsicDummyArgument RequiredDIM{"dim",
 static constexpr IntrinsicDummyArgument OptionalDIM{"dim",
     {IntType, KindCode::dimArg}, Rank::scalar, Optionality::optional,
     common::Intent::In};
+static constexpr IntrinsicDummyArgument MissingDIM{"dim",
+    {IntType, KindCode::dimArg}, Rank::scalar, Optionality::missing,
+    common::Intent::In};
 static constexpr IntrinsicDummyArgument OptionalMASK{"mask", AnyLogical,
     Rank::conformable, Optionality::optional, common::Intent::In};
 
@@ -346,8 +350,8 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
     {"count", {{"mask", AnyLogical, Rank::array}, OptionalDIM, DefaultingKIND},
         KINDInt, Rank::dimReduced, IntrinsicClass::transformationalFunction},
     {"cshift",
-        {{"array", SameType, Rank::array}, {"shift", AnyInt, Rank::dimRemoved},
-            OptionalDIM},
+        {{"array", SameType, Rank::array},
+            {"shift", AnyInt, Rank::dimRemovedOrScalar}, OptionalDIM},
         SameType, Rank::conformable, IntrinsicClass::transformationalFunction},
     {"dble", {{"a", AnyNumeric, Rank::elementalOrBOZ}}, DoublePrecision},
     {"digits", {{"x", AnyIntOrReal, Rank::anyOrAssumedRank}}, DefaultInt,
@@ -380,16 +384,16 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
     {"dshiftr", {{"i", BOZ}, {"j", SameInt}, {"shift", AnyInt}}, SameInt},
     {"eoshift",
         {{"array", SameIntrinsic, Rank::array},
-            {"shift", AnyInt, Rank::dimRemoved},
-            {"boundary", SameIntrinsic, Rank::dimRemoved,
+            {"shift", AnyInt, Rank::dimRemovedOrScalar},
+            {"boundary", SameIntrinsic, Rank::dimReduced,
                 Optionality::optional},
             OptionalDIM},
         SameIntrinsic, Rank::conformable,
         IntrinsicClass::transformationalFunction},
     {"eoshift",
         {{"array", SameDerivedType, Rank::array},
-            {"shift", AnyInt, Rank::dimRemoved},
-            {"boundary", SameDerivedType, Rank::dimRemoved}, OptionalDIM},
+            {"shift", AnyInt, Rank::dimReduced},
+            {"boundary", SameDerivedType, Rank::dimReduced}, OptionalDIM},
         SameDerivedType, Rank::conformable,
         IntrinsicClass::transformationalFunction},
     {"epsilon", {{"x", SameReal, Rank::anyOrAssumedRank}}, SameReal,
@@ -410,20 +414,21 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
             {"value", AnyNumeric, Rank::scalar}, RequiredDIM, OptionalMASK,
             SizeDefaultKIND,
             {"back", AnyLogical, Rank::scalar, Optionality::optional}},
-        KINDInt, Rank::dimRemoved, IntrinsicClass::transformationalFunction},
+        KINDInt, Rank::locReduced, IntrinsicClass::transformationalFunction},
     {"findloc",
         {{"array", AnyNumeric, Rank::array},
-            {"value", AnyNumeric, Rank::scalar}, OptionalMASK, SizeDefaultKIND,
+            {"value", AnyNumeric, Rank::scalar}, MissingDIM, OptionalMASK,
+            SizeDefaultKIND,
             {"back", AnyLogical, Rank::scalar, Optionality::optional}},
         KINDInt, Rank::vector, IntrinsicClass::transformationalFunction},
     {"findloc",
         {{"array", SameChar, Rank::array}, {"value", SameChar, Rank::scalar},
             RequiredDIM, OptionalMASK, SizeDefaultKIND,
             {"back", AnyLogical, Rank::scalar, Optionality::optional}},
-        KINDInt, Rank::dimRemoved, IntrinsicClass::transformationalFunction},
+        KINDInt, Rank::locReduced, IntrinsicClass::transformationalFunction},
     {"findloc",
         {{"array", SameChar, Rank::array}, {"value", SameChar, Rank::scalar},
-            OptionalMASK, SizeDefaultKIND,
+            MissingDIM, OptionalMASK, SizeDefaultKIND,
             {"back", AnyLogical, Rank::scalar, Optionality::optional}},
         KINDInt, Rank::vector, IntrinsicClass::transformationalFunction},
     {"findloc",
@@ -431,10 +436,11 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
             {"value", AnyLogical, Rank::scalar}, RequiredDIM, OptionalMASK,
             SizeDefaultKIND,
             {"back", AnyLogical, Rank::scalar, Optionality::optional}},
-        KINDInt, Rank::dimRemoved, IntrinsicClass::transformationalFunction},
+        KINDInt, Rank::locReduced, IntrinsicClass::transformationalFunction},
     {"findloc",
         {{"array", AnyLogical, Rank::array},
-            {"value", AnyLogical, Rank::scalar}, OptionalMASK, SizeDefaultKIND,
+            {"value", AnyLogical, Rank::scalar}, MissingDIM, OptionalMASK,
+            SizeDefaultKIND,
             {"back", AnyLogical, Rank::scalar, Optionality::optional}},
         KINDInt, Rank::vector, IntrinsicClass::transformationalFunction},
     {"floor", {{"a", AnyReal}, DefaultingKIND}, KINDInt},
@@ -444,12 +450,18 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
         Rank::scalar, IntrinsicClass::inquiryFunction},
     {"hypot", {{"x", OperandReal}, {"y", OperandReal}}, OperandReal},
     {"iachar", {{"c", AnyChar}, DefaultingKIND}, KINDInt},
-    {"iall", {{"array", SameInt, Rank::array}, OptionalDIM, OptionalMASK},
+    {"iall", {{"array", SameInt, Rank::array}, RequiredDIM, OptionalMASK},
         SameInt, Rank::dimReduced, IntrinsicClass::transformationalFunction},
-    {"iany", {{"array", SameInt, Rank::array}, OptionalDIM, OptionalMASK},
+    {"iall", {{"array", SameInt, Rank::array}, MissingDIM, OptionalMASK},
+        SameInt, Rank::scalar, IntrinsicClass::transformationalFunction},
+    {"iany", {{"array", SameInt, Rank::array}, RequiredDIM, OptionalMASK},
         SameInt, Rank::dimReduced, IntrinsicClass::transformationalFunction},
-    {"iparity", {{"array", SameInt, Rank::array}, OptionalDIM, OptionalMASK},
+    {"iany", {{"array", SameInt, Rank::array}, MissingDIM, OptionalMASK},
+        SameInt, Rank::scalar, IntrinsicClass::transformationalFunction},
+    {"iparity", {{"array", SameInt, Rank::array}, RequiredDIM, OptionalMASK},
         SameInt, Rank::dimReduced, IntrinsicClass::transformationalFunction},
+    {"iparity", {{"array", SameInt, Rank::array}, MissingDIM, OptionalMASK},
+        SameInt, Rank::scalar, IntrinsicClass::transformationalFunction},
     {"iand", {{"i", SameInt}, {"j", SameInt, Rank::elementalOrBOZ}}, SameInt},
     {"iand", {{"i", BOZ}, {"j", SameInt}}, SameInt},
     {"ibclr", {{"i", SameInt}, {"pos", AnyInt}}, SameInt},
@@ -540,14 +552,22 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
     {"maxexponent", {{"x", AnyReal, Rank::anyOrAssumedRank}}, DefaultInt,
         Rank::scalar, IntrinsicClass::inquiryFunction},
     {"maxloc",
-        {{"array", AnyRelatable, Rank::array}, OptionalDIM, OptionalMASK,
+        {{"array", AnyRelatable, Rank::array}, RequiredDIM, OptionalMASK,
             SizeDefaultKIND,
             {"back", AnyLogical, Rank::scalar, Optionality::optional}},
-        KINDInt, Rank::dimReduced, IntrinsicClass::transformationalFunction},
+        KINDInt, Rank::locReduced, IntrinsicClass::transformationalFunction},
+    {"maxloc",
+        {{"array", AnyRelatable, Rank::array}, MissingDIM, OptionalMASK,
+            SizeDefaultKIND,
+            {"back", AnyLogical, Rank::scalar, Optionality::optional}},
+        KINDInt, Rank::locReduced, IntrinsicClass::transformationalFunction},
     {"maxval",
-        {{"array", SameRelatable, Rank::array}, OptionalDIM, OptionalMASK},
+        {{"array", SameRelatable, Rank::array}, RequiredDIM, OptionalMASK},
         SameRelatable, Rank::dimReduced,
         IntrinsicClass::transformationalFunction},
+    {"maxval",
+        {{"array", SameRelatable, Rank::array}, MissingDIM, OptionalMASK},
+        SameRelatable, Rank::scalar, IntrinsicClass::transformationalFunction},
     {"merge",
         {{"tsource", SameType}, {"fsource", SameType}, {"mask", AnyLogical}},
         SameType},
@@ -569,14 +589,22 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
     {"minexponent", {{"x", AnyReal, Rank::anyOrAssumedRank}}, DefaultInt,
         Rank::scalar, IntrinsicClass::inquiryFunction},
     {"minloc",
-        {{"array", AnyRelatable, Rank::array}, OptionalDIM, OptionalMASK,
+        {{"array", AnyRelatable, Rank::array}, RequiredDIM, OptionalMASK,
             SizeDefaultKIND,
             {"back", AnyLogical, Rank::scalar, Optionality::optional}},
-        KINDInt, Rank::dimReduced, IntrinsicClass::transformationalFunction},
+        KINDInt, Rank::locReduced, IntrinsicClass::transformationalFunction},
+    {"minloc",
+        {{"array", AnyRelatable, Rank::array}, MissingDIM, OptionalMASK,
+            SizeDefaultKIND,
+            {"back", AnyLogical, Rank::scalar, Optionality::optional}},
+        KINDInt, Rank::locReduced, IntrinsicClass::transformationalFunction},
     {"minval",
-        {{"array", SameRelatable, Rank::array}, OptionalDIM, OptionalMASK},
+        {{"array", SameRelatable, Rank::array}, RequiredDIM, OptionalMASK},
         SameRelatable, Rank::dimReduced,
         IntrinsicClass::transformationalFunction},
+    {"minval",
+        {{"array", SameRelatable, Rank::array}, MissingDIM, OptionalMASK},
+        SameRelatable, Rank::scalar, IntrinsicClass::transformationalFunction},
     {"mod", {{"a", OperandIntOrReal}, {"p", OperandIntOrReal}},
         OperandIntOrReal},
     {"modulo", {{"a", OperandIntOrReal}, {"p", OperandIntOrReal}},
@@ -611,9 +639,11 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
     {"popcnt", {{"i", AnyInt}}, DefaultInt},
     {"poppar", {{"i", AnyInt}}, DefaultInt},
     {"product",
-        {{"array", SameNumeric, Rank::array}, OptionalDIM, OptionalMASK},
+        {{"array", SameNumeric, Rank::array}, RequiredDIM, OptionalMASK},
         SameNumeric, Rank::dimReduced,
         IntrinsicClass::transformationalFunction},
+    {"product", {{"array", SameNumeric, Rank::array}, MissingDIM, OptionalMASK},
+        SameNumeric, Rank::scalar, IntrinsicClass::transformationalFunction},
     {"precision", {{"x", AnyFloating, Rank::anyOrAssumedRank}}, DefaultInt,
         Rank::scalar, IntrinsicClass::inquiryFunction},
     {"present", {{"a", Addressable, Rank::anyOrAssumedRank}}, DefaultLogical,
@@ -630,10 +660,16 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
         KINDReal},
     {"reduce",
         {{"array", SameType, Rank::array},
-            {"operation", SameType, Rank::reduceOperation}, OptionalDIM,
+            {"operation", SameType, Rank::reduceOperation}, RequiredDIM,
             OptionalMASK, {"identity", SameType, Rank::scalar},
             {"ordered", AnyLogical, Rank::scalar, Optionality::optional}},
         SameType, Rank::dimReduced, IntrinsicClass::transformationalFunction},
+    {"reduce",
+        {{"array", SameType, Rank::array},
+            {"operation", SameType, Rank::reduceOperation}, MissingDIM,
+            OptionalMASK, {"identity", SameType, Rank::scalar},
+            {"ordered", AnyLogical, Rank::scalar, Optionality::optional}},
+        SameType, Rank::scalar, IntrinsicClass::transformationalFunction},
     {"repeat", {{"string", SameChar, Rank::scalar}, {"ncopies", AnyInt}},
         SameChar, Rank::scalar, IntrinsicClass::transformationalFunction},
     {"reshape",
@@ -695,9 +731,11 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
     {"sqrt", {{"x", SameFloating}}, SameFloating},
     {"storage_size", {{"a", AnyData, Rank::anyOrAssumedRank}, SizeDefaultKIND},
         KINDInt, Rank::scalar, IntrinsicClass::inquiryFunction},
-    {"sum", {{"array", SameNumeric, Rank::array}, OptionalDIM, OptionalMASK},
+    {"sum", {{"array", SameNumeric, Rank::array}, RequiredDIM, OptionalMASK},
         SameNumeric, Rank::dimReduced,
         IntrinsicClass::transformationalFunction},
+    {"sum", {{"array", SameNumeric, Rank::array}, MissingDIM, OptionalMASK},
+        SameNumeric, Rank::scalar, IntrinsicClass::transformationalFunction},
     {"tan", {{"x", SameFloating}}, SameFloating},
     {"tand", {{"x", SameFloating}}, SameFloating},
     {"tanh", {{"x", SameFloating}}, SameFloating},
@@ -1083,6 +1121,9 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
       bool found{false};
       int slot{missingActualArguments};
       for (std::size_t j{0}; j < nonRepeatedDummies && !found; ++j) {
+        if (dummy[j].optionality == Optionality::missing) {
+          continue;
+        }
         if (arg->keyword()) {
           found = *arg->keyword() == dummy[j].keyword;
           if (found) {
@@ -1150,6 +1191,9 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
       } else {
         continue;
       }
+    } else if (d.optionality == Optionality::missing) {
+      messages.Say("unexpected '%s=' argument"_err_en_US, d.keyword);
+      return std::nullopt;
     }
     if (arg->GetAssumedTypeDummy()) {
       // TYPE(*) assumed-type dummy argument forwarded to intrinsic
@@ -1350,7 +1394,8 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
         CHECK(arrayArg);
         argOk = rank == 0 || rank == arrayArg->Rank();
         break;
-      case Rank::dimRemoved:
+      case Rank::dimReduced:
+      case Rank::dimRemovedOrScalar:
         CHECK(arrayArg);
         argOk = rank == 0 || rank + 1 == arrayArg->Rank();
         break;
@@ -1360,7 +1405,7 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
         CHECK(arrayArg);
         argOk = rank == 0;
         break;
-      case Rank::dimReduced:
+      case Rank::locReduced:
       case Rank::rankPlus1:
       case Rank::shaped:
         common::die("INTERNAL: result-only rank code appears on argument '%s' "
@@ -1518,9 +1563,9 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
     CHECK(arrayArg);
     resultRank = hasDimArg ? arrayArg->Rank() - 1 : 0;
     break;
-  case Rank::dimRemoved:
+  case Rank::locReduced:
     CHECK(arrayArg);
-    resultRank = arrayArg->Rank() - 1;
+    resultRank = hasDimArg ? arrayArg->Rank() - 1 : 1;
     break;
   case Rank::rankPlus1:
     CHECK(knownArg);
@@ -1536,6 +1581,7 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
   case Rank::known:
   case Rank::anyOrAssumedRank:
   case Rank::reduceOperation:
+  case Rank::dimRemovedOrScalar:
     common::die("INTERNAL: bad Rank code on intrinsic '%s' result", name);
     break;
   }

diff  --git a/flang/lib/Evaluate/shape.cpp b/flang/lib/Evaluate/shape.cpp
index d1bf64cd0fad..eb94139635ef 100644
--- a/flang/lib/Evaluate/shape.cpp
+++ b/flang/lib/Evaluate/shape.cpp
@@ -575,8 +575,7 @@ auto GetShapeHelper::operator()(const ProcedureRef &call) const -> Result {
     } else if (intrinsic->name == "all" || intrinsic->name == "any" ||
         intrinsic->name == "count" || intrinsic->name == "iall" ||
         intrinsic->name == "iany" || intrinsic->name == "iparity" ||
-        intrinsic->name == "maxloc" || intrinsic->name == "maxval" ||
-        intrinsic->name == "minloc" || intrinsic->name == "minval" ||
+        intrinsic->name == "maxval" || intrinsic->name == "minval" ||
         intrinsic->name == "norm2" || intrinsic->name == "parity" ||
         intrinsic->name == "product" || intrinsic->name == "sum") {
       // Reduction with DIM=
@@ -594,6 +593,25 @@ auto GetShapeHelper::operator()(const ProcedureRef &call) const -> Result {
           }
         }
       }
+    } else if (intrinsic->name == "maxloc" || intrinsic->name == "minloc") {
+      // TODO: FINDLOC
+      if (call.arguments().size() >= 2) {
+        if (auto arrayShape{
+                (*this)(UnwrapExpr<Expr<SomeType>>(call.arguments().at(0)))}) {
+          auto rank{static_cast<int>(arrayShape->size())};
+          if (const auto *dimArg{
+                  UnwrapExpr<Expr<SomeType>>(call.arguments()[1])}) {
+            auto dim{ToInt64(*dimArg)};
+            if (dim && *dim >= 1 && *dim <= rank) {
+              arrayShape->erase(arrayShape->begin() + (*dim - 1));
+              return std::move(*arrayShape);
+            }
+          } else {
+            // xxxLOC(no DIM=) result is vector(1:RANK(ARRAY=))
+            return Shape{ExtentExpr{rank}};
+          }
+        }
+      }
     } else if (intrinsic->name == "cshift" || intrinsic->name == "eoshift") {
       if (!call.arguments().empty()) {
         return (*this)(call.arguments()[0]);
@@ -723,6 +741,10 @@ auto GetShapeHelper::operator()(const ProcedureRef &call) const -> Result {
           }
         }
       }
+    } else if (intrinsic->name == "unpack") {
+      if (call.arguments().size() >= 2) {
+        return (*this)(call.arguments()[1]); // MASK=
+      }
     } else if (intrinsic->characteristics.value().attrs.test(characteristics::
                        Procedure::Attr::NullPointer)) { // NULL(MOLD=)
       return (*this)(call.arguments());


        


More information about the llvm-branch-commits mailing list