diff --git a/Utilities/BEType.h b/Utilities/BEType.h index e845ad05e9..7957b6cd48 100644 --- a/Utilities/BEType.h +++ b/Utilities/BEType.h @@ -1,6 +1,7 @@ #pragma once #include "types.h" +#include "util/endian.hpp" #include // 128-bit vector type and also se_storage<> storage type @@ -332,339 +333,13 @@ inline v128 operator~(const v128& other) return v128::from64(~other._u64[0], ~other._u64[1]); } -template -struct se_storage -{ - struct type - { - alignas(Align) std::byte data[Size]; - }; - - // Unoptimized generic byteswap for unaligned data - static void reverse(u8* dst, const u8* src) - { - for (std::size_t i = 0; i < Size; i++) - { - dst[i] = src[Size - 1 - i]; - } - } - - static type to(const T& src) - { - type result; - reverse(reinterpret_cast(&result), reinterpret_cast(&src)); - return result; - } - - static T from(const type& src) - { - T result; - reverse(reinterpret_cast(&result), reinterpret_cast(&src)); - return result; - } -}; - -template -struct se_storage -{ - using type = u16; - - static constexpr u16 swap(u16 src) - { -#if defined(__GNUG__) - return __builtin_bswap16(src); -#else - return _byteswap_ushort(src); -#endif - } - - static inline u16 to(const T& src) - { - return swap(std::bit_cast(src)); - } - - static inline T from(u16 src) - { - return std::bit_cast(swap(src)); - } -}; - -template -struct se_storage -{ - using type = u32; - - static constexpr u32 swap(u32 src) - { -#if defined(__GNUG__) - return __builtin_bswap32(src); -#else - return _byteswap_ulong(src); -#endif - } - - static inline u32 to(const T& src) - { - return swap(std::bit_cast(src)); - } - - static inline T from(u32 src) - { - return std::bit_cast(swap(src)); - } -}; - -template -struct se_storage -{ - using type = u64; - - static constexpr u64 swap(u64 src) - { -#if defined(__GNUG__) - return __builtin_bswap64(src); -#else - return _byteswap_uint64(src); -#endif - } - - static inline u64 to(const T& src) - { - return swap(std::bit_cast(src)); - } - - static inline T from(u64 src) - { - return std::bit_cast(swap(src)); - } -}; - -template -struct se_storage -{ - using type = v128; - - static inline v128 swap(const v128& src) - { - return v128::from64(se_storage::swap(src._u64[1]), se_storage::swap(src._u64[0])); - } - - static inline v128 to(const T& src) - { - return swap(std::bit_cast(src)); - } - - static inline T from(const v128& src) - { - return std::bit_cast(swap(src)); - } -}; - -// Switched endianness -template -class se_t -{ - using type = typename std::remove_cv::type; - using stype = typename se_storage::type; - using storage = se_storage; - - stype m_data; - - static_assert(!std::is_pointer::value, "se_t<> error: invalid type (pointer)"); - static_assert(!std::is_reference::value, "se_t<> error: invalid type (reference)"); - static_assert(!std::is_array::value, "se_t<> error: invalid type (array)"); - static_assert(sizeof(type) == alignof(type), "se_t<> error: unexpected alignment"); - -public: - se_t() = default; - - se_t(const se_t& right) = default; - - se_t(type value) - : m_data(storage::to(value)) - { - } - - type value() const - { - return storage::from(m_data); - } - - stype& raw() - { - return m_data; - } - - se_t& operator=(const se_t&) = default; - - se_t& operator=(type value) - { - return m_data = storage::to(value), *this; - } - - using simple_type = simple_t; - - operator type() const - { - return storage::from(m_data); - } -}; - -// Native endianness -template -class se_t -{ - using type = typename std::remove_cv::type; - using stype = typename se_storage::type; - using storage = se_storage; - - static_assert(!std::is_pointer::value, "se_t<> error: invalid type (pointer)"); - static_assert(!std::is_reference::value, "se_t<> error: invalid type (reference)"); - static_assert(!std::is_array::value, "se_t<> error: invalid type (array)"); - static_assert(sizeof(type) == alignof(type), "se_t<> error: unexpected alignment"); - - stype m_data; - -public: - se_t() = default; - - se_t(type value) - : m_data(std::bit_cast(value)) - { - } - - type value() const - { - return std::bit_cast(m_data); - } - - stype& raw() - { - return m_data; - } - - se_t& operator=(const se_t& value) = default; - - se_t& operator=(type value) - { - m_data = std::bit_cast(value); - return *this; - } - - using simple_type = simple_t; - - operator type() const - { - return value(); - } -}; +using stx::se_t; +using stx::se_storage; // se_t<> with native endianness template using nse_t = se_t; -template -inline se_t& operator+=(se_t& left, const T1& right) -{ - auto value = left.value(); - return left = (value += right); -} - -template -inline se_t& operator-=(se_t& left, const T1& right) -{ - auto value = left.value(); - return left = (value -= right); -} - -template -inline se_t& operator*=(se_t& left, const T1& right) -{ - auto value = left.value(); - return left = (value *= right); -} - -template -inline se_t& operator/=(se_t& left, const T1& right) -{ - auto value = left.value(); - return left = (value /= right); -} - -template -inline se_t& operator%=(se_t& left, const T1& right) -{ - auto value = left.value(); - return left = (value %= right); -} - -template -inline se_t& operator&=(se_t& left, const T1& right) -{ - auto value = left.value(); - return left = (value &= right); -} - -template -inline se_t& operator|=(se_t& left, const T1& right) -{ - auto value = left.value(); - return left = (value |= right); -} - -template -inline se_t& operator^=(se_t& left, const T1& right) -{ - auto value = left.value(); - return left = (value ^= right); -} - -template -inline se_t& operator<<=(se_t& left, const T1& right) -{ - auto value = left.value(); - return left = (value <<= right); -} - -template -inline se_t& operator>>=(se_t& left, const T1& right) -{ - auto value = left.value(); - return left = (value >>= right); -} - -template -inline se_t operator++(se_t& left, int) -{ - auto value = left.value(); - auto result = value++; - left = value; - return result; -} - -template -inline se_t operator--(se_t& left, int) -{ - auto value = left.value(); - auto result = value--; - left = value; - return result; -} - -template -inline se_t& operator++(se_t& right) -{ - auto value = right.value(); - return right = ++value; -} - -template -inline se_t& operator--(se_t& right) -{ - auto value = right.value(); - return right = --value; -} - #if IS_LE_MACHINE == 1 template using be_t = se_t; diff --git a/Utilities/types.h b/Utilities/types.h index 0b87dea161..7471c5550d 100644 --- a/Utilities/types.h +++ b/Utilities/types.h @@ -191,12 +191,6 @@ namespace fmt const fmt_type_info* get_type_info(); } -template -struct se_storage; - -template -class se_t; - template class atomic_t; diff --git a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp index 70318540e4..98c65a30bd 100644 --- a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp @@ -335,7 +335,7 @@ static s32 savedata_check_args(u32 operation, u32 version, vm::cptr dirNam for (auto resv : setBuf->reserved) { - if (resv.raw() != 0) + if (resv) { // ****** sysutil savedata parameter error : 10 ****** return 10; diff --git a/rpcs3/Emu/RSX/CgBinaryFragmentProgram.cpp b/rpcs3/Emu/RSX/CgBinaryFragmentProgram.cpp index dcfe2ff146..521831b4f0 100644 --- a/rpcs3/Emu/RSX/CgBinaryFragmentProgram.cpp +++ b/rpcs3/Emu/RSX/CgBinaryFragmentProgram.cpp @@ -229,7 +229,7 @@ void CgBinaryDisasm::TaskFP() for (u32 i = 0; i < (m_buffer_size - m_offset) / sizeof(u32); i++) { // Get BE data - data[i] = be_t{data[i]}.raw(); + data[i] = std::bit_cast>(data[i]); } enum diff --git a/rpcs3/Emu/RSX/CgBinaryProgram.h b/rpcs3/Emu/RSX/CgBinaryProgram.h index 1458cf129b..06aca47021 100644 --- a/rpcs3/Emu/RSX/CgBinaryProgram.h +++ b/rpcs3/Emu/RSX/CgBinaryProgram.h @@ -375,7 +375,7 @@ public: verify(HERE), (m_buffer_size - m_offset) % sizeof(u32) == 0; for (u32 i = 0; i < (m_buffer_size - m_offset) / sizeof(u32); i++) { - vdata[i] = be_t{vdata[i]}.raw(); + vdata[i] = std::bit_cast>(vdata[i]); } for (u32 i = 0; i < prog.ucodeSize / sizeof(u32); i++) diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index f4c04b9386..b3d957c343 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -336,7 +336,7 @@ namespace rsx { //Endianness is swapped because common upload code expects input in BE //TODO: Implement fast upload path for LE inputs and do away with this - element_push_buffer.push_back(be_t{index}.raw()); + element_push_buffer.push_back(std::bit_cast>(index)); } u32 thread::get_push_buffer_index_count() const diff --git a/rpcs3/Emu/RSX/rsx_methods.cpp b/rpcs3/Emu/RSX/rsx_methods.cpp index 911902dda6..55d55997c7 100644 --- a/rpcs3/Emu/RSX/rsx_methods.cpp +++ b/rpcs3/Emu/RSX/rsx_methods.cpp @@ -65,9 +65,7 @@ namespace rsx rsx->sync_point_request = true; const u32 addr = get_address(method_registers.semaphore_offset_406e(), method_registers.semaphore_context_dma_406e()); - // Get raw BE value - arg = be_t{arg}.raw(); - const auto& sema = vm::_ref>>(addr); + const auto& sema = vm::_ref>>(addr); // TODO: Remove vblank semaphore hack if (sema.load() == arg || addr == rsx->ctxt_addr + 0x30) return; @@ -247,7 +245,7 @@ namespace rsx case rsx::vertex_base_type::ub: case rsx::vertex_base_type::ub256: // Get BE data - arg = be_t{arg}.raw(); + arg = std::bit_cast>(arg); break; default: break; @@ -1301,7 +1299,7 @@ namespace rsx else { std::vector temp(line_length * line_count); - u8* buf = temp.data(); + u8* buf = temp.data(); for (u32 y = 0; y < line_count; ++y) { @@ -1310,7 +1308,7 @@ namespace rsx src += in_pitch; } - buf = temp.data(); + buf = temp.data(); for (u32 y = 0; y < line_count; ++y) { diff --git a/rpcs3/util/endian.hpp b/rpcs3/util/endian.hpp new file mode 100644 index 0000000000..c3983ec802 --- /dev/null +++ b/rpcs3/util/endian.hpp @@ -0,0 +1,297 @@ +#pragma once + +#include +#include "Utilities/types.h" + +namespace stx +{ + template + struct se_storage + { + struct type8 + { + alignas(Align > alignof(T) ? alignof(T) : Align) unsigned char data[sizeof(T)]; + }; + + struct type64 + { + alignas(8) std::uint64_t data[sizeof(T) / 8]; + }; + + using type = std::conditional_t<(Align >= 8 && sizeof(T) % 8 == 0), type64, type8>; + + // Possibly unoptimized generic byteswap for unaligned data + static constexpr type swap(const type& src) noexcept; + }; + + template + struct se_storage + { + using type = std::uint16_t; + + static constexpr std::uint16_t swap(std::uint16_t src) noexcept + { +#if defined(__GNUG__) + return __builtin_bswap16(src); +#else + return _byteswap_ushort(src); +#endif + } + }; + + template + struct se_storage + { + using type = std::uint32_t; + + static constexpr std::uint32_t swap(std::uint32_t src) noexcept + { +#if defined(__GNUG__) + return __builtin_bswap32(src); +#else + return _byteswap_ulong(src); +#endif + } + }; + + template + struct se_storage + { + using type = std::uint64_t; + + static constexpr std::uint64_t swap(std::uint64_t src) noexcept + { +#if defined(__GNUG__) + return __builtin_bswap64(src); +#else + return _byteswap_uint64(src); +#endif + } + }; + + template + constexpr typename se_storage::type se_storage::swap(const type& src) noexcept + { + // Try to keep u16/u32/u64 optimizations at the cost of more bitcasts + if constexpr (sizeof(T) == 1) + { + return src; + } + else if constexpr (sizeof(T) == 2) + { + return std::bit_cast(se_storage::swap(std::bit_cast(src))); + } + else if constexpr (sizeof(T) == 4) + { + return std::bit_cast(se_storage::swap(std::bit_cast(src))); + } + else if constexpr (sizeof(T) == 8) + { + return std::bit_cast(se_storage::swap(std::bit_cast(src))); + } + else if constexpr (sizeof(T) % 8 == 0) + { + type64 tmp = std::bit_cast(src); + type64 dst{}; + + // Swap u64 blocks + for (std::size_t i = 0; i < sizeof(T) / 8; i++) + { + dst.data[i] = se_storage::swap(tmp.data[sizeof(T) / 8 - 1 - i]); + } + + return std::bit_cast(dst); + } + else + { + type dst{}; + + // Swap by moving every byte + for (std::size_t i = 0; i < sizeof(T); i++) + { + dst.data[i] = src.data[sizeof(T) - 1 - i]; + } + + return dst; + } + } + + // Endianness support template + template + class alignas(Align) se_t + { + using type = typename std::remove_cv::type; + using stype = typename se_storage::type; + using storage = se_storage; + + stype m_data; + + static_assert(!std::is_pointer::value, "se_t<> error: invalid type (pointer)"); + static_assert(!std::is_reference::value, "se_t<> error: invalid type (reference)"); + static_assert(!std::is_array::value, "se_t<> error: invalid type (array)"); + static_assert(sizeof(type) == alignof(type), "se_t<> error: unexpected alignment"); + + static stype to_data(type value) noexcept + { + if constexpr (Swap) + { + return storage::swap(std::bit_cast(value)); + } + else + { + return std::bit_cast(value); + } + } + + public: + se_t() = default; + + se_t(const se_t& right) = default; + + se_t(type value) noexcept + : m_data(to_data(value)) + { + } + + type value() const noexcept + { + if constexpr (Swap) + { + return std::bit_cast(storage::swap(m_data)); + } + else + { + return std::bit_cast(m_data); + } + } + + type get() const noexcept + { + return value(); + } + + se_t& operator=(const se_t&) = default; + + se_t& operator=(type value) noexcept + { + m_data = to_data(value); + return *this; + } + + using simple_type = simple_t; + + operator type() const noexcept + { + return value(); + } + +#ifdef _MSC_VER + explicit operator bool() const noexcept + { + static_assert(!type{}); + static_assert(!std::is_floating_point_v); + return !!std::bit_cast(m_data); + } +#endif + + template + se_t& operator+=(const T1& rhs) + { + *this = value() + rhs; + return *this; + } + + template + se_t& operator-=(const T1& rhs) + { + *this = value() - rhs; + return *this; + } + + template + se_t& operator*=(const T1& rhs) + { + *this = value() * rhs; + return *this; + } + + template + se_t& operator/=(const T1& rhs) + { + *this = value() / rhs; + return *this; + } + + template + se_t& operator%=(const T1& rhs) + { + *this = value() % rhs; + return *this; + } + + template + se_t& operator&=(const T1& rhs) + { + *this = value() & rhs; + return *this; + } + + template + se_t& operator|=(const T1& rhs) + { + *this = value() | rhs; + return *this; + } + + template + se_t& operator^=(const T1& rhs) + { + *this = value() ^ rhs; + return *this; + } + + template + se_t& operator<<=(const T1& rhs) + { + *this = value() << rhs; + return *this; + } + + template + se_t& operator>>=(const T1& rhs) + { + *this = value() >> rhs; + return *this; + } + + se_t& operator++() + { + T value = *this; + *this = ++value; + return *this; + } + + se_t& operator--() + { + T value = *this; + *this = --value; + return *this; + } + + T operator++(int) + { + T value = *this; + T result = value++; + *this = value; + return result; + } + + T operator--(int) + { + T value = *this; + T result = value--; + *this = value; + return result; + } + }; +}