[flang] checkpoint
authorpeter klausler <pklausler@nvidia.com>
Wed, 15 Aug 2018 20:46:33 +0000 (13:46 -0700)
committerpeter klausler <pklausler@nvidia.com>
Wed, 12 Sep 2018 23:28:51 +0000 (16:28 -0700)
Original-commit: flang-compiler/f18@2a9e80d9bbd75fdbf7b563dece563531866ac4e2
Reviewed-on: https://github.com/flang-compiler/f18/pull/183
Tree-same-pre-rewrite: false

flang/lib/evaluate/expression.cc
flang/lib/evaluate/expression.h
flang/lib/evaluate/type.h

index df3bc13..7ffeefd 100644 (file)
@@ -27,6 +27,108 @@ using namespace Fortran::parser::literals;
 
 namespace Fortran::evaluate {
 
+template<typename D, typename R, typename... O>
+std::ostream &Operation<D, R, O...>::Dump(std::ostream &o) const {
+  operand<0>().Dump(o << derived().prefix_);
+  if constexpr (operands() > 1) {
+    operand<1>().Dump(o << infix_);
+  }
+  return o << derived().postfix_;
+}
+
+template<typename D, typename R, typename... O>
+auto Operation<D, R, O...>::Fold(FoldingContext &context)
+    -> std::optional<Scalar<Result>> {
+  auto c0{operand<0>().Fold(context)};
+  if constexpr (operands() == 1) {
+    if (c0.has_value()) {
+      return derived().FoldScalar(context, *c0);
+    }
+  } else {
+    auto c1{operand<1>().Fold(context)};
+    if (c0.has_value() && c1.has_value()) {
+      return derived().FoldScalar(context, *c0, *c1);
+    }
+  }
+  return std::nullopt;
+}
+
+template<typename TO, typename FROM>
+auto Convert<TO, FROM>::FoldScalar(FoldingContext &context,
+    const Scalar<Operand> &c) -> std::optional<Scalar<Result>> {
+  if constexpr (std::is_same_v<Result, Operand>) {
+    return {c};
+  }
+  if constexpr (std::is_same_v<Result, SomeType>) {
+    using Generic = SomeKind<Operand::category>;
+    if constexpr (std::is_same_v<Operand, Generic>) {
+      return {Scalar<Result>{c}};
+    } else {
+      return {Scalar<Result>{Generic{c}}};
+    }
+  }
+  if constexpr (std::is_same_v<Operand, SomeType>) {
+    return std::visit(
+        [&](const auto &x) -> std::optional<Scalar<Result>> {
+          return Convert<Result, std::decay_t<decltype(x)>>::FoldScalar(
+              context, x);
+        },
+        c.u);
+  }
+  // Result and Operand are distinct types with known categories.
+  if constexpr (std::is_same_v<Result, SomeKind<Result::category>>) {
+    if constexpr (Result::category == Operand::category) {
+      return {Scalar<Result>{c}};
+    }
+    return std::nullopt;
+  }
+  // Result is a specific type.
+  if constexpr (std::is_same_v<Operand, SomeKind<Operand::category>>) {
+    return std::visit(
+        [&](const auto &x) -> std::optional<Scalar<Result>> {
+          return Convert<Result,
+              ScalarValueType<std::decay_t<decltype(x)>>>::FoldScalar(context,
+              x);
+        },
+        c.u);
+  }
+  // Result and Operand are distinct specific types.
+  if constexpr (Result::category == TypeCategory::Integer) {
+    if constexpr (Operand::category == TypeCategory::Integer) {
+      auto converted{Scalar<Result>::ConvertSigned(c)};
+      if (converted.overflow) {
+        context.messages.Say("INTEGER to INTEGER conversion overflowed"_en_US);
+      } else {
+        return {std::move(converted.value)};
+      }
+    }
+    if constexpr (Operand::category == TypeCategory::Real) {
+      auto converted{c.template ToInteger<Scalar<Result>>()};
+      if (converted.flags.test(RealFlag::InvalidArgument)) {
+        context.messages.Say(
+            "REAL to INTEGER conversion: invalid argument"_en_US);
+      } else if (converted.flags.test(RealFlag::Overflow)) {
+        context.messages.Say("REAL to INTEGER conversion overflowed"_en_US);
+      } else {
+        return {std::move(converted.value)};
+      }
+    }
+  }
+  if constexpr (Result::category == TypeCategory::Real) {
+    if constexpr (Operand::category == TypeCategory::Integer) {
+      auto converted{Scalar<Result>::FromInteger(c)};
+      RealFlagWarnings(context, converted.flags, "INTEGER to REAL conversion");
+      return {std::move(converted.value)};
+    }
+    if constexpr (Operand::category == TypeCategory::Real) {
+      auto converted{Scalar<Result>::Convert(c)};
+      RealFlagWarnings(context, converted.flags, "REAL to REAL conversion");
+      return {std::move(converted.value)};
+    }
+  }
+  return std::nullopt;
+}
+
 // Dumping
 template<typename... A>
 std::ostream &DumpExprWithType(std::ostream &o, const std::variant<A...> &u) {
@@ -82,7 +184,7 @@ std::ostream &Expr<Type<TypeCategory::Integer, KIND>>::Dump(
       common::visitors{[&](const Scalar<Result> &n) { o << n.SignedDecimal(); },
           [&](const CopyableIndirection<DataRef> &d) { d->Dump(o); },
           [&](const CopyableIndirection<FunctionRef> &d) { d->Dump(o); },
-          [&](const Parentheses &p) { p.Dump(o, "("); },
+          [&](const Parentheses<Result> &p) { p.Dump(o); },
           [&](const Negate &n) { n.Dump(o, "(-"); },
           [&](const Add &a) { a.Dump(o, "+"); },
           [&](const Subtract &s) { s.Dump(o, "-"); },
@@ -107,7 +209,7 @@ std::ostream &Expr<Type<TypeCategory::Real, KIND>>::Dump(
                  [&](const CopyableIndirection<DataRef> &d) { d->Dump(o); },
                  [&](const CopyableIndirection<ComplexPart> &d) { d->Dump(o); },
                  [&](const CopyableIndirection<FunctionRef> &d) { d->Dump(o); },
-                 [&](const Parentheses &p) { p.Dump(o, "("); },
+                 [&](const Parentheses<Result> &p) { p.Dump(o); },
                  [&](const Negate &n) { n.Dump(o, "(-"); },
                  [&](const Add &a) { a.Dump(o, "+"); },
                  [&](const Subtract &s) { s.Dump(o, "-"); },
@@ -134,7 +236,7 @@ std::ostream &Expr<Type<TypeCategory::Complex, KIND>>::Dump(
                               },
                  [&](const CopyableIndirection<DataRef> &d) { d->Dump(o); },
                  [&](const CopyableIndirection<FunctionRef> &d) { d->Dump(o); },
-                 [&](const Parentheses &p) { p.Dump(o, "("); },
+                 [&](const Parentheses<Result> &p) { p.Dump(o); },
                  [&](const Negate &n) { n.Dump(o, "(-"); },
                  [&](const Add &a) { a.Dump(o, "+"); },
                  [&](const Subtract &s) { s.Dump(o, "-"); },
@@ -153,6 +255,7 @@ std::ostream &Expr<Type<TypeCategory::Character, KIND>>::Dump(
   std::visit(common::visitors{[&](const Scalar<Result> &s) {
                                 o << parser::QuoteCharacterLiteral(s);
                               },
+                 //          [&](const Parentheses<Result> &p) { p.Dump(o); },
                  [&](const Concat &concat) { concat.Dump(o, "//"); },
                  [&](const Max &m) { m.Dump(o, ",", "MAX("); },
                  [&](const Min &m) { m.Dump(o, ",", "MIN("); },
@@ -176,6 +279,7 @@ std::ostream &Expr<Type<TypeCategory::Logical, KIND>>::Dump(
                               },
                  [&](const CopyableIndirection<DataRef> &d) { d->Dump(o); },
                  [&](const CopyableIndirection<FunctionRef> &d) { d->Dump(o); },
+                 //          [&](const Parentheses<Result> &p) { p.Dump(o); },
                  [&](const Not &n) { n.Dump(o, "(.NOT."); },
                  [&](const And &a) { a.Dump(o, ".AND."); },
                  [&](const Or &a) { a.Dump(o, ".OR."); },
@@ -395,9 +499,13 @@ auto Expr<Type<TypeCategory::Integer, KIND>>::Fold(FoldingContext &context)
           return {x};
         }
         if constexpr (evaluate::FoldableTrait<Ty>) {
-          auto c{x.Fold(context)};
-          if (c.has_value()) {
-            u_ = *c;
+          if (auto c{x.Fold(context)}) {
+            if constexpr (std::is_same_v<Ty, Parentheses<Result>>) {
+              // Preserve parentheses around constants.
+              u_ = Parentheses<Result>{Expr{*c}};
+            } else {
+              u_ = *c;
+            }
             return c;
           }
         }
@@ -542,8 +650,7 @@ auto Expr<Type<TypeCategory::Real, KIND>>::Fold(FoldingContext &context)
           return {x};
         }
         if constexpr (evaluate::FoldableTrait<Ty>) {
-          auto c{x.Fold(context)};
-          if (c.has_value()) {
+          if (auto c{x.Fold(context)}) {
             if (context.flushDenormalsToZero) {
               *c = c->FlushDenormalToZero();
             }
@@ -639,8 +746,7 @@ auto Expr<Type<TypeCategory::Complex, KIND>>::Fold(FoldingContext &context)
           return {x};
         }
         if constexpr (evaluate::FoldableTrait<Ty>) {
-          auto c{x.Fold(context)};
-          if (c.has_value()) {
+          if (auto c{x.Fold(context)}) {
             if (context.flushDenormalsToZero) {
               *c = c->FlushDenormalToZero();
             }
@@ -693,8 +799,7 @@ auto Expr<Type<TypeCategory::Character, KIND>>::Fold(FoldingContext &context)
           return {x};
         }
         if constexpr (evaluate::FoldableTrait<Ty>) {
-          auto c{x.Fold(context)};
-          if (c.has_value()) {
+          if (auto c{x.Fold(context)}) {
             u_ = *c;
             return c;
           }
@@ -800,8 +905,7 @@ auto Expr<Type<TypeCategory::Logical, KIND>>::Fold(FoldingContext &context)
           return {x};
         }
         if constexpr (evaluate::FoldableTrait<Ty>) {
-          std::optional<Scalar<Result>> c{x.Fold(context)};
-          if (c.has_value()) {
+          if (auto c{x.Fold(context)}) {
             u_ = *c;
             return c;
           }
index a3e302d..a8e2bea 100644 (file)
 #include "../lib/parser/char-block.h"
 #include "../lib/parser/message.h"
 #include <ostream>
+#include <tuple>
 #include <variant>
 
 namespace Fortran::evaluate {
 
 template<typename A> class Expr;
 
+template<typename DERIVED, typename RESULT, typename... OPERAND>
+class Operation {
+private:
+  using OperandTypes = std::tuple<OPERAND...>;
+
+public:
+  using Derived = DERIVED;
+  using Result = RESULT;
+  template<int J> using Operand = std::tuple_element_t<J, OperandTypes>;
+  using FoldableTrait = std::true_type;
+
+  CLASS_BOILERPLATE(Operation)
+  Operation(Expr<OPERAND> &&... x) : operand_{std::move(x)...} {}
+  Operation(const Expr<OPERAND> &... x) : operand_{x...} {}
+
+  DERIVED &derived() { return *static_cast<DERIVED *>(this); }
+  const DERIVED &derived() const { return *static_cast<const DERIVED *>(this); }
+
+  static constexpr auto operands() { return sizeof...(OPERAND); }
+  template<int J> Expr<Operand<J>> &operand() { return *std::get<J>(operand_); }
+  template<int J> const Expr<Operand<J>> &operand() const {
+    return *std::get<J>(operand_);
+  }
+
+  std::optional<Scalar<Result>> Fold(FoldingContext &);  // TODO rank > 0
+
+protected:
+  // Overridable strings for Dump()
+  static constexpr const char *prefix_{"("}, *infix_{""}, *postfix_{")"};
+
+private:
+  std::tuple<CopyableIndirection<Expr<OPERAND>>...> operand_;
+};
+
+template<typename A>
+class Parentheses : public Operation<Parentheses<A>, A, A> {
+  using Base = Operation<Parentheses, A, A>;
+  friend Base;
+  using Base::Base;
+  using typename Base::Result;
+  using Operand = typename Base::template Operand<0>;
+  static std::optional<Scalar<Result>> FoldScalar(
+      FoldingContext &, const Scalar<Operand> &x) {
+    return {x};
+  }
+};
+
+template<typename TO, typename FROM>
+class Convert : public Operation<Convert<TO, FROM>, TO, FROM> {
+  using Base = Operation<Convert<TO, FROM>, TO, FROM>;
+  friend Base;
+  using Base::Base;
+  using typename Base::Result;
+  using Operand = typename Base::template Operand<0>;
+  static std::optional<Scalar<Result>> FoldScalar(
+      FoldingContext &, const Scalar<Operand> &);
+};
+
 // Helper base classes for packaging subexpressions.
 template<typename CRTP, typename RESULT, typename A = RESULT> class Unary {
 public:
@@ -102,13 +161,6 @@ public:
 
   template<typename CRTP> using Un = Unary<CRTP, Result>;
   template<typename CRTP> using Bin = Binary<CRTP, Result>;
-  struct Parentheses : public Un<Parentheses> {
-    using Un<Parentheses>::Un;
-    static std::optional<Scalar<Result>> FoldScalar(
-        FoldingContext &, const Scalar<Result> &x) {
-      return {x};
-    }
-  };
   struct Negate : public Un<Negate> {
     using Un<Negate>::Un;
     static std::optional<Scalar<Result>> FoldScalar(
@@ -189,7 +241,8 @@ public:
 private:
   std::variant<Scalar<Result>, CopyableIndirection<DataRef>,
       CopyableIndirection<FunctionRef>, ConvertInteger, ConvertReal,
-      Parentheses, Negate, Add, Subtract, Multiply, Divide, Power, Max, Min>
+      Parentheses<Result>, Negate, Add, Subtract, Multiply, Divide, Power, Max,
+      Min>
       u_;
 };
 
@@ -213,13 +266,6 @@ public:
   };
   template<typename CRTP> using Un = Unary<CRTP, Result>;
   template<typename CRTP> using Bin = Binary<CRTP, Result>;
-  struct Parentheses : public Un<Parentheses> {
-    using Un<Parentheses>::Un;
-    static std::optional<Scalar<Result>> FoldScalar(
-        FoldingContext &, const Scalar<Result> &x) {
-      return {x};
-    }
-  };
   struct Negate : public Un<Negate> {
     using Un<Negate>::Un;
     static std::optional<Scalar<Result>> FoldScalar(
@@ -311,8 +357,8 @@ public:
 private:
   std::variant<Scalar<Result>, CopyableIndirection<DataRef>,
       CopyableIndirection<ComplexPart>, CopyableIndirection<FunctionRef>,
-      ConvertInteger, ConvertReal, Parentheses, Negate, Add, Subtract, Multiply,
-      Divide, Power, IntPower, Max, Min, RealPart, AIMAG>
+      ConvertInteger, ConvertReal, Parentheses<Result>, Negate, Add, Subtract,
+      Multiply, Divide, Power, IntPower, Max, Min, RealPart, AIMAG>
       u_;
 };
 
@@ -323,13 +369,6 @@ public:
 
   template<typename CRTP> using Un = Unary<CRTP, Result>;
   template<typename CRTP> using Bin = Binary<CRTP, Result>;
-  struct Parentheses : public Un<Parentheses> {
-    using Un<Parentheses>::Un;
-    static std::optional<Scalar<Result>> FoldScalar(
-        FoldingContext &, const Scalar<Result> &x) {
-      return {x};
-    }
-  };
   struct Negate : public Un<Negate> {
     using Un<Negate>::Un;
     static std::optional<Scalar<Result>> FoldScalar(
@@ -388,8 +427,8 @@ public:
 
 private:
   std::variant<Scalar<Result>, CopyableIndirection<DataRef>,
-      CopyableIndirection<FunctionRef>, Parentheses, Negate, Add, Subtract,
-      Multiply, Divide, Power, IntPower, CMPLX>
+      CopyableIndirection<FunctionRef>, Parentheses<Result>, Negate, Add,
+      Subtract, Multiply, Divide, Power, IntPower, CMPLX>
       u_;
 };
 
@@ -431,8 +470,9 @@ public:
 
 private:
   std::variant<Scalar<Result>, CopyableIndirection<DataRef>,
-      CopyableIndirection<Substring>, CopyableIndirection<FunctionRef>, Concat,
-      Max, Min>
+      CopyableIndirection<Substring>, CopyableIndirection<FunctionRef>,
+      //      Parentheses<Result>,
+      Concat, Max, Min>
       u_;
 };
 
@@ -541,8 +581,9 @@ public:
 
 private:
   std::variant<Scalar<Result>, CopyableIndirection<DataRef>,
-      CopyableIndirection<FunctionRef>, Not, And, Or, Eqv, Neqv,
-      CategoryComparison<TypeCategory::Integer>,
+      CopyableIndirection<FunctionRef>,
+      //      Parentheses<Result>,
+      Not, And, Or, Eqv, Neqv, CategoryComparison<TypeCategory::Integer>,
       CategoryComparison<TypeCategory::Real>,
       CategoryComparison<TypeCategory::Complex>,
       CategoryComparison<TypeCategory::Character>>
@@ -634,11 +675,7 @@ template<typename A> using ResultType = typename std::decay_t<A>::Result;
 // These definitions are created with temporary helper macros to reduce
 // C++ boilerplate.  All combinations of lvalue and rvalue references are
 // allowed for operands.
-#define UNARY(FUNC, CONSTR) \
-  template<typename A> A FUNC(const A &x) { return {typename A::CONSTR{x}}; }
-UNARY(Parentheses, Parentheses)
-UNARY(operator-, Negate)
-#undef UNARY
+template<typename A> A operator-(const A &x) { return {typename A::Negate{x}}; }
 
 #define BINARY(FUNC, CONSTR) \
   template<typename A> A FUNC(const A &x, const A &y) { \
index c831f8e..a2bf598 100644 (file)
@@ -35,9 +35,11 @@ namespace Fortran::evaluate {
 
 using common::TypeCategory;
 
+// Specific intrinsic types
+
 template<TypeCategory C, int KIND> struct TypeBase {
+  static constexpr bool knowKind{true};
   static constexpr TypeCategory category{C};
-  static constexpr TypeCategory GetCategory() { return C; };
   static constexpr int kind{KIND};
   static constexpr bool hasLen{false};
   static std::string Dump() {
@@ -253,8 +255,9 @@ struct GenericScalar {
 
 // Represents a type of any supported kind within a particular category.
 template<TypeCategory CAT> struct SomeKind {
-  static constexpr TypeCategory category{CAT};
+  static constexpr bool knowKind{false};
   using Scalar = SomeKindScalar<CAT>;
+  static constexpr TypeCategory category{CAT};
 };
 
 using SomeInteger = SomeKind<TypeCategory::Integer>;
@@ -265,6 +268,7 @@ using SomeLogical = SomeKind<TypeCategory::Logical>;
 
 // Represents a completely generic type.
 struct SomeType {
+  static constexpr bool knowKind{false};
   using Scalar = GenericScalar;
 };