fp: Fix FPToFixed for borderline values

This commit is contained in:
Merry 2023-01-15 23:59:27 +00:00
parent f3af94bc7c
commit 4f3ef50d5c
2 changed files with 19 additions and 1 deletions

View file

@ -5,6 +5,7 @@
#include "dynarmic/common/fp/op/FPToFixed.h" #include "dynarmic/common/fp/op/FPToFixed.h"
#include <fmt/format.h>
#include <mcl/assert.hpp> #include <mcl/assert.hpp>
#include <mcl/bit/bit_count.hpp> #include <mcl/bit/bit_count.hpp>
#include <mcl/bit/bit_field.hpp> #include <mcl/bit/bit_field.hpp>
@ -75,7 +76,7 @@ u64 FPToFixed(size_t ibits, FPT op, size_t fbits, bool unsigned_, FPCR fpcr, Rou
} }
// Detect Overflow // Detect Overflow
const int min_exponent_for_overflow = static_cast<int>(ibits) - static_cast<int>(mcl::bit::highest_set_bit(value.mantissa + (round_up ? 1 : 0))) - (unsigned_ ? 0 : 1); const int min_exponent_for_overflow = static_cast<int>(ibits) - static_cast<int>(mcl::bit::highest_set_bit(value.mantissa + (round_up ? Safe::LogicalShiftRight<u64>(1, exponent) : 0))) - (unsigned_ ? 0 : 1);
if (exponent >= min_exponent_for_overflow) { if (exponent >= min_exponent_for_overflow) {
// Positive overflow // Positive overflow
if (unsigned_ || !sign) { if (unsigned_ || !sign) {

View file

@ -38,3 +38,20 @@ TEST_CASE("FPToFixed", "[fp]") {
REQUIRE(fpsr.Value() == expected_fpsr); REQUIRE(fpsr.Value() == expected_fpsr);
} }
} }
TEST_CASE("FPToFixed edge cases", "[fp]") {
const std::vector<std::tuple<u64, u64, bool, FP::RoundingMode>> test_cases{
{0x41dffffffffffffe, 0x7fffffff, false, FP::RoundingMode::ToNearest_TieEven},
{0x41dffffffffffffe, 0x7fffffff, false, FP::RoundingMode::TowardsPlusInfinity},
{0x41dffffffffffffe, 0x7fffffff, false, FP::RoundingMode::TowardsMinusInfinity},
{0x41dffffffffffffe, 0x7fffffff, false, FP::RoundingMode::TowardsZero},
{0x41dffffffffffffe, 0x7fffffff, false, FP::RoundingMode::ToNearest_TieAwayFromZero},
};
const FPCR fpcr;
FPSR fpsr;
for (auto [input, expected_output, unsigned_, rounding_mode] : test_cases) {
const u64 output = FPToFixed<u64>(32, input, 0, unsigned_, fpcr, rounding_mode, fpsr);
REQUIRE(output == expected_output);
}
}