mirror of https://github.com/PCSX2/pcsx2.git
196 lines
4.7 KiB
C
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
|