[flang-commits] [flang] df62afd - [flang] Unsplit COMPLEX operations

peter klausler via flang-commits flang-commits at lists.llvm.org
Mon Nov 16 09:39:14 PST 2020


Author: peter klausler
Date: 2020-11-16T09:39:03-08:00
New Revision: df62afd559d4899a968cb72ad2ddc98b27412fa6

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

LOG: [flang] Unsplit COMPLEX operations

COMPLEX negation, addition, subtraction, conversions of kind, and
equality/inequality were represented as component-wise REAL
operations.  It turns out to be easier for lowering if we
do not split and recombine these COMPLEX operations, and it
avoids a potential problem with COMPLEX valued function calls
in these contexts.  So add this suite of operations to the
typed expression representation in place of the component-wise
transformations, and support them in folding.

Differential revision: https://reviews.llvm.org/D91443

Added: 
    

Modified: 
    flang/include/flang/Evaluate/expression.h
    flang/include/flang/Evaluate/tools.h
    flang/lib/Evaluate/fold-implementation.h
    flang/lib/Evaluate/fold-logical.cpp
    flang/lib/Evaluate/formatting.cpp
    flang/lib/Evaluate/tools.cpp

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Evaluate/expression.h b/flang/include/flang/Evaluate/expression.h
index f0ce375da015..8fdeb45024d8 100644
--- a/flang/include/flang/Evaluate/expression.h
+++ b/flang/include/flang/Evaluate/expression.h
@@ -202,15 +202,11 @@ template <typename TO, TypeCategory FROMCAT = TO::category>
 struct Convert : public Operation<Convert<TO, FROMCAT>, TO, SomeKind<FROMCAT>> {
   // Fortran doesn't have conversions between kinds of CHARACTER apart from
   // assignments, and in those the data must be convertible to/from 7-bit ASCII.
-  // Conversions between kinds of COMPLEX are represented piecewise.
   static_assert(((TO::category == TypeCategory::Integer ||
                      TO::category == TypeCategory::Real) &&
                     (FROMCAT == TypeCategory::Integer ||
                         FROMCAT == TypeCategory::Real)) ||
-      (TO::category == TypeCategory::Character &&
-          FROMCAT == TypeCategory::Character) ||
-      (TO::category == TypeCategory::Logical &&
-          FROMCAT == TypeCategory::Logical));
+      TO::category == FROMCAT);
   using Result = TO;
   using Operand = SomeKind<FROMCAT>;
   using Base = Operation<Convert, Result, Operand>;
@@ -542,8 +538,7 @@ class Expr<Type<TypeCategory::Real, KIND>>
 
 private:
   // N.B. Real->Complex and Complex->Real conversions are done with CMPLX
-  // and part access operations (resp.).  Conversions between kinds of
-  // Complex are done via decomposition to Real and reconstruction.
+  // and part access operations (resp.).
   using Conversions = std::variant<Convert<Result, TypeCategory::Integer>,
       Convert<Result, TypeCategory::Real>>;
   using Operations = std::variant<ComplexComponent<KIND>, Parentheses<Result>,
@@ -563,12 +558,10 @@ class Expr<Type<TypeCategory::Complex, KIND>>
   using Result = Type<TypeCategory::Complex, KIND>;
   EVALUATE_UNION_CLASS_BOILERPLATE(Expr)
   explicit Expr(const Scalar<Result> &x) : u{Constant<Result>{x}} {}
-
-  // Note that many COMPLEX operations are represented as REAL operations
-  // over their components (viz., conversions, negation, add, and subtract).
-  using Operations =
-      std::variant<Parentheses<Result>, Multiply<Result>, Divide<Result>,
-          Power<Result>, RealToIntPower<Result>, ComplexConstructor<KIND>>;
+  using Operations = std::variant<Parentheses<Result>, Negate<Result>,
+      Convert<Result, TypeCategory::Complex>, Add<Result>, Subtract<Result>,
+      Multiply<Result>, Divide<Result>, Power<Result>, RealToIntPower<Result>,
+      ComplexConstructor<KIND>>;
   using Others = std::variant<Constant<Result>, ArrayConstructor<Result>,
       Designator<Result>, FunctionRef<Result>>;
 
