[flang] begin testing reals
authorpeter klausler <pklausler@nvidia.com>
Tue, 5 Jun 2018 23:29:26 +0000 (16:29 -0700)
committerpeter klausler <pklausler@nvidia.com>
Thu, 14 Jun 2018 20:52:44 +0000 (13:52 -0700)
Original-commit: flang-compiler/f18@9d261b594bbf2a6dcec833239635599b28007e4d
Reviewed-on: https://github.com/flang-compiler/f18/pull/101
Tree-same-pre-rewrite: false

flang/CMakeLists.txt
flang/lib/evaluate/real.h
flang/test/evaluate/CMakeLists.txt
flang/test/evaluate/real.cc [new file with mode: 0644]

index 499afc5..22556ff 100644 (file)
@@ -108,3 +108,4 @@ enable_testing()
 add_test(NAME Leadz COMMAND leading-zero-bit-count-test)
 add_test(NAME PopPar COMMAND bit-population-count-test)
 add_test(NAME Integer COMMAND integer-test)
+add_test(NAME Real COMMAND real-test)
index d2221fb..7e6e91c 100644 (file)
@@ -40,29 +40,31 @@ public:
   constexpr Real() {}  // +0.0
   constexpr Real(const Real &) = default;
   constexpr Real &operator=(const Real &) = default;
