/* 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 "common/assert.h" #include "common/bit_util.h" #include "common/common_types.h" #include "common/fp/fpcr.h" #include "common/fp/fpsr.h" #include "common/fp/info.h" #include "common/fp/mantissa_util.h" #include "common/fp/op/FPRoundInt.h" #include "common/fp/process_exception.h" #include "common/fp/process_nan.h" #include "common/fp/rounding_mode.h" #include "common/fp/unpacked.h" #include "common/safe_ops.h" namespace Dynarmic::FP { template u64 FPRoundInt(FPT op, FPCR fpcr, RoundingMode rounding, bool exact, FPSR& fpsr) { ASSERT(rounding != RoundingMode::ToOdd); auto [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 FPInfo::Infinity(sign); } if (type == FPType::Zero) { return FPInfo::Zero(sign); } // Reshift decimal point back to bit zero. const int exponent = value.exponent - normalized_point_position; if (exponent >= 0) { // Guaranteed to be an integer return op; } u64 int_result = sign ? Safe::Negate(value.mantissa) : static_cast(value.mantissa); const ResidualError error = ResidualErrorOnRightShift(int_result, -exponent); int_result = Safe::ArithmeticShiftLeft(int_result, exponent); bool round_up = false; switch (rounding) { case RoundingMode::ToNearest_TieEven: round_up = error > ResidualError::Half || (error == ResidualError::Half && Common::Bit<0>(int_result)); break; case RoundingMode::TowardsPlusInfinity: round_up = error != ResidualError::Zero; break; case RoundingMode::TowardsMinusInfinity: round_up = false; break; case RoundingMode::TowardsZero: round_up = error != ResidualError::Zero && Common::MostSignificantBit(int_result); break; case RoundingMode::ToNearest_TieAwayFromZero: round_up = error > ResidualError::Half || (error == ResidualError::Half && !Common::MostSignificantBit(int_result)); break; case RoundingMode::ToOdd: UNREACHABLE(); } if (round_up) { int_result++; } const bool new_sign = Common::MostSignificantBit(int_result); const u64 abs_int_result = new_sign ? Safe::Negate(int_result) : static_cast(int_result); const FPT result = int_result == 0 ? FPInfo::Zero(sign) : FPRound(FPUnpacked{new_sign, normalized_point_position, abs_int_result}, fpcr, RoundingMode::TowardsZero, fpsr); if (error != ResidualError::Zero && exact) { FPProcessException(FPExc::Inexact, fpcr, fpsr); } return result; } template u64 FPRoundInt(u16 op, FPCR fpcr, RoundingMode rounding, bool exact, FPSR& fpsr); template u64 FPRoundInt(u32 op, FPCR fpcr, RoundingMode rounding, bool exact, FPSR& fpsr); template u64 FPRoundInt(u64 op, FPCR fpcr, RoundingMode rounding, bool exact, FPSR& fpsr); } // namespace Dynarmic::FP