[flang] Use EnumSet<> for real flags

Original-commit: flang-compiler/f18@a61f193036
Reviewed-on: https://github.com/flang-compiler/f18/pull/101
Tree-same-pre-rewrite: false
This commit is contained in:
peter klausler 2018-06-06 11:11:35 -07:00
parent b940e3de3f
commit 3fb4757cc7
4 changed files with 43 additions and 40 deletions

View File

@ -15,6 +15,7 @@
#ifndef FORTRAN_EVALUATE_COMMON_H_
#define FORTRAN_EVALUATE_COMMON_H_
#include "../semantics/enum-set.h"
#include <cinttypes>
namespace Fortran::evaluate {
@ -63,20 +64,19 @@ static constexpr Relation Reverse(Relation relation) {
}
}
namespace RealFlag {
enum {
Ok = 0,
Overflow = 1,
DivideByZero = 2,
InvalidArgument = 4,
Underflow = 8,
Inexact = 16
enum class RealFlag {
Overflow,
DivideByZero,
InvalidArgument,
Underflow,
Inexact
};
} // namespace RealFlag
using RealFlags = semantics::EnumSet<RealFlag, 5>;
template<typename A> struct ValueWithRealFlags {
A value;
int flags{RealFlag::Ok};
RealFlags flags;
};
enum class Rounding { TiesToEven, ToZero, Down, Up, TiesAwayFromZero };

View File

@ -50,7 +50,7 @@ namespace Fortran::evaluate {
// Member functions that correspond to Fortran intrinsic functions are
// named accordingly so that they can be referenced easily in the
// language standard.
template<int BITS, bool LITTLE_ENDIAN = IsHostLittleEndian,
template<int BITS, bool IS_LITTLE_ENDIAN = IsHostLittleEndian,
int PARTBITS =
BITS<32 ? BITS : 32, typename PART = HostUnsignedInt<PARTBITS>,
typename BIGPART = HostUnsignedInt<PARTBITS * 2>> class Integer {
@ -60,7 +60,7 @@ public:
using Part = PART;
using BigPart = BIGPART;
static_assert(CHAR_BIT * sizeof(BigPart) >= 2 * partBits);
static constexpr bool littleEndian{LITTLE_ENDIAN};
static constexpr bool littleEndian{IS_LITTLE_ENDIAN};
private:
static constexpr int maxPartBits{CHAR_BIT * sizeof(Part)};

View File

@ -128,7 +128,7 @@ public:
std::uint64_t exponent{Exponent()};
Fraction fraction{GetFraction()};
if (exponent == maxExponent && !fraction.IsZero()) { // NaN
result.flags |= RealFlag::InvalidArgument;
result.flags.set(RealFlag::InvalidArgument);
result.value = result.value.HUGE();
} else if (exponent >= maxExponent || exponent >= exponentBias + result.value.bits) { // +/-Inf
if (isNegative) {
@ -136,37 +136,38 @@ public:
} else {
result.value = result.value.HUGE();
}
result.flags |= RealFlag::Overflow;
result.flags.set(RealFlag::Overflow);
} else if (exponent < exponentBias) { // |x| < 1.0
if (!fraction.IsZero()) {
result.flags |= RealFlag::Underflow | RealFlag::Inexact;
result.flags.set(RealFlag::Underflow);
result.flags.set(RealFlag::Inexact);
}
} else {
if (exponent < exponentBias + significandBits) {
int rshift = exponentBias + significandBits - exponent;
if (!fraction.IBITS(0, rshift).IsZero()) {
result.flags |= RealFlag::Inexact;
result.flags.set(RealFlag::Inexact);
}
auto truncated = result.value.Convert(fraction.SHIFTR(rshift));
if (truncated.overflow) {
result.flags |= RealFlag::Overflow;
result.flags.set(RealFlag::Overflow);
} else {
result.value = truncated.value;
}
} else {
int lshift = exponent - (exponentBias + significandBits);
if (lshift + precision >= result.value.bits) {
result.flags |= RealFlag::Overflow;
result.flags.set(RealFlag::Overflow);
} else {
result.value = result.value.Convert(fraction).value.SHIFTL(lshift);
}
}
if (result.flags & RealFlag::Overflow) {
if (result.flags.test(RealFlag::Overflow)) {
result.value = result.value.HUGE();
} else if (isNegative) {
auto negated = result.value.Negate();
if (negated.overflow) {
result.flags |= RealFlag::Overflow;
result.flags.set(RealFlag::Overflow);
result.value = result.value.HUGE();
} else {
result.value = negated.value;
@ -218,7 +219,7 @@ public:
ValueWithRealFlags<Real> result;
if (IsNotANumber() || y.IsNotANumber()) {
result.value.word_ = NaNWord(); // NaN + x -> NaN
result.flags = RealFlag::InvalidArgument;
result.flags.set(RealFlag::InvalidArgument);
return result;
}
bool isNegative{IsNegative()};
@ -228,7 +229,7 @@ public:
result.value = *this; // +/-Inf + +/-Inf -> +/-Inf
} else {
result.value.word_ = NaNWord(); // +/-Inf + -/+Inf -> NaN
result.flags = RealFlag::InvalidArgument;
result.flags.set(RealFlag::InvalidArgument);
}
return result;
}
@ -289,7 +290,7 @@ public:
ValueWithRealFlags<Real> result;
if (IsNotANumber() || y.IsNotANumber()) {
result.value.word_ = NaNWord(); // NaN * x -> NaN
result.flags = RealFlag::InvalidArgument;
result.flags.set(RealFlag::InvalidArgument);
} else {
bool isNegative{IsNegative() != y.IsNegative()};
if (IsInfinite() || y.IsInfinite()) {
@ -311,24 +312,24 @@ public:
ValueWithRealFlags<Real> result;
if (IsNotANumber() || y.IsNotANumber()) {
result.value.word_ = NaNWord(); // NaN / x -> NaN, x / NaN -> NaN
result.flags = RealFlag::InvalidArgument;
result.flags.set(RealFlag::InvalidArgument);
} else {
bool isNegative{IsNegative() != y.IsNegative()};
if (IsInfinite()) {
if (y.IsInfinite() || y.IsZero()) {
result.value.word_ = NaNWord(); // Inf/Inf -> NaN, Inf/0 -> Nan
result.flags = RealFlag::InvalidArgument;
result.flags.set(RealFlag::InvalidArgument);
} else {
result.value.Normalize(isNegative, maxExponent, Fraction{});
}
} else if (y.IsInfinite()) {
result.value.word_ = NaNWord(); // x/Inf -> NaN
result.flags = RealFlag::InvalidArgument;
result.flags.set(RealFlag::InvalidArgument);
} else {
auto qr = GetFraction().DivideUnsigned(y.GetFraction());
if (qr.divisionByZero) {
result.value.Normalize(isNegative, maxExponent, Fraction{});
result.flags |= RealFlag::DivideByZero;
result.flags.set(RealFlag::DivideByZero);
} else {
// To round, double the remainder and compare it to the divisor.
auto doubled = qr.remainder.AddUnsigned(qr.remainder);
@ -394,15 +395,14 @@ private:
return Word{maxExponent}.SHIFTL(significandBits).IBSET(0);
}
// Returns flag bits.
constexpr int Normalize(
constexpr RealFlags Normalize(
bool negative, std::uint64_t biasedExponent, const Fraction &fraction) {
if (biasedExponent >= maxExponent) {
word_ = Word{maxExponent}.SHIFTL(significandBits);
if (negative) {
word_ = word_.IBSET(bits - 1);
}
return RealFlag::Overflow;
return {RealFlag::Overflow};
} else {
std::uint64_t leadz = fraction.LEADZ();
if (leadz >= precision) {
@ -421,7 +421,7 @@ private:
if (negative) {
word_ = word_.IBSET(bits - 1);
}
return RealFlag::Ok;
return {};
}
}
@ -445,10 +445,13 @@ private:
return round;
}
// Rounds a result, if necessary; returns flags.
int Round(Rounding rounding, const RoundingBits &bits) {
// Rounds a result, if necessary.
RealFlags Round(Rounding rounding, const RoundingBits &bits) {
std::uint64_t exponent{Exponent()};
int flags{(bits.round | bits.guard) ? RealFlag::Inexact : RealFlag::Ok};
RealFlags flags;
if (bits.round | bits.guard) {
flags.set(RealFlag::Inexact);
}
if (exponent < maxExponent && MustRound(rounding, bits)) {
typename Fraction::ValueWithCarry sum{
GetFraction().AddUnsigned(Fraction{}, true)};
@ -458,7 +461,7 @@ private:
sum.value.IBSET(precision - 1);
} else {
// rounded away to an infinity
flags |= RealFlag::Overflow;
flags.set(RealFlag::Overflow);
}
}
flags |= Normalize(IsNegative(), exponent, sum.value);

View File

@ -49,7 +49,7 @@ template<typename R> void tests() {
TEST(zero.Compare(minusZero) == Relation::Equal)(desc);
ValueWithRealFlags<R> vr;
MATCH(0, vr.value.RawBits().ToUInt64())(desc);
MATCH(0, vr.flags)(desc);
TEST(vr.flags.empty())(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);
@ -99,14 +99,14 @@ template<typename R> void tests() {
TEST(!vr.value.IsZero())("%s,%d,0x%llx",desc,j,x);
auto ivf = vr.value.template ToInteger<Integer<64>>();
if (j > (maxExponent / 2)) {
MATCH(RealFlag::Overflow, vr.flags)(desc);
TEST(vr.flags.test(RealFlag::Overflow))(desc);
TEST(vr.value.IsInfinite())("%s,%d,0x%llx",desc,j,x);
MATCH(RealFlag::Overflow, ivf.flags)("%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);
} else {
MATCH(RealFlag::Ok, vr.flags)(desc);
TEST(vr.flags.empty())(desc);
TEST(!vr.value.IsInfinite())("%s,%d,0x%llx",desc,j,x);
MATCH(RealFlag::Ok, ivf.flags)("%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);
}
}