+  constexpr Real(const Word &bits) : word_{bits} {}
 
   template<typename INT>
   static constexpr ValueWithRealFlags<Real> ConvertSigned(
       const INT &n, Rounding rounding = Rounding::TiesToEven) {
     bool isNegative{n.IsNegative()};
+    INT absN{n};
     if (isNegative) {
-      n = n.Negate().value;  // overflow is okay
+      absN = n.Negate().value;  // overflow is safe to ignore
     }
-    int leadz{n.LEADZ()};
-    if (leadz >= n.bits) {
+    int leadz{absN.LEADZ()};
+    if (leadz >= absN.bits) {
       return {};  // all bits zero -> +0.0
     }
     ValueWithRealFlags<Real> result;
-    int exponent{exponentBias + n.bits - leadz - 1};
-    int bitsNeeded{n.bits - (leadz + implicitMSB)};
+    std::uint64_t exponent{exponentBias + absN.bits - leadz - 1};
+    int bitsNeeded{absN.bits - (leadz + implicitMSB)};
     int bitsLost{bitsNeeded - significandBits};
     if (bitsLost <= 0) {
-      Fraction fraction{Fraction::Convert(n).value};
+      Fraction fraction{Fraction::Convert(absN).value};
       result.flags |= result.value.Normalize(
           isNegative, exponent, fraction.SHIFTL(-bitsLost));
     } else {
-      RoundingBits roundingBits{GetRoundingBits(n, bitsLost)};
-      Fraction fraction{Fraction::Convert(n.SHIFTR(bitsLost)).value};
+      RoundingBits roundingBits{GetRoundingBits(absN, bitsLost)};
+      Fraction fraction{Fraction::Convert(absN.SHIFTR(bitsLost)).value};
       result.flags |= result.value.Normalize(isNegative, exponent, fraction);
       result.flags |= result.value.Round(rounding, roundingBits);
     }
@@ -74,10 +76,15 @@ public:
   // HUGE, INT/NINT, MAXEXPONENT, MINEXPONENT, NEAREST, OUT_OF_RANGE,
   // PRECISION, HUGE, TINY, RRSPACING/SPACING, SCALE, SET_EXPONENT, SIGN
 
+  constexpr Word RawBits() const {
+    return word_;
+  }
   constexpr std::uint64_t Exponent() const {
     return word_.IBITS(significandBits, exponentBits).ToUInt64();
   }
-  constexpr bool IsNegative() const { return word_.BTEST(bits - 1); }
+  constexpr bool IsNegative() const {
+    return !IsNotANumber() && word_.BTEST(bits - 1);
+  }
   constexpr bool IsNotANumber() const {
     return Exponent() == maxExponent && !GetSignificand().IsZero();
   }
@@ -158,7 +165,7 @@ public:
         result.value = result.value.HUGE();
       } else if (isNegative) {
         auto negated = result.value.Negate();
-        if (result.overflow) {
+        if (negated.overflow) {
           result.flags |= RealFlag::Overflow;
           result.value = result.value.HUGE();
         } else {
@@ -369,8 +376,8 @@ private:
     }
   }
 
-  static constexpr RoundingBits GetRoundingBits(
-      const Fraction &fraction, int rshift) {
+  template<typename INT>
+  static constexpr RoundingBits GetRoundingBits(const INT &fraction, int rshift) {
     RoundingBits roundingBits;
     if (rshift > fraction.bits) {
       roundingBits.guard = !fraction.IsZero();
@@ -392,16 +399,10 @@ private:
       bool negative, std::uint64_t biasedExponent, const Fraction &fraction) {
     if (biasedExponent >= maxExponent) {
       word_ = Word{maxExponent}.SHIFTL(significandBits);
-      if (fraction.IsZero()) {
-        // infinity
-        if (negative) {
-          word_ = word_.IBSET(bits - 1);
-        }
-        return RealFlag::Ok;
-      } else {
-        word_ = NaNWord();
-        return RealFlag::InvalidArgument;
+      if (negative) {
+        word_ = word_.IBSET(bits - 1);
       }
+      return RealFlag::Overflow;
     } else {
       std::uint64_t leadz = fraction.LEADZ();
       if (leadz >= precision) {
@@ -415,7 +416,7 @@ private:
         if (implicitMSB) {
           word_ = word_.IBCLR(significandBits);
         }
-        word_.IOR(Word{biasedExponent - leadz}.SHIFTL(significandBits));
+        word_ = word_.IOR(Word{biasedExponent - leadz}.SHIFTL(significandBits));
       }
       if (negative) {
         word_ = word_.IBSET(bits - 1);
index 4009641..3334f3c 100644 (file)
@@ -42,3 +42,12 @@ target_link_libraries(integer-test
   FortranEvaluate
   FortranEvaluateTesting
 )
+
+add_executable(real-test
+  real.cc
+)
+
+target_link_libraries(real-test
+  FortranEvaluate
+  FortranEvaluateTesting
+)
diff --git a/flang/test/evaluate/real.cc b/flang/test/evaluate/real.cc
new file mode 100644 (file)
index 0000000..7f51d3e
--- /dev/null
@@ -0,0 +1,126 @@
+// 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.
+
+#include "../../lib/evaluate/integer.h"
+#include "../../lib/evaluate/real.h"
+#include "testing.h"
+#include <cstdio>
+
+using Fortran::evaluate::Integer;
+using Fortran::evaluate::Ordering;
+using Fortran::evaluate::Real;
+using Fortran::evaluate::Relation;
+using Fortran::evaluate::ValueWithRealFlags;
+
+template<typename R> void tests() {
+  char desc[64];
+  using Word = typename R::Word;
+  std::snprintf(desc, sizeof desc, "bits=%d, le=%d",
+               R::bits, Word::littleEndian);
+  R zero;
+  TEST(!zero.IsNegative())(desc);
+  TEST(!zero.IsNotANumber())(desc);
+  TEST(!zero.IsInfinite())(desc);
+  TEST(zero.IsZero())(desc);
+  MATCH(0, zero.Exponent())(desc);
+  TEST(zero.RawBits().IsZero())(desc);
+  MATCH(0, zero.RawBits().ToUInt64())(desc);
+  TEST(zero.ABS().RawBits().IsZero())(desc);
+  TEST(zero.Negate().RawBits().IEOR(Word::MASKL(1)).IsZero())(desc);
+  TEST(zero.Compare(zero) == Relation::Equal)(desc);
+  R minusZero{Word{std::uint64_t{1}}.SHIFTL(R::bits - 1)};
+  TEST(minusZero.IsNegative())(desc);
+  TEST(!minusZero.IsNotANumber())(desc);
+  TEST(!minusZero.IsInfinite())(desc);
+  TEST(minusZero.IsZero())(desc);
+  TEST(minusZero.ABS().RawBits().IsZero())(desc);
+  TEST(minusZero.Negate().RawBits().IsZero())(desc);
+  MATCH(0, minusZero.Exponent())(desc);
+  MATCH(0, minusZero.RawBits().LEADZ())(desc);
+  MATCH(1, minusZero.RawBits().POPCNT())(desc);
+  TEST(minusZero.Compare(minusZero) == Relation::Equal)(desc);
+  TEST(zero.Compare(minusZero) == Relation::Equal)(desc);
+  ValueWithRealFlags<R> vr;
+  MATCH(0, vr.value.RawBits().ToUInt64())(desc);
+  MATCH(0, vr.flags)(desc);
+  R nan{Word{std::uint64_t{1}}.SHIFTL(R::bits).SubtractSigned(Word{std::uint64_t{1}}).value};
+  MATCH(R::bits, nan.RawBits().POPCNT())(desc);
+  TEST(!nan.IsNegative())(desc);
+  TEST(nan.IsNotANumber())(desc);
+  TEST(!nan.IsInfinite())(desc);
+  TEST(!nan.IsZero())(desc);
+  TEST(zero.Compare(nan) == Relation::Unordered)(desc);
+  TEST(minusZero.Compare(nan) == Relation::Unordered)(desc);
+  TEST(nan.Compare(zero) == Relation::Unordered)(desc);
+  TEST(nan.Compare(minusZero) == Relation::Unordered)(desc);
+  TEST(nan.Compare(nan) == Relation::Unordered)(desc);
+  int significandBits{R::precision - R::implicitMSB};
+  int exponentBits{R::bits - significandBits - 1};
+  std::uint64_t maxExponent{(std::uint64_t{1} << exponentBits) - 1};
+  MATCH(nan.Exponent(), maxExponent)(desc);
+  R inf{Word{maxExponent}.SHIFTL(significandBits)};
+  TEST(!inf.IsNegative())(desc);
+  TEST(!inf.IsNotANumber())(desc);
+  TEST(inf.IsInfinite())(desc);
+  TEST(!inf.IsZero())(desc);
+  TEST(inf.RawBits().CompareUnsigned(inf.ABS().RawBits()) == Ordering::Equal)(desc);
+  TEST(zero.Compare(inf) == Relation::Less)(desc);
+  TEST(minusZero.Compare(inf) == Relation::Less)(desc);
+  TEST(nan.Compare(inf) == Relation::Unordered)(desc);
+  TEST(inf.Compare(inf) == Relation::Equal)(desc);
+  R negInf{Word{maxExponent}.SHIFTL(significandBits).IOR(Word::MASKL(1))};
+  TEST(negInf.IsNegative())(desc);
+  TEST(!negInf.IsNotANumber())(desc);
+  TEST(negInf.IsInfinite())(desc);
+  TEST(!negInf.IsZero())(desc);
+  TEST(inf.RawBits().CompareUnsigned(negInf.ABS().RawBits()) == Ordering::Equal)(desc);
+  TEST(inf.RawBits().CompareUnsigned(negInf.Negate().RawBits()) == Ordering::Equal)(desc);
+  TEST(inf.Negate().RawBits().CompareUnsigned(negInf.RawBits()) == Ordering::Equal)(desc);
+  TEST(zero.Compare(negInf) == Relation::Greater)(desc);
+  TEST(minusZero.Compare(negInf) == Relation::Greater)(desc);
+  TEST(nan.Compare(negInf) == Relation::Unordered)(desc);
+  TEST(inf.Compare(negInf) == Relation::Greater)(desc);
+  TEST(negInf.Compare(negInf) == Relation::Equal)(desc);
+  for (std::uint64_t j{0}; j < 63; ++j) {
+    std::uint64_t x{1};
+    x <<= j;
+    Integer<64> ix{x};
+    MATCH(x, ix.ToUInt64())("%s,%d,0x%llx",desc,j,x);
+    vr = R::ConvertSigned(ix);
+    TEST(!vr.value.IsNegative())("%s,%d,0x%llx",desc,j,x);
+    TEST(!vr.value.IsNotANumber())("%s,%d,0x%llx",desc,j,x);
+    TEST(!vr.value.IsZero())("%s,%d,0x%llx",desc,j,x);
+    auto ivf = vr.value.template ToInteger<Integer<64>>();
+    if (j > (maxExponent / 2)) {
+      MATCH(Fortran::evaluate::RealFlag::Overflow, vr.flags)(desc);
+      TEST(vr.value.IsInfinite())("%s,%d,0x%llx",desc,j,x);
+      MATCH(Fortran::evaluate::RealFlag::Overflow, ivf.flags)("%s,%d,0x%llx",desc,j,x);
+      MATCH(0x7fffffffffffffff, ivf.value.ToUInt64())("%s,%d,0x%llx",desc,j,x);
+    } else {
+      MATCH(Fortran::evaluate::RealFlag::Ok, vr.flags)(desc);
+      TEST(!vr.value.IsInfinite())("%s,%d,0x%llx",desc,j,x);
+      MATCH(Fortran::evaluate::RealFlag::Ok, ivf.flags)("%s,%d,0x%llx",desc,j,x);
+      MATCH(x, ivf.value.ToUInt64())("%s,%d,0x%llx",desc,j,x);
+    }
+  }
+}
+
+int main() {
+  tests<Real<Integer<16>, 11>>();
+  tests<Real<Integer<32>, 24>>();
+  tests<Real<Integer<64>, 53>>();
+  tests<Real<Integer<80>, 64, false>>();
+  tests<Real<Integer<128>, 112>>();
+  return testing::Complete();
+}