pcsx2/common/SingleRegisterTypes.h

196 lines
4.7 KiB
C

// 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 <cstring>
#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<const r128*>(ptr));
}
[[maybe_unused]] __fi static void r128_store(void* ptr, r128 val)
{
return _mm_store_si128(reinterpret_cast<r128*>(ptr), val);
}
[[maybe_unused]] __fi static void r128_store_unaligned(void* ptr, r128 val)
{
return _mm_storeu_si128(reinterpret_cast<r128*>(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<const __m128i*>(&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<r128*>(&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<u8*>(dest), vld1q_u8(static_cast<const u8*>(src)));
}
[[maybe_unused]] __fi static void ZeroQWC(void* dest)
{
vst1q_u8(static_cast<u8*>(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<const uint32_t*>(ptr));
}
[[maybe_unused]] __fi static void r128_store(void* ptr, r128 value)
{
return vst1q_u32(reinterpret_cast<uint32_t*>(ptr), value);
}
[[maybe_unused]] __fi static void r128_store_unaligned(void* ptr, r128 value)
{
return vst1q_u32(reinterpret_cast<uint32_t*>(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<const uint32_t*>(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