fp: Remove MantissaT

This commit is contained in:
MerryMage 2018-07-23 11:52:37 +01:00
parent bda86fd167
commit 805428e35e
6 changed files with 33 additions and 36 deletions

View file

@ -18,20 +18,19 @@ enum class ResidualError {
GreaterThanHalf, GreaterThanHalf,
}; };
template<typename MantissaT> inline ResidualError ResidualErrorOnRightShift(u64 mantissa, int shift_amount) {
ResidualError ResidualErrorOnRightShift(MantissaT mantissa, int shift_amount) {
if (shift_amount <= 0 || mantissa == 0) { if (shift_amount <= 0 || mantissa == 0) {
return ResidualError::Zero; return ResidualError::Zero;
} }
if (shift_amount > static_cast<int>(Common::BitSize<MantissaT>())) { if (shift_amount > static_cast<int>(Common::BitSize<u64>())) {
return Common::MostSignificantBit(mantissa) ? ResidualError::GreaterThanHalf : ResidualError::LessThanHalf; return Common::MostSignificantBit(mantissa) ? ResidualError::GreaterThanHalf : ResidualError::LessThanHalf;
} }
const size_t half_bit_position = static_cast<size_t>(shift_amount - 1); const size_t half_bit_position = static_cast<size_t>(shift_amount - 1);
const MantissaT half = static_cast<MantissaT>(1) << half_bit_position; const u64 half = static_cast<u64>(1) << half_bit_position;
const MantissaT error_mask = Common::Ones<MantissaT>(static_cast<size_t>(shift_amount)); const u64 error_mask = Common::Ones<u64>(static_cast<size_t>(shift_amount));
const MantissaT error = mantissa & error_mask; const u64 error = mantissa & error_mask;
if (error == 0) { if (error == 0) {
return ResidualError::Zero; return ResidualError::Zero;

View file

@ -77,7 +77,7 @@ u64 FPRoundInt(FPT op, FPCR fpcr, RoundingMode rounding, bool exact, FPSR& fpsr)
const FPT result = int_result == 0 const FPT result = int_result == 0
? FPInfo<FPT>::Zero(sign) ? FPInfo<FPT>::Zero(sign)
: FPRound<FPT>(FPUnpacked<u64>{new_sign, 0, abs_int_result}, fpcr, RoundingMode::TowardsZero, fpsr); : FPRound<FPT>(FPUnpacked{new_sign, 0, abs_int_result}, fpcr, RoundingMode::TowardsZero, fpsr);
if (error != ResidualError::Zero && exact) { if (error != ResidualError::Zero && exact) {
FPProcessException(FPExc::Inexact, fpcr, fpsr); FPProcessException(FPExc::Inexact, fpcr, fpsr);

View file

@ -14,7 +14,7 @@
namespace Dynarmic::FP { namespace Dynarmic::FP {
template<typename FPT> template<typename FPT>
std::tuple<FPType, bool, FPUnpacked<u64>> FPUnpack(FPT op, FPCR fpcr, FPSR& fpsr) { std::tuple<FPType, bool, FPUnpacked> FPUnpack(FPT op, FPCR fpcr, FPSR& fpsr) {
constexpr size_t sign_bit = FPInfo<FPT>::exponent_width + FPInfo<FPT>::explicit_mantissa_width; constexpr size_t sign_bit = FPInfo<FPT>::exponent_width + FPInfo<FPT>::explicit_mantissa_width;
constexpr size_t exponent_high_bit = FPInfo<FPT>::exponent_width + FPInfo<FPT>::explicit_mantissa_width - 1; constexpr size_t exponent_high_bit = FPInfo<FPT>::exponent_width + FPInfo<FPT>::explicit_mantissa_width - 1;
constexpr size_t exponent_low_bit = FPInfo<FPT>::explicit_mantissa_width; constexpr size_t exponent_low_bit = FPInfo<FPT>::explicit_mantissa_width;
@ -51,21 +51,21 @@ std::tuple<FPType, bool, FPUnpacked<u64>> FPUnpack(FPT op, FPCR fpcr, FPSR& fpsr
return {FPType::Nonzero, sign, {sign, exp, frac}}; return {FPType::Nonzero, sign, {sign, exp, frac}};
} }
template std::tuple<FPType, bool, FPUnpacked<u64>> FPUnpack<u32>(u32 op, FPCR fpcr, FPSR& fpsr); template std::tuple<FPType, bool, FPUnpacked> FPUnpack<u32>(u32 op, FPCR fpcr, FPSR& fpsr);
template std::tuple<FPType, bool, FPUnpacked<u64>> FPUnpack<u64>(u64 op, FPCR fpcr, FPSR& fpsr); template std::tuple<FPType, bool, FPUnpacked> FPUnpack<u64>(u64 op, FPCR fpcr, FPSR& fpsr);
template<size_t F, typename MantissaT> template<size_t F>
std::tuple<bool, int, MantissaT, MantissaT> Normalize(FPUnpacked<MantissaT> op) { std::tuple<bool, int, u64, u64> Normalize(FPUnpacked op) {
const int highest_set_bit = Common::HighestSetBit(op.mantissa); const int highest_set_bit = Common::HighestSetBit(op.mantissa);
const int shift_amount = highest_set_bit - static_cast<int>(F); const int shift_amount = highest_set_bit - static_cast<int>(F);
const MantissaT mantissa = Safe::LogicalShiftRight(op.mantissa, shift_amount); const u64 mantissa = Safe::LogicalShiftRight(op.mantissa, shift_amount);
const MantissaT error = Safe::LogicalShiftRightDouble(op.mantissa, static_cast<MantissaT>(0), shift_amount); const u64 error = Safe::LogicalShiftRightDouble(op.mantissa, static_cast<u64>(0), shift_amount);
const int exponent = op.exponent + highest_set_bit; const int exponent = op.exponent + highest_set_bit;
return std::make_tuple(op.sign, exponent, mantissa, error); return std::make_tuple(op.sign, exponent, mantissa, error);
} }
template<typename FPT, typename MantissaT> template<typename FPT>
FPT FPRoundBase(FPUnpacked<MantissaT> op, FPCR fpcr, RoundingMode rounding, FPSR& fpsr) { FPT FPRoundBase(FPUnpacked op, FPCR fpcr, RoundingMode rounding, FPSR& fpsr) {
ASSERT(op.mantissa != 0); ASSERT(op.mantissa != 0);
ASSERT(rounding != RoundingMode::ToNearest_TieAwayFromZero); ASSERT(rounding != RoundingMode::ToNearest_TieAwayFromZero);
@ -94,7 +94,7 @@ FPT FPRoundBase(FPUnpacked<MantissaT> op, FPCR fpcr, RoundingMode rounding, FPSR
bool round_up = false, overflow_to_inf = false; bool round_up = false, overflow_to_inf = false;
switch (rounding) { switch (rounding) {
case RoundingMode::ToNearest_TieEven: { case RoundingMode::ToNearest_TieEven: {
constexpr MantissaT half = static_cast<MantissaT>(1) << (Common::BitSize<MantissaT>() - 1); constexpr u64 half = static_cast<u64>(1) << (Common::BitSize<u64>() - 1);
round_up = (error > half) || (error == half && Common::Bit<0>(mantissa)); round_up = (error > half) || (error == half && Common::Bit<0>(mantissa));
overflow_to_inf = true; overflow_to_inf = true;
break; break;
@ -175,7 +175,7 @@ FPT FPRoundBase(FPUnpacked<MantissaT> op, FPCR fpcr, RoundingMode rounding, FPSR
return result; return result;
} }
template u32 FPRoundBase<u32, u64>(FPUnpacked<u64> op, FPCR fpcr, RoundingMode rounding, FPSR& fpsr); template u32 FPRoundBase<u32>(FPUnpacked op, FPCR fpcr, RoundingMode rounding, FPSR& fpsr);
template u64 FPRoundBase<u64, u64>(FPUnpacked<u64> op, FPCR fpcr, RoundingMode rounding, FPSR& fpsr); template u64 FPRoundBase<u64>(FPUnpacked op, FPCR fpcr, RoundingMode rounding, FPSR& fpsr);
} // namespace Dynarmic::FP } // namespace Dynarmic::FP

View file

@ -25,33 +25,31 @@ enum class FPType {
}; };
/// value = (sign ? -1 : +1) * mantissa * 2^exponent /// value = (sign ? -1 : +1) * mantissa * 2^exponent
template<typename MantissaT>
struct FPUnpacked { struct FPUnpacked {
bool sign; bool sign;
int exponent; int exponent;
MantissaT mantissa; u64 mantissa;
}; };
template<typename MantissaT> inline bool operator==(const FPUnpacked& a, const FPUnpacked& b) {
inline bool operator==(const FPUnpacked<MantissaT>& a, const FPUnpacked<MantissaT>& b) {
return std::tie(a.sign, a.exponent, a.mantissa) == std::tie(b.sign, b.exponent, b.mantissa); return std::tie(a.sign, a.exponent, a.mantissa) == std::tie(b.sign, b.exponent, b.mantissa);
} }
template<typename FPT> template<typename FPT>
std::tuple<FPType, bool, FPUnpacked<u64>> FPUnpack(FPT op, FPCR fpcr, FPSR& fpsr); std::tuple<FPType, bool, FPUnpacked> FPUnpack(FPT op, FPCR fpcr, FPSR& fpsr);
template<typename FPT, typename MantissaT> template<typename FPT>
FPT FPRoundBase(FPUnpacked<MantissaT> op, FPCR fpcr, RoundingMode rounding, FPSR& fpsr); FPT FPRoundBase(FPUnpacked op, FPCR fpcr, RoundingMode rounding, FPSR& fpsr);
template<typename FPT, typename MantissaT> template<typename FPT>
FPT FPRound(FPUnpacked<MantissaT> op, FPCR fpcr, RoundingMode rounding, FPSR& fpsr) { FPT FPRound(FPUnpacked op, FPCR fpcr, RoundingMode rounding, FPSR& fpsr) {
fpcr.AHP(false); fpcr.AHP(false);
return FPRoundBase<FPT, MantissaT>(op, fpcr, rounding, fpsr); return FPRoundBase<FPT>(op, fpcr, rounding, fpsr);
} }
template<typename FPT, typename MantissaT> template<typename FPT>
FPT FPRound(FPUnpacked<MantissaT> op, FPCR fpcr, FPSR& fpsr) { FPT FPRound(FPUnpacked op, FPCR fpcr, FPSR& fpsr) {
return FPRound<FPT, MantissaT>(op, fpcr, fpcr.RMode(), fpsr); return FPRound<FPT>(op, fpcr, fpcr.RMode(), fpsr);
} }
} // namespace Dynarmic::FP } // namespace Dynarmic::FP

View file

@ -38,12 +38,12 @@ TEST_CASE("ResidualErrorOnRightShift", "[fp]") {
TEST_CASE("ResidualErrorOnRightShift Randomized", "[fp]") { TEST_CASE("ResidualErrorOnRightShift Randomized", "[fp]") {
for (size_t test = 0; test < 100000; test++) { for (size_t test = 0; test < 100000; test++) {
const u32 mantissa = RandInt<u32>(0, 0xFFFFFFFF); const u64 mantissa = Common::SignExtend<32, u64>(RandInt<u32>(0, 0xFFFFFFFF));
const int shift = RandInt<int>(-60, 60); const int shift = RandInt<int>(-60, 60);
const ResidualError result = ResidualErrorOnRightShift(mantissa, shift); const ResidualError result = ResidualErrorOnRightShift(mantissa, shift);
const u64 calculated_error = Safe::ArithmeticShiftRightDouble(Common::SignExtend<32, u64>(mantissa), u64(0), shift); const u64 calculated_error = Safe::ArithmeticShiftRightDouble(mantissa, u64(0), shift);
const ResidualError expected_result = [&]{ const ResidualError expected_result = [&]{
constexpr u64 half_error = 0x8000'0000'0000'0000ull; constexpr u64 half_error = 0x8000'0000'0000'0000ull;
if (calculated_error == 0) { if (calculated_error == 0) {

View file

@ -19,7 +19,7 @@ using namespace Dynarmic;
using namespace Dynarmic::FP; using namespace Dynarmic::FP;
TEST_CASE("FPUnpack Tests", "[fp]") { TEST_CASE("FPUnpack Tests", "[fp]") {
const static std::vector<std::tuple<u32, std::tuple<FPType, bool, FPUnpacked<u64>>, u32>> test_cases { const static std::vector<std::tuple<u32, std::tuple<FPType, bool, FPUnpacked>, u32>> test_cases {
{0x00000000, {FPType::Zero, false, {false, 0, 0}}, 0}, {0x00000000, {FPType::Zero, false, {false, 0, 0}}, 0},
{0x7F800000, {FPType::Infinity, false, {false, 1000000, 1}}, 0}, {0x7F800000, {FPType::Infinity, false, {false, 1000000, 1}}, 0},
{0xFF800000, {FPType::Infinity, true, {true, 1000000, 1}}, 0}, {0xFF800000, {FPType::Infinity, true, {true, 1000000, 1}}, 0},
@ -43,7 +43,7 @@ TEST_CASE("FPUnpack Tests", "[fp]") {
} }
TEST_CASE("FPRound Tests", "[fp]") { TEST_CASE("FPRound Tests", "[fp]") {
const static std::vector<std::tuple<u32, std::tuple<FPType, bool, FPUnpacked<u64>>, u32>> test_cases { const static std::vector<std::tuple<u32, std::tuple<FPType, bool, FPUnpacked>, u32>> test_cases {
{0x7F800000, {FPType::Infinity, false, {false, 1000000, 1}}, 0x14}, {0x7F800000, {FPType::Infinity, false, {false, 1000000, 1}}, 0x14},
{0xFF800000, {FPType::Infinity, true, {true, 1000000, 1}}, 0x14}, {0xFF800000, {FPType::Infinity, true, {true, 1000000, 1}}, 0x14},
{0x00000001, {FPType::Nonzero, false, {false, -149, 1}}, 0}, // Smallest single precision denormal is 2^-149. {0x00000001, {FPType::Nonzero, false, {false, -149, 1}}, 0}, // Smallest single precision denormal is 2^-149.