/* 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/fp/fpcr.h" #include "common/fp/info.h" namespace Dynarmic::FP { /// Is floating point value a zero? template inline bool IsZero(FPT value, FPCR fpcr) { if (fpcr.FZ()) { return (value & FPInfo::exponent_mask) == 0; } return (value & ~FPInfo::sign_mask) == 0; } /// Is floating point value an infinity? template constexpr bool IsInf(FPT value) { return (value & ~FPInfo::sign_mask) == FPInfo::Infinity(false); } /// Is floating point value a QNaN? template constexpr bool IsQNaN(FPT value) { constexpr FPT qnan_bits = FPInfo::exponent_mask | FPInfo::mantissa_msb; return (value & qnan_bits) == qnan_bits; } /// Is floating point value a SNaN? template constexpr bool IsSNaN(FPT value) { constexpr FPT qnan_bits = FPInfo::exponent_mask | FPInfo::mantissa_msb; constexpr FPT snan_bits = FPInfo::exponent_mask; return (value & qnan_bits) == snan_bits && (value & FPInfo::mantissa_mask) != 0; } /// Is floating point value a NaN? template constexpr bool IsNaN(FPT 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 std::nullopt. template constexpr std::optional ProcessNaNs(FPT a) { if (IsSNaN(a)) { return a | FPInfo::mantissa_msb; } else if (IsQNaN(a)) { return a; } return std::nullopt; } /// Given a pair of arguments, return the NaN value which would be returned by an ARM processor. /// If neither argument is a NaN, returns std::nullopt. template constexpr std::optional ProcessNaNs(FPT a, FPT b) { if (IsSNaN(a)) { return a | FPInfo::mantissa_msb; } else if (IsSNaN(b)) { return b | FPInfo::mantissa_msb; } else if (IsQNaN(a)) { return a; } else if (IsQNaN(b)) { return b; } return std::nullopt; } /// Given three arguments, return the NaN value which would be returned by an ARM processor. /// If none of the arguments is a NaN, returns std::nullopt. template constexpr std::optional ProcessNaNs(FPT a, FPT b, FPT c) { if (IsSNaN(a)) { return a | FPInfo::mantissa_msb; } else if (IsSNaN(b)) { return b | FPInfo::mantissa_msb; } else if (IsSNaN(c)) { return c | FPInfo::mantissa_msb; } else if (IsQNaN(a)) { return a; } else if (IsQNaN(b)) { return b; } else if (IsQNaN(c)) { return c; } return std::nullopt; } } // namespace Dynarmic::FP