@@ -614,6 +607,7 @@ struct Relational : public Operation<Relational<T>, LogicalResult, T, T> {
   using Operand = typename Base::template Operand<0>;
   static_assert(Operand::category == TypeCategory::Integer ||
       Operand::category == TypeCategory::Real ||
+      Operand::category == TypeCategory::Complex ||
       Operand::category == TypeCategory::Character);
   CLASS_BOILERPLATE(Relational)
   Relational(
@@ -625,9 +619,8 @@ struct Relational : public Operation<Relational<T>, LogicalResult, T, T> {
 };
 
 template <> class Relational<SomeType> {
-  // COMPLEX data are compared piecewise.
-  using DirectlyComparableTypes =
-      common::CombineTuples<IntegerTypes, RealTypes, CharacterTypes>;
+  using DirectlyComparableTypes = common::CombineTuples<IntegerTypes, RealTypes,
+      ComplexTypes, CharacterTypes>;
 
 public:
   using Result = LogicalResult;

diff  --git a/flang/include/flang/Evaluate/tools.h b/flang/include/flang/Evaluate/tools.h
index 4ae85b9c0d56..7df91e13dc58 100644
--- a/flang/include/flang/Evaluate/tools.h
+++ b/flang/include/flang/Evaluate/tools.h
@@ -331,49 +331,29 @@ template <typename A> const Symbol *GetFirstSymbol(const A &x) {
 template <typename TO, TypeCategory FROMCAT>
 Expr<TO> ConvertToType(Expr<SomeKind<FROMCAT>> &&x) {
   static_assert(IsSpecificIntrinsicType<TO>);
-  if constexpr (FROMCAT != TO::category) {
-    if constexpr (TO::category == TypeCategory::Complex) {
-      using Part = typename TO::Part;
-      Scalar<Part> zero;
-      return Expr<TO>{ComplexConstructor<TO::kind>{
-          ConvertToType<Part>(std::move(x)), Expr<Part>{Constant<Part>{zero}}}};
-    } else if constexpr (FROMCAT == TypeCategory::Complex) {
-      // Extract and convert the real component of a complex value
-      return std::visit(
-          [&](auto &&z) {
-            using ZType = ResultType<decltype(z)>;
-            using Part = typename ZType::Part;
-            return ConvertToType<TO, TypeCategory::Real>(Expr<SomeReal>{
-                Expr<Part>{ComplexComponent<Part::kind>{false, std::move(z)}}});
-          },
-          std::move(x.u));
-    } else {
-      return Expr<TO>{Convert<TO, FROMCAT>{std::move(x)}};
-    }
-  } else {
-    // Same type category
+  if constexpr (FROMCAT == TO::category) {
     if (auto *already{std::get_if<Expr<TO>>(&x.u)}) {
       return std::move(*already);
-    }
-    if constexpr (TO::category == TypeCategory::Complex) {
-      // Extract, convert, and recombine the components.
-      return Expr<TO>{std::visit(
-          [](auto &z) {
-            using FromType = ResultType<decltype(z)>;
-            using FromPart = typename FromType::Part;
-            using FromGeneric = SomeKind<TypeCategory::Real>;
-            using ToPart = typename TO::Part;
-            Convert<ToPart, TypeCategory::Real> re{Expr<FromGeneric>{
-                Expr<FromPart>{ComplexComponent<FromType::kind>{false, z}}}};
-            Convert<ToPart, TypeCategory::Real> im{Expr<FromGeneric>{
-                Expr<FromPart>{ComplexComponent<FromType::kind>{true, z}}}};
-            return ComplexConstructor<TO::kind>{
-                AsExpr(std::move(re)), AsExpr(std::move(im))};
-          },
-          x.u)};
     } else {
-      return Expr<TO>{Convert<TO, TO::category>{std::move(x)}};
+      return Expr<TO>{Convert<TO, FROMCAT>{std::move(x)}};
     }
+  } else if constexpr (TO::category == TypeCategory::Complex) {
+    using Part = typename TO::Part;
+    Scalar<Part> zero;
+    return Expr<TO>{ComplexConstructor<TO::kind>{
+        ConvertToType<Part>(std::move(x)), Expr<Part>{Constant<Part>{zero}}}};
+  } else if constexpr (FROMCAT == TypeCategory::Complex) {
+    // Extract and convert the real component of a complex value
+    return std::visit(
+        [&](auto &&z) {
+          using ZType = ResultType<decltype(z)>;
+          using Part = typename ZType::Part;
+          return ConvertToType<TO, TypeCategory::Real>(Expr<SomeReal>{
+              Expr<Part>{ComplexComponent<Part::kind>{false, std::move(z)}}});
+        },
+        std::move(x.u));
+  } else {
+    return Expr<TO>{Convert<TO, FROMCAT>{std::move(x)}};
   }
 }
 
@@ -523,24 +503,11 @@ template <typename A> Expr<TypeOf<A>> ScalarConstantToExpr(const A &x) {
 }
 
 // Combine two expressions of the same specific numeric type with an operation
-// to produce a new expression.  Implements piecewise addition and subtraction
-// for COMPLEX.
+// to produce a new expression.
 template <template <typename> class OPR, typename SPECIFIC>
 Expr<SPECIFIC> Combine(Expr<SPECIFIC> &&x, Expr<SPECIFIC> &&y) {
   static_assert(IsSpecificIntrinsicType<SPECIFIC>);
-  if constexpr (SPECIFIC::category == TypeCategory::Complex &&
-      (std::is_same_v<OPR<LargestReal>, Add<LargestReal>> ||
-          std::is_same_v<OPR<LargestReal>, Subtract<LargestReal>>)) {
-    static constexpr int kind{SPECIFIC::kind};
-    using Part = Type<TypeCategory::Real, kind>;
-    return AsExpr(ComplexConstructor<kind>{
-        AsExpr(OPR<Part>{AsExpr(ComplexComponent<kind>{false, x}),
-            AsExpr(ComplexComponent<kind>{false, y})}),
-        AsExpr(OPR<Part>{AsExpr(ComplexComponent<kind>{true, x}),
-            AsExpr(ComplexComponent<kind>{true, y})})});
-  } else {
-    return AsExpr(OPR<SPECIFIC>{std::move(x), std::move(y)});
-  }
+  return AsExpr(OPR<SPECIFIC>{std::move(x), std::move(y)});
 }
 
 // Given two expressions of arbitrary kind in the same intrinsic type
@@ -620,15 +587,6 @@ Expr<Type<C, K>> operator-(Expr<Type<C, K>> &&x) {
   return AsExpr(Negate<Type<C, K>>{std::move(x)});
 }
 
-template <int K>
-Expr<Type<TypeCategory::Complex, K>> operator-(
-    Expr<Type<TypeCategory::Complex, K>> &&x) {
-  using Part = Type<TypeCategory::Real, K>;
-  return AsExpr(ComplexConstructor<K>{
-      AsExpr(Negate<Part>{AsExpr(ComplexComponent<K>{false, x})}),
-      AsExpr(Negate<Part>{AsExpr(ComplexComponent<K>{true, x})})});
-}
-
 template <TypeCategory C, int K>
 Expr<Type<C, K>> operator+(Expr<Type<C, K>> &&x, Expr<Type<C, K>> &&y) {
   return AsExpr(Combine<Add, Type<C, K>>(std::move(x), std::move(y)));

diff  --git a/flang/lib/Evaluate/fold-implementation.h b/flang/lib/Evaluate/fold-implementation.h
index ee3aaa3f9124..4b22a593df91 100644
--- a/flang/lib/Evaluate/fold-implementation.h
+++ b/flang/lib/Evaluate/fold-implementation.h
@@ -1236,6 +1236,15 @@ Expr<TO> FoldOperation(
               }
               return ScalarConstantToExpr(std::move(converted.value));
             }
+          } else if constexpr (TO::category == TypeCategory::Complex) {
+            if constexpr (Operand::category == TypeCategory::Complex) {
+              return FoldOperation(ctx,
+                  ComplexConstructor<TO::kind>{
+                      AsExpr(Convert<typename TO::Part>{AsCategoryExpr(
+                          Constant<typename Operand::Part>{value->REAL()})}),
+                      AsExpr(Convert<typename TO::Part>{AsCategoryExpr(
+                          Constant<typename Operand::Part>{value->AIMAG()})})});
+            }
           } else if constexpr (TO::category == TypeCategory::Character &&
               Operand::category == TypeCategory::Character) {
             if (auto converted{ConvertString<Scalar<TO>>(std::move(*value))}) {

diff  --git a/flang/lib/Evaluate/fold-logical.cpp b/flang/lib/Evaluate/fold-logical.cpp
index bf283c4f9206..b22c742b0ea6 100644
--- a/flang/lib/Evaluate/fold-logical.cpp
+++ b/flang/lib/Evaluate/fold-logical.cpp
@@ -134,11 +134,13 @@ Expr<LogicalResult> FoldOperation(
           Satisfies(relation.opr, folded->first.CompareSigned(folded->second));
     } else if constexpr (T::category == TypeCategory::Real) {
       result = Satisfies(relation.opr, folded->first.Compare(folded->second));
+    } else if constexpr (T::category == TypeCategory::Complex) {
+      result = (relation.opr == RelationalOperator::EQ) ==
+          folded->first.Equals(folded->second);
     } else if constexpr (T::category == TypeCategory::Character) {
       result = Satisfies(relation.opr, Compare(folded->first, folded->second));
     } else {
-      static_assert(T::category != TypeCategory::Complex &&
-          T::category != TypeCategory::Logical);
+      static_assert(T::category != TypeCategory::Logical);
     }
     return Expr<LogicalResult>{Constant<LogicalResult>{result}};
   }

diff  --git a/flang/lib/Evaluate/formatting.cpp b/flang/lib/Evaluate/formatting.cpp
index bed7fc4efee7..e59e79873f4c 100644
--- a/flang/lib/Evaluate/formatting.cpp
+++ b/flang/lib/Evaluate/formatting.cpp
@@ -349,6 +349,7 @@ template <typename TO, TypeCategory FROMCAT>
 llvm::raw_ostream &Convert<TO, FROMCAT>::AsFortran(llvm::raw_ostream &o) const {
   static_assert(TO::category == TypeCategory::Integer ||
           TO::category == TypeCategory::Real ||
+          TO::category == TypeCategory::Complex ||
           TO::category == TypeCategory::Character ||
           TO::category == TypeCategory::Logical,
       "Convert<> to bad category!");
@@ -358,6 +359,8 @@ llvm::raw_ostream &Convert<TO, FROMCAT>::AsFortran(llvm::raw_ostream &o) const {
     this->left().AsFortran(o << "int(");
   } else if constexpr (TO::category == TypeCategory::Real) {
     this->left().AsFortran(o << "real(");
+  } else if constexpr (TO::category == TypeCategory::Complex) {
+    this->left().AsFortran(o << "cmplx(");
   } else {
     this->left().AsFortran(o << "logical(");
   }

diff  --git a/flang/lib/Evaluate/tools.cpp b/flang/lib/Evaluate/tools.cpp
index 22b881a98a7f..afad30271c1c 100644
--- a/flang/lib/Evaluate/tools.cpp
+++ b/flang/lib/Evaluate/tools.cpp
@@ -69,7 +69,7 @@ auto IsVariableHelper::operator()(const ProcedureDesignator &x) const
   return symbol && symbol->attrs().test(semantics::Attr::POINTER);
 }
 
-// Conversions of complex component expressions to REAL.
+// Conversions of COMPLEX component expressions to REAL.
 ConvertRealOperandsResult ConvertRealOperands(
     parser::ContextualMessages &messages, Expr<SomeType> &&x,
     Expr<SomeType> &&y, int defaultRealKind) {
@@ -498,31 +498,14 @@ std::optional<Expr<LogicalResult>> Relate(parser::ContextualMessages &messages,
           },
           [&](Expr<SomeComplex> &&zx,
               Expr<SomeComplex> &&zy) -> std::optional<Expr<LogicalResult>> {
-            if (opr != RelationalOperator::EQ &&
-                opr != RelationalOperator::NE) {
+            if (opr == RelationalOperator::EQ ||
+                opr == RelationalOperator::NE) {
+              return PromoteAndRelate(opr, std::move(zx), std::move(zy));
+            } else {
               messages.Say(
                   "COMPLEX data may be compared only for equality"_err_en_US);
-            } else {
-              auto rr{Relate(messages, opr,
-                  AsGenericExpr(GetComplexPart(zx, false)),
-                  AsGenericExpr(GetComplexPart(zy, false)))};
-              auto ri{
-                  Relate(messages, opr, AsGenericExpr(GetComplexPart(zx, true)),
-                      AsGenericExpr(GetComplexPart(zy, true)))};
-              if (auto parts{
-                      common::AllPresent(std::move(rr), std::move(ri))}) {
-                // (a,b)==(c,d) -> (a==c) .AND. (b==d)
-                // (a,b)/=(c,d) -> (a/=c) .OR. (b/=d)
-                LogicalOperator combine{opr == RelationalOperator::EQ
-                        ? LogicalOperator::And
-                        : LogicalOperator::Or};
-                return Expr<LogicalResult>{
-                    LogicalOperation<LogicalResult::kind>{combine,
-                        std::get<0>(std::move(*parts)),
-                        std::get<1>(std::move(*parts))}};
-              }
+              return std::nullopt;
             }
-            return std::nullopt;
           },
           [&](Expr<SomeComplex> &&zx, Expr<SomeInteger> &&iy) {
             return Relate(messages, opr, std::move(x),


        


More information about the flang-commits mailing list