diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index b86c1521a1..f266a25587 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -493,7 +493,7 @@ namespace rsx default: break; } - fmt::throw_exception("RSXVertexData::GetTypeSize: Bad vertex data type (%d)!", static_cast(type)); + fmt::throw_exception("Bad vertex data type (%d)!", static_cast(type)); } void tiled_region::write(const void *src, u32 width, u32 height, u32 pitch) @@ -552,7 +552,7 @@ namespace rsx } break; default: - ::narrow(tile->comp); + fmt::throw_exception("Bad tile compression type (%d)!", tile->comp); } } @@ -603,7 +603,7 @@ namespace rsx } break; default: - ::narrow(tile->comp); + fmt::throw_exception("Bad tile compression type (%d)!", tile->comp); } } diff --git a/rpcs3/util/types.hpp b/rpcs3/util/types.hpp index e078c2cae0..42c900898f 100644 --- a/rpcs3/util/types.hpp +++ b/rpcs3/util/types.hpp @@ -976,85 +976,33 @@ constexpr decltype(auto) ensure(T&& arg, F&& pred, const_str msg = const_str(), fmt::raw_verify_error(src_loc, msg, 0); } -// narrow() function details -template -struct narrow_impl -{ - // Temporarily (diagnostic) - static_assert(std::is_void_v, "narrow_impl<> specialization not found"); - - // Returns true if value cannot be represented in type To - static constexpr bool test(const From&) - { - // Unspecialized cases (including cast to void) always considered narrowing - return true; - } -}; - -// Unsigned to unsigned narrowing -template -struct narrow_impl && std::is_unsigned_v>> -{ - static constexpr bool test(const From& value) - { - return sizeof(To) < sizeof(From) && static_cast(value) != value; - } -}; - -// Signed to signed narrowing -template -struct narrow_impl && std::is_signed_v>> -{ - static constexpr bool test(const From& value) - { - return sizeof(To) < sizeof(From) && static_cast(value) != value; - } -}; - -// Unsigned to signed narrowing -template -struct narrow_impl && std::is_signed_v>> -{ - static constexpr bool test(const From& value) - { - return sizeof(To) <= sizeof(From) && value > (static_cast>(-1) >> 1); - } -}; - -// Signed to unsigned narrowing (I) -template -struct narrow_impl && std::is_unsigned_v && sizeof(To) >= sizeof(From)>> -{ - static constexpr bool test(const From& value) - { - return value < static_cast(0); - } -}; - -// Signed to unsigned narrowing (II) -template -struct narrow_impl && std::is_unsigned_v && sizeof(To) < sizeof(From)>> -{ - static constexpr bool test(const From& value) - { - return static_cast>(value) > static_cast(-1); - } -}; - -// Simple type enabled (TODO: allow for To as well) -template -struct narrow_impl, From>>> - : narrow_impl, To> -{ -}; - -template (std::declval()))> +template requires (std::is_integral_v() + std::declval())>) [[nodiscard]] constexpr To narrow(const From& value, std::source_location src_loc = std::source_location::current()) { // Narrow check - if (narrow_impl::test(value)) [[unlikely]] + using CommonFrom = std::common_type_t; + using CommonTo = std::common_type_t; + + using UnFrom = std::make_unsigned_t; + using UnTo = std::make_unsigned_t; + + constexpr bool is_from_signed = std::is_signed_v; + constexpr bool is_to_signed = std::is_signed_v; + + constexpr auto from_mask = is_from_signed > is_to_signed ? UnFrom{umax} >> 1 : UnFrom{umax}; + constexpr auto to_mask = is_to_signed > is_from_signed ? UnTo{umax} >> 1 : UnTo{umax}; + + constexpr auto mask = ~(from_mask & to_mask); + + // Signed to unsigned always require test + // Otherwise, this is bit-wise narrowing or conversion between types of different signedness of the same size + if constexpr (is_from_signed > is_to_signed || to_mask < from_mask) { - fmt::raw_verify_error(src_loc, u8"Narrowing error", +value); + // Try to optimize test if both are of the same signedness + if (is_from_signed != is_to_signed ? !!(value & mask) : static_cast(value) != value) [[unlikely]] + { + fmt::raw_verify_error(src_loc, u8"Narrowing error", +value); + } } return static_cast(value);