[flang] More real work. All ops, rounding modes, and flags good except for division.
Original-commit: flang-compiler/f18@ea697295db Reviewed-on: https://github.com/flang-compiler/f18/pull/101 Tree-same-pre-rewrite: false
This commit is contained in:
		
							parent
							
								
									fab448de59
								
							
						
					
					
						commit
						52ef92b513
					
				| 
						 | 
				
			
			@ -267,8 +267,11 @@ public:
 | 
			
		|||
        return y.Add(*this, rounding);
 | 
			
		||||
      }
 | 
			
		||||
      if (order == Ordering::Equal) {
 | 
			
		||||
        // x + (-x) -> +0.0, never -0.0
 | 
			
		||||
        return {};
 | 
			
		||||
        // x + (-x) -> +0.0 unless rounding is directed downwards
 | 
			
		||||
        if (rounding == Rounding::Down) {
 | 
			
		||||
          result.value.Normalize(true, 0, Fraction{}, rounding);  // -0.0
 | 
			
		||||
        }
 | 
			
		||||
        return result;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    // Our exponent is greater than y's, or the exponents match and y is not
 | 
			
		||||
| 
						 | 
				
			
			@ -296,8 +299,8 @@ public:
 | 
			
		|||
      fraction = fraction.SHIFTR(1).IBSET(fraction.bits - 1);
 | 
			
		||||
      ++exponent;
 | 
			
		||||
    }
 | 
			
		||||
    result.flags |=
 | 
			
		||||
        result.value.Normalize(isNegative, exponent, fraction, &roundingBits);
 | 
			
		||||
    result.flags |= result.value.Normalize(
 | 
			
		||||
        isNegative, exponent, fraction, rounding, &roundingBits);
 | 
			
		||||
    result.flags |= result.value.Round(rounding, roundingBits);
 | 
			
		||||
    return result;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -312,7 +315,9 @@ public:
 | 
			
		|||
    ValueWithRealFlags<Real> result;
 | 
			
		||||
    if (IsNotANumber() || y.IsNotANumber()) {
 | 
			
		||||
      result.value.word_ = NaNWord();  // NaN * x -> NaN
 | 
			
		||||
      if (IsSignalingNaN() || y.IsSignalingNaN()) {
 | 
			
		||||
        result.flags.set(RealFlag::InvalidArgument);
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      bool isNegative{IsNegative() != y.IsNegative()};
 | 
			
		||||
      if (IsInfinite() || y.IsInfinite()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -338,7 +343,10 @@ public:
 | 
			
		|||
          if (rshift >= product.upper.bits + product.lower.bits) {
 | 
			
		||||
            sticky = !product.lower.IsZero() || !product.upper.IsZero();
 | 
			
		||||
          } else if (rshift >= product.lower.bits) {
 | 
			
		||||
            sticky = !product.lower.IsZero();
 | 
			
		||||
            sticky = !product.lower.IsZero() ||
 | 
			
		||||
                !product.upper
 | 
			
		||||
                     .IAND(product.upper.MASKR(rshift - product.lower.bits))
 | 
			
		||||
                     .IsZero();
 | 
			
		||||
          } else {
 | 
			
		||||
            sticky = !product.lower.IAND(product.lower.MASKR(rshift)).IsZero();
 | 
			
		||||
          }
 | 
			
		||||
| 
						 | 
				
			
			@ -359,10 +367,14 @@ public:
 | 
			
		|||
        exponent -= lshift;
 | 
			
		||||
        product.upper = product.upper.DSHIFTL(product.lower, lshift);
 | 
			
		||||
        product.lower = product.lower.SHIFTL(lshift);
 | 
			
		||||
        RoundingBits roundingBits{product.lower, product.upper.bits};
 | 
			
		||||
        RoundingBits roundingBits{product.lower, product.lower.bits};
 | 
			
		||||
        result.flags |= result.value.Normalize(
 | 
			
		||||
            isNegative, exponent, product.upper, &roundingBits);
 | 
			
		||||
            isNegative, exponent, product.upper, rounding, &roundingBits);
 | 
			
		||||
        result.flags |= result.value.Round(rounding, roundingBits);
 | 
			
		||||
        if (result.flags.test(RealFlag::Inexact) &&
 | 
			
		||||
            result.value.Exponent() == 0) {
 | 
			
		||||
          result.flags.set(RealFlag::Underflow);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return result;
 | 
			
		||||
| 
						 | 
				
			
			@ -514,9 +526,19 @@ private:
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  constexpr RealFlags Normalize(bool negative, std::uint64_t exponent,
 | 
			
		||||
      const Fraction &fraction, RoundingBits *roundingBits = nullptr) {
 | 
			
		||||
      const Fraction &fraction, Rounding rounding = Rounding::TiesToEven,
 | 
			
		||||
      RoundingBits *roundingBits = nullptr) {
 | 
			
		||||
    if (exponent >= maxExponent) {
 | 
			
		||||
      if (rounding == Rounding::TiesToEven ||
 | 
			
		||||
          rounding == Rounding::TiesAwayFromZero ||
 | 
			
		||||
          (rounding == Rounding::Up && !negative) ||
 | 
			
		||||
          (rounding == Rounding::Down && negative)) {
 | 
			
		||||
        word_ = Word{maxExponent}.SHIFTL(significandBits);  // Inf
 | 
			
		||||
      } else {
 | 
			
		||||
        // directed rounding: round to largest finite value rather than infinity
 | 
			
		||||
        // (x86 does this, not sure whether it's standard or not)
 | 
			
		||||
        word_ = Word{word_.MASKR(word_.bits - 1)}.IBCLR(significandBits);
 | 
			
		||||
      }
 | 
			
		||||
      if (negative) {
 | 
			
		||||
        word_ = word_.IBSET(bits - 1);
 | 
			
		||||
      }
 | 
			
		||||
| 
						 | 
				
			
			@ -608,7 +630,7 @@ extern template class Real<Integer<32>, 24>;
 | 
			
		|||
using RealKind8 = Real<Integer<64>, 53>;
 | 
			
		||||
extern template class Real<Integer<64>, 53>;
 | 
			
		||||
 | 
			
		||||
using RealKind10 = Real<Integer<80>, 64, false>;  // 80387
 | 
			
		||||
using RealKind10 = Real<Integer<80>, 64, false>;  // 80387 extended precision
 | 
			
		||||
extern template class Real<Integer<80>, 64, false>;
 | 
			
		||||
 | 
			
		||||
using RealKind16 = Real<Integer<128>, 112>;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -63,7 +63,7 @@ void ScopedHostFloatingPointEnvironment::ClearFlags() const {
 | 
			
		|||
  feclearexcept(FE_ALL_EXCEPT);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RealFlags ScopedHostFloatingPointEnvironment::CurrentFlags() const {
 | 
			
		||||
RealFlags ScopedHostFloatingPointEnvironment::CurrentFlags() {
 | 
			
		||||
  int exceptions = fetestexcept(FE_ALL_EXCEPT);
 | 
			
		||||
  RealFlags flags;
 | 
			
		||||
  if (exceptions & FE_INVALID) {
 | 
			
		||||
| 
						 | 
				
			
			@ -83,3 +83,16 @@ RealFlags ScopedHostFloatingPointEnvironment::CurrentFlags() const {
 | 
			
		|||
  }
 | 
			
		||||
  return flags;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ScopedHostFloatingPointEnvironment::SetRounding(Rounding rounding) {
 | 
			
		||||
  switch (rounding) {
 | 
			
		||||
  case Rounding::TiesToEven: fesetround(FE_TONEAREST); break;
 | 
			
		||||
  case Rounding::ToZero: fesetround(FE_TOWARDZERO); break;
 | 
			
		||||
  case Rounding::Up: fesetround(FE_UPWARD); break;
 | 
			
		||||
  case Rounding::Down: fesetround(FE_DOWNWARD); break;
 | 
			
		||||
  case Rounding::TiesAwayFromZero:
 | 
			
		||||
    std::fprintf(stderr, "SetRounding: TiesAwayFromZero not available");
 | 
			
		||||
    std::abort();
 | 
			
		||||
    break;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,6 +19,7 @@
 | 
			
		|||
#include <fenv.h>
 | 
			
		||||
 | 
			
		||||
using Fortran::evaluate::RealFlags;
 | 
			
		||||
using Fortran::evaluate::Rounding;
 | 
			
		||||
 | 
			
		||||
class ScopedHostFloatingPointEnvironment {
 | 
			
		||||
public:
 | 
			
		||||
| 
						 | 
				
			
			@ -26,7 +27,8 @@ public:
 | 
			
		|||
      bool flushDenormalResultsToZero = false);
 | 
			
		||||
  ~ScopedHostFloatingPointEnvironment();
 | 
			
		||||
  void ClearFlags() const;
 | 
			
		||||
  RealFlags CurrentFlags() const;
 | 
			
		||||
  static RealFlags CurrentFlags();
 | 
			
		||||
  static void SetRounding(Rounding rounding);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
  fenv_t originalFenv_;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,7 +20,7 @@
 | 
			
		|||
 | 
			
		||||
using namespace Fortran::evaluate;
 | 
			
		||||
 | 
			
		||||
template<typename R> void tests() {
 | 
			
		||||
template<typename R> void basicTests(int rm, Rounding rounding) {
 | 
			
		||||
  char desc[64];
 | 
			
		||||
  using Word = typename R::Word;
 | 
			
		||||
  std::snprintf(
 | 
			
		||||
| 
						 | 
				
			
			@ -99,51 +99,52 @@ template<typename R> void tests() {
 | 
			
		|||
  TEST(inf.Compare(negInf) == Relation::Greater)(desc);
 | 
			
		||||
  TEST(negInf.Compare(negInf) == Relation::Equal)(desc);
 | 
			
		||||
  for (std::uint64_t j{0}; j < 63; ++j) {
 | 
			
		||||
    char ldesc[128];
 | 
			
		||||
    std::uint64_t x{1};
 | 
			
		||||
    x <<= j;
 | 
			
		||||
    std::snprintf(ldesc, sizeof ldesc, "%s j=%d x=0x%llx rm=%d", desc,
 | 
			
		||||
        static_cast<int>(j), static_cast<unsigned long long>(x), rm);
 | 
			
		||||
    Integer<64> ix{x};
 | 
			
		||||
    TEST(!ix.IsNegative())("%s,%d,0x%llx", desc, j, 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);
 | 
			
		||||
    TEST(!ix.IsNegative())(ldesc);
 | 
			
		||||
    MATCH(x, ix.ToUInt64())(ldesc);
 | 
			
		||||
    vr = R::ConvertSigned(ix, rounding);
 | 
			
		||||
    TEST(!vr.value.IsNegative())(ldesc);
 | 
			
		||||
    TEST(!vr.value.IsNotANumber())(ldesc);
 | 
			
		||||
    TEST(!vr.value.IsZero())(ldesc);
 | 
			
		||||
    auto ivf = vr.value.template ToInteger<Integer<64>>();
 | 
			
		||||
    if (j > (maxExponent / 2)) {
 | 
			
		||||
      TEST(vr.flags.test(RealFlag::Overflow))(desc);
 | 
			
		||||
      TEST(vr.value.IsInfinite())("%s,%d,0x%llx", desc, j, x);
 | 
			
		||||
      TEST(ivf.flags.test(RealFlag::Overflow))("%s,%d,0x%llx", desc, j, x);
 | 
			
		||||
      MATCH(0x7fffffffffffffff, ivf.value.ToUInt64())
 | 
			
		||||
      ("%s,%d,0x%llx", desc, j, x);
 | 
			
		||||
      TEST(vr.flags.test(RealFlag::Overflow))(ldesc);
 | 
			
		||||
      TEST(vr.value.IsInfinite())(ldesc);
 | 
			
		||||
      TEST(ivf.flags.test(RealFlag::Overflow))(ldesc);
 | 
			
		||||
      MATCH(0x7fffffffffffffff, ivf.value.ToUInt64())(ldesc);
 | 
			
		||||
    } else {
 | 
			
		||||
      TEST(vr.flags.empty())(desc);
 | 
			
		||||
      TEST(!vr.value.IsInfinite())("%s,%d,0x%llx", desc, j, x);
 | 
			
		||||
      TEST(ivf.flags.empty())("%s,%d,0x%llx", desc, j, x);
 | 
			
		||||
      MATCH(x, ivf.value.ToUInt64())("%s,%d,0x%llx", desc, j, x);
 | 
			
		||||
      TEST(vr.flags.empty())(ldesc);
 | 
			
		||||
      TEST(!vr.value.IsInfinite())(ldesc);
 | 
			
		||||
      TEST(ivf.flags.empty())(ldesc);
 | 
			
		||||
      MATCH(x, ivf.value.ToUInt64())(ldesc);
 | 
			
		||||
    }
 | 
			
		||||
    ix = ix.Negate().value;
 | 
			
		||||
    TEST(ix.IsNegative())("%s,%d,0x%llx", desc, j, x);
 | 
			
		||||
    TEST(ix.IsNegative())(ldesc);
 | 
			
		||||
    x = -x;
 | 
			
		||||
    std::int64_t nx = x;
 | 
			
		||||
    MATCH(x, ix.ToUInt64())("%s,%d,0x%llx", desc, j, x);
 | 
			
		||||
    MATCH(nx, ix.ToInt64())("%s,%d,0x%llx", desc, j, x);
 | 
			
		||||
    MATCH(x, ix.ToUInt64())(ldesc);
 | 
			
		||||
    MATCH(nx, ix.ToInt64())(ldesc);
 | 
			
		||||
    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);
 | 
			
		||||
    TEST(vr.value.IsNegative())(ldesc);
 | 
			
		||||
    TEST(!vr.value.IsNotANumber())(ldesc);
 | 
			
		||||
    TEST(!vr.value.IsZero())(ldesc);
 | 
			
		||||
    ivf = vr.value.template ToInteger<Integer<64>>();
 | 
			
		||||
    if (j > (maxExponent / 2)) {
 | 
			
		||||
      TEST(vr.flags.test(RealFlag::Overflow))(desc);
 | 
			
		||||
      TEST(vr.value.IsInfinite())("%s,%d,0x%llx", desc, j, x);
 | 
			
		||||
      TEST(ivf.flags.test(RealFlag::Overflow))("%s,%d,0x%llx", desc, j, x);
 | 
			
		||||
      MATCH(0x8000000000000000, ivf.value.ToUInt64())
 | 
			
		||||
      ("%s,%d,0x%llx", desc, j, x);
 | 
			
		||||
      TEST(vr.flags.test(RealFlag::Overflow))(ldesc);
 | 
			
		||||
      TEST(vr.value.IsInfinite())(ldesc);
 | 
			
		||||
      TEST(ivf.flags.test(RealFlag::Overflow))(ldesc);
 | 
			
		||||
      MATCH(0x8000000000000000, ivf.value.ToUInt64())(ldesc);
 | 
			
		||||
    } else {
 | 
			
		||||
      TEST(vr.flags.empty())(desc);
 | 
			
		||||
      TEST(!vr.value.IsInfinite())("%s,%d,0x%llx", desc, j, x);
 | 
			
		||||
      TEST(ivf.flags.empty())("%s,%d,0x%llx", desc, j, x);
 | 
			
		||||
      MATCH(x, ivf.value.ToUInt64())("%s,%d,0x%llx", desc, j, x);
 | 
			
		||||
      MATCH(nx, ivf.value.ToInt64())("%s,%d,0x%llx", desc, j, x);
 | 
			
		||||
      TEST(vr.flags.empty())(ldesc);
 | 
			
		||||
      TEST(!vr.value.IsInfinite())(ldesc);
 | 
			
		||||
      TEST(ivf.flags.empty())(ldesc);
 | 
			
		||||
      MATCH(x, ivf.value.ToUInt64())(ldesc);
 | 
			
		||||
      MATCH(nx, ivf.value.ToInt64())(ldesc);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -183,12 +184,41 @@ std::uint32_t FlagsToBits(const RealFlags &flags) {
 | 
			
		|||
  return bits;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void subset32bit() {
 | 
			
		||||
void inttest(std::int64_t x, int pass, Rounding rounding) {
 | 
			
		||||
  union {
 | 
			
		||||
    std::uint32_t u32;
 | 
			
		||||
    float f;
 | 
			
		||||
  } u;
 | 
			
		||||
  ScopedHostFloatingPointEnvironment fpenv;
 | 
			
		||||
  Integer<64> ix{x};
 | 
			
		||||
  ValueWithRealFlags<RealKind4> real;
 | 
			
		||||
  real = real.value.ConvertSigned(ix, rounding);
 | 
			
		||||
  fpenv.ClearFlags();
 | 
			
		||||
  float fcheck = x;  // TODO unsigned too
 | 
			
		||||
  auto actualFlags{FlagsToBits(fpenv.CurrentFlags())};
 | 
			
		||||
  u.f = fcheck;
 | 
			
		||||
  std::uint32_t rcheck{NormalizeNaN(u.u32)};
 | 
			
		||||
  std::uint32_t check = real.value.RawBits().ToUInt64();
 | 
			
		||||
  MATCH(rcheck, check)("%d 0x%llx", pass, x);
 | 
			
		||||
  MATCH(actualFlags, FlagsToBits(real.flags))("%d 0x%llx", pass, x);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void subset32bit(int pass, Rounding rounding) {
 | 
			
		||||
  for (int j{0}; j < 63; ++j) {
 | 
			
		||||
    std::int64_t x{1};
 | 
			
		||||
    x <<= j;
 | 
			
		||||
    inttest(x, pass, rounding);
 | 
			
		||||
    inttest(-x, pass, rounding);
 | 
			
		||||
  }
 | 
			
		||||
  inttest(0, pass, rounding);
 | 
			
		||||
  inttest(static_cast<std::int64_t>(0x8000000000000000), pass, rounding);
 | 
			
		||||
 | 
			
		||||
  union {
 | 
			
		||||
    std::uint32_t u32;
 | 
			
		||||
    float f;
 | 
			
		||||
  } u;
 | 
			
		||||
  ScopedHostFloatingPointEnvironment fpenv;
 | 
			
		||||
 | 
			
		||||
  for (std::uint32_t j{0}; j < 8192; ++j) {
 | 
			
		||||
    std::uint32_t rj{MakeReal(j)};
 | 
			
		||||
    u.u32 = rj;
 | 
			
		||||
| 
						 | 
				
			
			@ -200,51 +230,71 @@ void subset32bit() {
 | 
			
		|||
      float fk{u.f};
 | 
			
		||||
      RealKind4 y{Integer<32>{std::uint64_t{rk}}};
 | 
			
		||||
      {
 | 
			
		||||
        ValueWithRealFlags<RealKind4> sum{x.Add(y)};
 | 
			
		||||
        ValueWithRealFlags<RealKind4> sum{x.Add(y, rounding)};
 | 
			
		||||
        fpenv.ClearFlags();
 | 
			
		||||
        float fcheck{fj + fk};
 | 
			
		||||
        auto actualFlags{FlagsToBits(fpenv.CurrentFlags())};
 | 
			
		||||
        u.f = fcheck;
 | 
			
		||||
        std::uint32_t rcheck{NormalizeNaN(u.u32)};
 | 
			
		||||
        std::uint32_t check = sum.value.RawBits().ToUInt64();
 | 
			
		||||
        MATCH(rcheck, check)("0x%x + 0x%x", rj, rk);
 | 
			
		||||
        MATCH(actualFlags, FlagsToBits(sum.flags))("0x%x + 0x%x", rj, rk);
 | 
			
		||||
        MATCH(rcheck, check)("%d 0x%x + 0x%x", pass, rj, rk);
 | 
			
		||||
        MATCH(actualFlags, FlagsToBits(sum.flags))
 | 
			
		||||
        ("%d 0x%x + 0x%x", pass, rj, rk);
 | 
			
		||||
      }
 | 
			
		||||
      {
 | 
			
		||||
        ValueWithRealFlags<RealKind4> diff{x.Subtract(y)};
 | 
			
		||||
        ValueWithRealFlags<RealKind4> diff{x.Subtract(y, rounding)};
 | 
			
		||||
        fpenv.ClearFlags();
 | 
			
		||||
        float fcheck{fj - fk};
 | 
			
		||||
        auto actualFlags{FlagsToBits(fpenv.CurrentFlags())};
 | 
			
		||||
        u.f = fcheck;
 | 
			
		||||
        std::uint32_t rcheck{NormalizeNaN(u.u32)};
 | 
			
		||||
        std::uint32_t check = diff.value.RawBits().ToUInt64();
 | 
			
		||||
        MATCH(rcheck, check)("0x%x - 0x%x", rj, rk);
 | 
			
		||||
        MATCH(rcheck, check)("%d 0x%x - 0x%x", pass, rj, rk);
 | 
			
		||||
        MATCH(actualFlags, FlagsToBits(diff.flags))
 | 
			
		||||
        ("%d 0x%x - 0x%x", pass, rj, rk);
 | 
			
		||||
      }
 | 
			
		||||
      {
 | 
			
		||||
        ValueWithRealFlags<RealKind4> prod{x.Multiply(y)};
 | 
			
		||||
        ValueWithRealFlags<RealKind4> prod{x.Multiply(y, rounding)};
 | 
			
		||||
        fpenv.ClearFlags();
 | 
			
		||||
        float fcheck{fj * fk};
 | 
			
		||||
        auto actualFlags{FlagsToBits(fpenv.CurrentFlags())};
 | 
			
		||||
        u.f = fcheck;
 | 
			
		||||
        std::uint32_t rcheck{NormalizeNaN(u.u32)};
 | 
			
		||||
        std::uint32_t check = prod.value.RawBits().ToUInt64();
 | 
			
		||||
        MATCH(rcheck, check)("0x%x * 0x%x", rj, rk);
 | 
			
		||||
        MATCH(rcheck, check)("%d 0x%x * 0x%x", pass, rj, rk);
 | 
			
		||||
        MATCH(actualFlags, FlagsToBits(prod.flags))
 | 
			
		||||
        ("%d 0x%x * 0x%x -> 0x%x", pass, rj, rk, rcheck);
 | 
			
		||||
      }
 | 
			
		||||
#if 0
 | 
			
		||||
      { ValueWithRealFlags<RealKind4> quot{x.Divide(y)};
 | 
			
		||||
        float fcheck{fj * fk};
 | 
			
		||||
      { ValueWithRealFlags<RealKind4> quot{x.Divide(y, rounding)};
 | 
			
		||||
        fpenv.ClearFlags();
 | 
			
		||||
        float fcheck{fj / fk};
 | 
			
		||||
        auto actualFlags{FlagsToBits(fpenv.CurrentFlags())};
 | 
			
		||||
        u.f = fcheck;
 | 
			
		||||
        std::uint32_t rcheck{NormalizeNaN(u.u32)};
 | 
			
		||||
        std::uint32_t check = quot.value.RawBits().ToUInt64();
 | 
			
		||||
        MATCH(rcheck, check)("0x%x / 0x%x", rj, rk);
 | 
			
		||||
        MATCH(rcheck, check)("%d 0x%x / 0x%x", pass, rj, rk);
 | 
			
		||||
        MATCH(actualFlags, FlagsToBits(quot.flags))("%d 0x%x / 0x%x", pass, rj, rk);
 | 
			
		||||
      }
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main() {
 | 
			
		||||
  tests<RealKind2>();
 | 
			
		||||
  tests<RealKind4>();
 | 
			
		||||
  tests<RealKind8>();
 | 
			
		||||
  tests<RealKind10>();
 | 
			
		||||
  tests<RealKind16>();
 | 
			
		||||
  subset32bit();  // TODO rounding modes
 | 
			
		||||
  return testing::Complete();
 | 
			
		||||
void roundTest(int rm, Rounding rounding) {
 | 
			
		||||
  basicTests<RealKind2>(rm, rounding);
 | 
			
		||||
  basicTests<RealKind4>(rm, rounding);
 | 
			
		||||
  basicTests<RealKind8>(rm, rounding);
 | 
			
		||||
  basicTests<RealKind10>(rm, rounding);
 | 
			
		||||
  basicTests<RealKind16>(rm, rounding);
 | 
			
		||||
  ScopedHostFloatingPointEnvironment::SetRounding(rounding);
 | 
			
		||||
  subset32bit(rm, rounding);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main() {
 | 
			
		||||
  roundTest(0, Rounding::TiesToEven);
 | 
			
		||||
  roundTest(1, Rounding::ToZero);
 | 
			
		||||
  roundTest(2, Rounding::Up);
 | 
			
		||||
  roundTest(3, Rounding::Down);
 | 
			
		||||
  // TODO: how to test Rounding::TiesAwayFromZero on x86?
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue