[flang] begin real.h
authorpeter klausler <pklausler@nvidia.com>
Fri, 1 Jun 2018 22:30:31 +0000 (15:30 -0700)
committerpeter klausler <pklausler@nvidia.com>
Thu, 14 Jun 2018 20:52:37 +0000 (13:52 -0700)
Original-commit: flang-compiler/f18@b0f0cd896161d769efc3f499cd3ae1359c82953a
Reviewed-on: https://github.com/flang-compiler/f18/pull/101
Tree-same-pre-rewrite: false

flang/lib/evaluate/common.h
flang/lib/evaluate/integer.h
flang/lib/evaluate/real.h [new file with mode: 0644]

index 67c4f54..c62223e 100644 (file)
@@ -33,6 +33,16 @@ static constexpr Ordering Reverse(Ordering ordering) {
   }
 }
 
+static constexpr Relation RelationFromOrdering(Ordering ordering) {
+  if (ordering == Ordering::Less) {
+    return Relation::Less;
+  } else if (ordering == Ordering::Greater) {
+    return Relation::Greater;
+  } else {
+    return Relation::Equal;
+  }
+}
+
 static constexpr Relation Reverse(Relation relation) {
   if (relation == Relation::Less) {
     return Relation::Greater;
index 63de0e2..a9e1932 100644 (file)
@@ -191,6 +191,8 @@ public:
     return {result, overflow};
   }
 
+  // TODO formatting
+
   static constexpr Integer HUGE() { return MASKR(bits - 1); }
 
   // Returns the number of full decimal digits that can be represented.
diff --git a/flang/lib/evaluate/real.h b/flang/lib/evaluate/real.h
new file mode 100644 (file)
index 0000000..c0d68b1
--- /dev/null
@@ -0,0 +1,120 @@
+// Copyright (c) 2018, NVIDIA CORPORATION.  All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef FORTRAN_EVALUATE_REAL_H_
+#define FORTRAN_EVALUATE_REAL_H_
+
+#include "common.h"
+#include "integer.h"
+#include <cinttypes>
+
+namespace Fortran::evaluate {
+
+// The class template parameter specifies the total number of bits in the
+// significand, including any bit that might be implicit in a machine
+// representation.
+template<int SIGNIFICAND_BITS> class Real {
+public:
+  static constexpr int significandBits{SIGNIFICAND_BITS};
+  static_assert(significandBits > 0);
+
+  constexpr Real() {}  // +0.0
+  constexpr Real(std::int64_t n)
+      : significand_{n}, exponent_{64}, negative_{n < 0} {
+    if (negative_) {
+      significand_ = significand_.Negate().value;  // overflow is safe to ignore
+    }
+    Normalize();
+  }
+
+  constexpr bool IsNegative() const { return negative_ && !notANumber_; }
+  constexpr bool IsFinite() const { return !infinite_ && !notANumber_; }
+  constexpr bool IsInfinite() const { return infinite_ && !notANumber_; }
+  constexpr bool IsANumber() const { return !notANumber_; }
+  constexpr bool IsNotANumber() const { return notANumber_; }
+  constexpr bool IsZero() const { return !notANumber_ && significand_.IsZero(); }
+
+  constexpr Relation Compare(const Real &y) const {
+    if (notANumber_ || y.notANumber_) {
+      return Relation::Unordered;
+    } else if (infinite_) {
+      if (y.infinite_) {
+        if (negative_) {
+          return y.negative_ ? Relation::Equal : Relation::Less;
+        } else {
+          return y.negative_ ? Relation::Greater : Relation::Equal;
+        }
+      } else {
+        return negative_ ? Relation::Less : Relation::Greater;
+      }
+    } else if (y.infinite_) {
+      return y.negative_ ? Relation::Greater : Relation::Less;
+    } else {
+      // two finite numbers
+      if (exponent_ == y.exponent_) {
+        Ordering order{significand_.CompareUnsigned(y.significand_)};
+        if (order == Ordering::Equal) {
+          if (negative_ == y.negative_ ||
+              (exponent_ == 0 && significand_.IsZero())) {
+            // Ignore signs on zeros, +0.0 == -0.0
+            return Relation::Equal;
+          } else {
+            // finite nonzero numbers, same exponent & significand
+            return negative_ ? Relation::Less : Relation::Greater;
+          }
+        } else {
+          // finite numbers, same exponent, distinct significands
+          if (negative_ != y.negative_) {
+            return negative_ ? Relation::Less : Relation::Greater;
+          } else {
+            return RelationFromOrdering(order);
+          }
+        }
+      } else {
+        // not same exponent
+        if (negative_ != y.negative_) {
+          return negative_ ? Relation::Less : Relation::Greater;
+        } else {
+          return exponent_ < y.exponent_ ? Relation::Less : Relation::Greater;
+        }
+      }
+    }
+  }
+
+private:
+  using Significand = Integer<significandBits>;
+  using DoubleSignificand = Integer<2 * significandBits>;
+
+  // All values are normalized on output and assumed normal on input.
+  void Normalize() {
+    if (!notANumber_ && !infinite_) {
+      int shift{significand_.LEADZ()};
+      if (shift >= significandBits) {
+        exponent_ = 0;  // +/-0.0
+      } else {
+        exponent_ -= shift;
+        significand_ = significand_.SHIFTL(shift);
+      }
+    }
+  }
+
+  Significand significand_{};
+  int exponent_{0};  // unbiased; 1.0 has exponent 1
+  bool negative_{false};
+  bool infinite_{false};
+  bool notANumber_{false};
+};
+
+}  // namespace Fortran::evaluate
+#endif  // FORTRAN_EVALUATE_REAL_H_