From 95af9dafbe3532f9fe7f7aa319607159ebf91d9d Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sun, 3 Mar 2019 01:08:12 -0500 Subject: [PATCH] common/fp/op: Add FP conversion functions --- src/CMakeLists.txt | 2 + src/common/fp/op.h | 1 + src/common/fp/op/FPConvert.cpp | 102 +++++++++++++++++++++++++++++++++ src/common/fp/op/FPConvert.h | 18 ++++++ 4 files changed, 123 insertions(+) create mode 100644 src/common/fp/op/FPConvert.cpp create mode 100644 src/common/fp/op/FPConvert.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c9ef4fcb..66c1db77 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -24,6 +24,8 @@ add_library(dynarmic common/fp/info.h common/fp/mantissa_util.h common/fp/op.h + common/fp/op/FPConvert.cpp + common/fp/op/FPConvert.h common/fp/op/FPMulAdd.cpp common/fp/op/FPMulAdd.h common/fp/op/FPRecipEstimate.cpp diff --git a/src/common/fp/op.h b/src/common/fp/op.h index c792e50e..b8ee1441 100644 --- a/src/common/fp/op.h +++ b/src/common/fp/op.h @@ -6,6 +6,7 @@ #pragma once +#include "common/fp/op/FPConvert.h" #include "common/fp/op/FPMulAdd.h" #include "common/fp/op/FPRecipEstimate.h" #include "common/fp/op/FPRecipExponent.h" diff --git a/src/common/fp/op/FPConvert.cpp b/src/common/fp/op/FPConvert.cpp new file mode 100644 index 00000000..559d0242 --- /dev/null +++ b/src/common/fp/op/FPConvert.cpp @@ -0,0 +1,102 @@ +/* This file is part of the dynarmic project. + * Copyright (c) 2019 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/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" + +namespace Dynarmic::FP { +namespace { +// We don't care about unreachable code warnings here +// TODO: Remove this disabling of warnings when +// half-float support is added. +#ifdef _MSC_VER +#pragma warning(disable:4702) +#endif +template +FPT_TO FPConvertNaN(FPT_FROM op) { + const bool sign = Common::Bit() - 1>(op); + const u64 frac = [op] { + if constexpr (sizeof(FPT_FROM) == sizeof(u64)) { + return Common::Bits<0, 50>(op); + } + + if constexpr (sizeof(FPT_FROM) == sizeof(u32)) { + return u64{Common::Bits<0, 21>(op)} << 29; + } + + return u64{Common::Bits<0, 8>(op)} << 42; + }(); + + const size_t dest_bit_size = Common::BitSize(); + const u64 shifted_sign = u64{sign} << (dest_bit_size - 1); + const u64 exponent = Common::Ones(dest_bit_size - FPInfo::explicit_mantissa_width); + + if constexpr (sizeof(FPT_TO) == sizeof(u64)) { + return FPT_TO(shifted_sign | exponent << 52 | frac); + } + + if constexpr (sizeof(FPT_TO) == sizeof(u32)) { + return FPT_TO(shifted_sign | exponent << 22 | Common::Bits<29, 50>(frac)); + } + + return FPT_TO(shifted_sign | exponent << 9 | Common::Bits<42, 50>(frac)); +} +#ifdef _MSC_VER +#pragma warning(default:4702) +#endif +} // Anonymous namespace + +template +FPT_TO FPConvert(FPT_FROM op, FPCR fpcr, RoundingMode rounding_mode, FPSR& fpsr) { + const auto [type, sign, value] = FPUnpack(op, fpcr, fpsr); + const bool is_althp = Common::BitSize() == 16 && fpcr.AHP(); + + if (type == FPType::SNaN || type == FPType::QNaN) { + FPT_TO result{}; + + if (is_althp) { + result = FPInfo::Zero(sign); + } else if (fpcr.DN()) { + result = FPInfo::DefaultNaN(); + } else { + result = FPConvertNaN(op); + } + + if (type == FPType::SNaN || is_althp) { + FPProcessException(FPExc::InvalidOp, fpcr, fpsr); + } + + return result; + } + + if (type == FPType::Infinity) { + if (is_althp) { + FPProcessException(FPExc::InvalidOp, fpcr, fpsr); + return static_cast(u32{sign} << 15 | 0b111111111111111); + } + + return FPInfo::Infinity(sign); + } + + if (type == FPType::Zero) { + return FPInfo::Zero(sign); + } + + return FPRoundBase(value, fpcr, rounding_mode, fpsr); +} + +template u64 FPConvert(u32 op, FPCR fpcr, RoundingMode rounding_mode, FPSR& fpsr); +template u32 FPConvert(u64 op, FPCR fpcr, RoundingMode rounding_mode, FPSR& fpsr); + +} // namespace Dynarmic::FP diff --git a/src/common/fp/op/FPConvert.h b/src/common/fp/op/FPConvert.h new file mode 100644 index 00000000..419a158b --- /dev/null +++ b/src/common/fp/op/FPConvert.h @@ -0,0 +1,18 @@ +/* This file is part of the dynarmic project. + * Copyright (c) 2019 MerryMage + * This software may be used and distributed according to the terms of the GNU + * General Public License version 2 or any later version. + */ + +#pragma once + +namespace Dynarmic::FP { + +class FPCR; +class FPSR; +enum class RoundingMode; + +template +FPT_TO FPConvert(FPT_FROM op, FPCR fpcr, RoundingMode rounding_mode, FPSR& fpsr); + +} // namespace Dynarmic::FP