2020-04-22 20:46:23 +01:00

156 lines
4.4 KiB
C++

/* 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 <boost/optional.hpp>
#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<u32> 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<u32> 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<u32> 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<u64> 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<u64> 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<u64> 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