/* 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. */ #pragma once #include #include "common/common_types.h" namespace Dynarmic::FP { /// Is 32-bit floating point value a zero? constexpr bool IsZero(u32 value) { return (value & 0x7fffffff) == 0; } /// Is 32-bit floating point value an infinity? constexpr bool IsInf(u32 value) { return (value & 0x7fffffff) == 0x7f800000; } /// Is 32-bit floating point value a QNaN? constexpr bool IsQNaN(u32 value) { return (value & 0x7fc00000) == 0x7fc00000; } /// Is 32-bit floating point value a SNaN? constexpr bool IsSNaN(u32 value) { return (value & 0x7fc00000) == 0x7f800000 && (value & 0x007fffff) != 0; } /// Is 32-bit floating point value a NaN? constexpr bool IsNaN(u32 value) { return IsQNaN(value) || IsSNaN(value); } /// Given a single argument, return the NaN value which would be returned by an ARM processor. /// If the argument isn't a NaN, returns boost::none. inline boost::optional ProcessNaNs(u32 a) { if (IsSNaN(a)) { return a | 0x00400000; } else if (IsQNaN(a)) { return a; } return boost::none; } /// Given a pair of arguments, return the NaN value which would be returned by an ARM processor. /// If neither argument is a NaN, returns boost::none. inline boost::optional ProcessNaNs(u32 a, u32 b) { if (IsSNaN(a)) { return a | 0x00400000; } else if (IsSNaN(b)) { return b | 0x00400000; } else if (IsQNaN(a)) { return a; } else if (IsQNaN(b)) { return b; } return boost::none; } /// Given three arguments, return the NaN value which would be returned by an ARM processor. /// If none of the arguments is a NaN, returns boost::none. inline boost::optional ProcessNaNs(u32 a, u32 b, u32 c) { if (IsSNaN(a)) { return a | 0x00400000; } else if (IsSNaN(b)) { return b | 0x00400000; } else if (IsSNaN(c)) { return c | 0x00400000; } else if (IsQNaN(a)) { return a; } else if (IsQNaN(b)) { return b; } else if (IsQNaN(c)) { return c; } return boost::none; } /// Is 64-bit floating point value a zero? constexpr bool IsZero(u64 value) { return (value & 0x7FFF'FFFF'FFFF'FFFF) == 0; } /// Is 64-bit floating point value an infinity? constexpr bool IsInf(u64 value) { return (value & 0x7FFF'FFFF'FFFF'FFFF) == 0x7FF0'0000'0000'000; } /// Is 64-bit floating point value a QNaN? constexpr bool IsQNaN(u64 value) { return (value & 0x7FF8'0000'0000'0000) == 0x7FF8'0000'0000'0000; } /// Is 64-bit floating point value a SNaN? constexpr bool IsSNaN(u64 value) { return (value & 0x7FF8'0000'0000'0000) == 0x7FF0'0000'0000'0000 && (value & 0x0007'FFFF'FFFF'FFFF) != 0; } /// Is 64-bit floating point value a NaN? constexpr bool IsNaN(u64 value) { return IsQNaN(value) || IsSNaN(value); } /// Given a single argument, return the NaN value which would be returned by an ARM processor. /// If the argument isn't a NaN, returns boost::none. inline boost::optional ProcessNaNs(u64 a) { if (IsSNaN(a)) { return a | 0x0008'0000'0000'0000; } else if (IsQNaN(a)) { return a; } return boost::none; } /// Given a pair of arguments, return the NaN value which would be returned by an ARM processor. /// If neither argument is a NaN, returns boost::none. inline boost::optional ProcessNaNs(u64 a, u64 b) { if (IsSNaN(a)) { return a | 0x0008'0000'0000'0000; } else if (IsSNaN(b)) { return b | 0x0008'0000'0000'0000; } else if (IsQNaN(a)) { return a; } else if (IsQNaN(b)) { return b; } return boost::none; } /// Given three arguments, return the NaN value which would be returned by an ARM processor. /// If none of the arguments is a NaN, returns boost::none. inline boost::optional ProcessNaNs(u64 a, u64 b, u64 c) { if (IsSNaN(a)) { return a | 0x0008'0000'0000'0000; } else if (IsSNaN(b)) { return b | 0x0008'0000'0000'0000; } else if (IsSNaN(c)) { return c | 0x0008'0000'0000'0000; } else if (IsQNaN(a)) { return a; } else if (IsQNaN(b)) { return b; } else if (IsQNaN(c)) { return c; } return boost::none; } } // namespace Dynarmic::FP