// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team // SPDX-License-Identifier: GPL-3.0+ // -------------------------------------------------------------------------------------- // r64 / r128 - Types that are guaranteed to fit in one register // -------------------------------------------------------------------------------------- // Note: Recompilers rely on some of these types and the registers they allocate to, // so be careful if you want to change them #pragma once #include "Pcsx2Defs.h" #include "Pcsx2Types.h" #include "VectorIntrin.h" #include #if defined(_M_X86) // Can't stick them in structs because it breaks calling convention things, yay using r128 = __m128i; // Calling convention setting, yay #define RETURNS_R128 r128 __vectorcall #define TAKES_R128 __vectorcall // And since we can't stick them in structs, we get lots of static methods, yay! [[maybe_unused]] __fi static r128 r128_load(const void* ptr) { return _mm_load_si128(reinterpret_cast(ptr)); } [[maybe_unused]] __fi static void r128_store(void* ptr, r128 val) { return _mm_store_si128(reinterpret_cast(ptr), val); } [[maybe_unused]] __fi static void r128_store_unaligned(void* ptr, r128 val) { return _mm_storeu_si128(reinterpret_cast(ptr), val); } [[maybe_unused]] __fi static r128 r128_zero() { return _mm_setzero_si128(); } /// Expects that r64 came from r64-handling code, and not from a recompiler or something [[maybe_unused]] __fi static r128 r128_from_u64_dup(u64 val) { return _mm_set1_epi64x(val); } [[maybe_unused]] __fi static r128 r128_from_u64_zext(u64 val) { return _mm_set_epi64x(0, val); } [[maybe_unused]] __fi static r128 r128_from_u32_dup(u32 val) { return _mm_set1_epi32(val); } [[maybe_unused]] __fi static r128 r128_from_u32x4(u32 lo0, u32 lo1, u32 hi0, u32 hi1) { return _mm_setr_epi32(lo0, lo1, hi0, hi1); } [[maybe_unused]] __fi static r128 r128_from_u128(const u128& u) { return _mm_loadu_si128(reinterpret_cast(&u)); } [[maybe_unused]] __fi static u32 r128_to_u32(r128 val) { return _mm_cvtsi128_si32(val); } [[maybe_unused]] __fi static u64 r128_to_u64(r128 val) { return _mm_cvtsi128_si64(val); } [[maybe_unused]] __fi static u128 r128_to_u128(r128 val) { alignas(16) u128 ret; _mm_store_si128(reinterpret_cast(&ret), val); return ret; } [[maybe_unused]] __fi static void CopyQWC(void* dest, const void* src) { _mm_store_ps((float*)dest, _mm_load_ps((const float*)src)); } [[maybe_unused]] __fi static void ZeroQWC(void* dest) { _mm_store_ps((float*)dest, _mm_setzero_ps()); } [[maybe_unused]] __fi static void ZeroQWC(u128& dest) { _mm_store_ps((float*)&dest, _mm_setzero_ps()); } #elif defined(_M_ARM64) using r128 = uint32x4_t; #define RETURNS_R128 r128 __vectorcall #define TAKES_R128 __vectorcall [[maybe_unused]] __fi static void CopyQWC(void* dest, const void* src) { vst1q_u8(static_cast(dest), vld1q_u8(static_cast(src))); } [[maybe_unused]] __fi static void ZeroQWC(void* dest) { vst1q_u8(static_cast(dest), vmovq_n_u8(0)); } [[maybe_unused]] __fi static void ZeroQWC(u128& dest) { vst1q_u8(&dest._u8[0], vmovq_n_u8(0)); } [[maybe_unused]] __fi static r128 r128_load(const void* ptr) { return vld1q_u32(reinterpret_cast(ptr)); } [[maybe_unused]] __fi static void r128_store(void* ptr, r128 value) { return vst1q_u32(reinterpret_cast(ptr), value); } [[maybe_unused]] __fi static void r128_store_unaligned(void* ptr, r128 value) { return vst1q_u32(reinterpret_cast(ptr), value); } [[maybe_unused]] __fi static r128 r128_zero() { return vmovq_n_u32(0); } /// Expects that r64 came from r64-handling code, and not from a recompiler or something [[maybe_unused]] __fi static r128 r128_from_u64_dup(u64 val) { return vreinterpretq_u32_u64(vdupq_n_u64(val)); } [[maybe_unused]] __fi static r128 r128_from_u64_zext(u64 val) { return vreinterpretq_u32_u64(vcombine_u64(vcreate_u64(val), vcreate_u64(0))); } [[maybe_unused]] __fi static r128 r128_from_u32_dup(u32 val) { return vdupq_n_u32(val); } [[maybe_unused]] __fi static r128 r128_from_u32x4(u32 lo0, u32 lo1, u32 hi0, u32 hi1) { const u32 values[4] = {lo0, lo1, hi0, hi1}; return vld1q_u32(values); } [[maybe_unused]] __fi static r128 r128_from_u128(const u128& u) { return vld1q_u32(reinterpret_cast(u._u32)); } [[maybe_unused]] __fi static u32 r128_to_u32(r128 val) { return vgetq_lane_u32(val, 0); } [[maybe_unused]] __fi static u64 r128_to_u64(r128 val) { return vgetq_lane_u64(vreinterpretq_u64_u32(val), 0); } [[maybe_unused]] __fi static u128 r128_to_u128(r128 val) { alignas(16) u128 ret; vst1q_u32(ret._u32, val); return ret; } #else #error Unknown architecture. #endif