/* This file is part of the dynarmic project. * Copyright (c) 2018 MerryMage * This software may be used and distributed according to the terms of the GNU * General Public License version 2 or any later version. */ #include #include "common/assert.h" #include "common/common_types.h" #include "common/fp/fpcr.h" #include "common/fp/fpsr.h" #include "common/fp/info.h" #include "common/fp/op/FPRecipEstimate.h" #include "common/fp/process_exception.h" #include "common/fp/process_nan.h" #include "common/fp/unpacked.h" #include "common/math_util.h" namespace Dynarmic::FP { template FPT FPRecipEstimate(FPT op, FPCR fpcr, FPSR& fpsr) { FPType type; bool sign; FPUnpacked value; std::tie(type, sign, value) = FPUnpack(op, fpcr, fpsr); if (type == FPType::SNaN || type == FPType::QNaN) { return FPProcessNaN(type, op, fpcr, fpsr); } if (type == FPType::Infinity) { return FPT(FPInfo::Zero(sign)); } if (type == FPType::Zero) { FPProcessException(FPExc::DivideByZero, fpcr, fpsr); return FPT(FPInfo::Infinity(sign)); } if (value.exponent < FPInfo::exponent_min - 2) { const bool overflow_to_inf = [&]{ switch (fpcr.RMode()) { case RoundingMode::ToNearest_TieEven: return true; case RoundingMode::TowardsPlusInfinity: return !sign; case RoundingMode::TowardsMinusInfinity: return sign; case RoundingMode::TowardsZero: return false; default: UNREACHABLE(); } return false; }(); FPProcessException(FPExc::Overflow, fpcr, fpsr); FPProcessException(FPExc::Inexact, fpcr, fpsr); return overflow_to_inf ? FPT(FPInfo::Infinity(sign)) : FPT(FPInfo::MaxNormal(sign)); } if ((fpcr.FZ() && !std::is_same_v) || (fpcr.FZ16() && std::is_same_v)) { if (value.exponent >= -FPInfo::exponent_min) { fpsr.UFC(true); return FPT(FPInfo::Zero(sign)); } } const u64 scaled = value.mantissa >> (normalized_point_position - 8); u64 estimate = static_cast(Common::RecipEstimate(scaled)) << (FPInfo::explicit_mantissa_width - 8); int result_exponent = -(value.exponent + 1); if (result_exponent < FPInfo::exponent_min) { switch (result_exponent) { case (FPInfo::exponent_min - 1): estimate |= FPInfo::implicit_leading_bit; estimate >>= 1; break; case (FPInfo::exponent_min - 2): estimate |= FPInfo::implicit_leading_bit; estimate >>= 2; result_exponent++; break; default: UNREACHABLE(); } } const FPT bits_sign = FPT(FPInfo::Zero(sign)); const FPT bits_exponent = static_cast(result_exponent + FPInfo::exponent_bias); const FPT bits_mantissa = static_cast(estimate); return FPT((bits_exponent << FPInfo::explicit_mantissa_width) | (bits_mantissa & FPInfo::mantissa_mask) | bits_sign); } template u16 FPRecipEstimate(u16 op, FPCR fpcr, FPSR& fpsr); template u32 FPRecipEstimate(u32 op, FPCR fpcr, FPSR& fpsr); template u64 FPRecipEstimate(u64 op, FPCR fpcr, FPSR& fpsr); } // namespace Dynarmic::FP