mirror of
https://github.com/PCSX2/pcsx2.git
synced 2025-12-16 04:08:48 +00:00
161 lines
7.5 KiB
C++
161 lines
7.5 KiB
C++
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
|
// SPDX-License-Identifier: GPL-3.0+
|
|
|
|
#pragma once
|
|
|
|
namespace x86Emitter
|
|
{
|
|
|
|
// =====================================================================================================
|
|
// xImpl_SIMD Types (template free!)
|
|
// =====================================================================================================
|
|
|
|
struct SIMDInstructionInfo {
|
|
/// The prefix byte of a simd instruction. These match up with their (E)VEX encodings.
|
|
enum class Prefix : u32 {
|
|
None = 0,
|
|
P66 = 1,
|
|
PF3 = 2,
|
|
PF2 = 3,
|
|
};
|
|
/// The opcode map of a simd instruction. These match up with their (E)VEX encodings.
|
|
enum class Map : u32 {
|
|
M0F = 1,
|
|
M0F38 = 2,
|
|
M0F3A = 3,
|
|
};
|
|
/// Whether an operation operates on float (ss, ps), integer (b, w, d, q), or double (sd, pd) data.
|
|
/// May be used to choose an appropriate mov instruction if one is needed.
|
|
enum class Type : u32 {
|
|
Float, Integer, Double
|
|
};
|
|
|
|
/// The main opcode
|
|
u32 opcode : 8;
|
|
/// Prefix byte
|
|
Prefix prefix : 2;
|
|
/// Opcode map
|
|
Map map : 5;
|
|
/// Information about the data this operation operates on. Ignored for instructions where the SSE4 and AVX versions have the same number of arguments.
|
|
Type type : 2;
|
|
/// For instructions like pslld, the data that should go into the reg field in place of the first src
|
|
u32 ext : 3;
|
|
/// If true, the two inputs to the function can be swapped without changing its result.
|
|
u32 is_commutative : 1;
|
|
/// If true, the dst and src1 must be the same in AVX (e.g. mov instructions, pshufd)
|
|
u32 is_mov : 1;
|
|
/// If true, get `W` from dst register instead of `w_bit`
|
|
u32 dst_w : 1;
|
|
/// If true, get `W` from src register instead of `w_bit`
|
|
u32 src_w : 1;
|
|
/// If true, the instruction has the VEX W bit set
|
|
u32 w_bit : 1;
|
|
|
|
constexpr SIMDInstructionInfo(u8 opcode_, u8 ext_ = 0)
|
|
: opcode(opcode_), prefix(Prefix::None), map(Map::M0F), type(Type::Float), ext(ext_)
|
|
, is_commutative(false), is_mov(false), dst_w(false), src_w(false), w_bit(false)
|
|
{
|
|
}
|
|
|
|
// For configuration using in a builder-style
|
|
constexpr SIMDInstructionInfo p66() const { SIMDInstructionInfo copy = *this; copy.prefix = Prefix::P66; return copy; }
|
|
constexpr SIMDInstructionInfo pf3() const { SIMDInstructionInfo copy = *this; copy.prefix = Prefix::PF3; return copy; }
|
|
constexpr SIMDInstructionInfo pf2() const { SIMDInstructionInfo copy = *this; copy.prefix = Prefix::PF2; return copy; }
|
|
constexpr SIMDInstructionInfo m0f38() const { SIMDInstructionInfo copy = *this; copy.map = Map::M0F38; return copy; }
|
|
constexpr SIMDInstructionInfo m0f3a() const { SIMDInstructionInfo copy = *this; copy.map = Map::M0F3A; return copy; }
|
|
constexpr SIMDInstructionInfo f() const { SIMDInstructionInfo copy = *this; copy.type = Type::Float; return copy; }
|
|
constexpr SIMDInstructionInfo i() const { SIMDInstructionInfo copy = *this; copy.type = Type::Integer; return copy; }
|
|
constexpr SIMDInstructionInfo d() const { SIMDInstructionInfo copy = *this; copy.type = Type::Double; return copy; }
|
|
constexpr SIMDInstructionInfo w() const { SIMDInstructionInfo copy = *this; copy.w_bit = true; return copy; }
|
|
constexpr SIMDInstructionInfo dstw() const { SIMDInstructionInfo copy = *this; copy.dst_w = true; return copy; }
|
|
constexpr SIMDInstructionInfo srcw() const { SIMDInstructionInfo copy = *this; copy.src_w = true; return copy; }
|
|
constexpr SIMDInstructionInfo commutative() const { SIMDInstructionInfo copy = *this; copy.is_commutative = true; return copy; }
|
|
constexpr SIMDInstructionInfo mov() const { SIMDInstructionInfo copy = *this; copy.is_mov = true; return copy; }
|
|
};
|
|
|
|
// ------------------------------------------------------------------------
|
|
// For implementing SSE/AVX logic operations that have two arguments in both SSE and AVX
|
|
// like MOVAPS, CVTPS2DQ, etc
|
|
//
|
|
struct xImplSimd_2Arg
|
|
{
|
|
SIMDInstructionInfo info;
|
|
|
|
constexpr xImplSimd_2Arg(SIMDInstructionInfo info_): info(info_.mov()) {}
|
|
|
|
void operator()(const xRegisterSSE& dst, const xRegisterSSE& src) const;
|
|
void operator()(const xRegisterSSE& dst, const xIndirectVoid& src) const;
|
|
};
|
|
|
|
// ------------------------------------------------------------------------
|
|
// For implementing SSE/AVX logic operations that have two arguments in both SSE and AVX, plus an immediate
|
|
// like PSHUFD
|
|
//
|
|
struct xImplSimd_2ArgImm
|
|
{
|
|
SIMDInstructionInfo info;
|
|
|
|
constexpr xImplSimd_2ArgImm(SIMDInstructionInfo info_): info(info_.mov()) {}
|
|
|
|
void operator()(const xRegisterSSE& dst, const xRegisterSSE& src, u8 imm) const;
|
|
void operator()(const xRegisterSSE& dst, const xIndirectVoid& src, u8 imm) const;
|
|
};
|
|
|
|
// ------------------------------------------------------------------------
|
|
// For implementing SSE/AVX logic operations that have three arguments AVX and two in SSE
|
|
// like ANDPS, ANDPD, etc
|
|
//
|
|
struct xImplSimd_3Arg
|
|
{
|
|
SIMDInstructionInfo info;
|
|
|
|
void operator()(const xRegisterSSE& dst, const xRegisterSSE& src) const { (*this)(dst, dst, src); }
|
|
void operator()(const xRegisterSSE& dst, const xIndirectVoid& src) const { (*this)(dst, dst, src); }
|
|
void operator()(const xRegisterSSE& dst, const xRegisterSSE& src1, const xRegisterSSE& src2) const;
|
|
void operator()(const xRegisterSSE& dst, const xRegisterSSE& src1, const xIndirectVoid& src2) const;
|
|
};
|
|
|
|
// ------------------------------------------------------------------------
|
|
// For implementing SSE/AVX logic operations that have three arguments AVX and two in SSE
|
|
// like SHUFPS, INSERTPS, etc
|
|
//
|
|
struct xImplSimd_3ArgImm
|
|
{
|
|
SIMDInstructionInfo info;
|
|
|
|
void operator()(const xRegisterSSE& dst, const xRegisterSSE& src, u8 imm) const { (*this)(dst, dst, src, imm); }
|
|
void operator()(const xRegisterSSE& dst, const xIndirectVoid& src, u8 imm) const { (*this)(dst, dst, src, imm); }
|
|
void operator()(const xRegisterSSE& dst, const xRegisterSSE& src1, const xRegisterSSE& src2, u8 imm) const;
|
|
void operator()(const xRegisterSSE& dst, const xRegisterSSE& src1, const xIndirectVoid& src2, u8 imm) const;
|
|
};
|
|
|
|
// ------------------------------------------------------------------------
|
|
// For implementing SSE/AVX logic operations that have three arguments AVX and two in SSE
|
|
// like SHUFPS, INSERTPS, etc
|
|
//
|
|
struct xImplSimd_3ArgCmp
|
|
{
|
|
SIMDInstructionInfo info;
|
|
|
|
void operator()(const xRegisterSSE& dst, const xRegisterSSE& src, SSE2_ComparisonType imm) const { (*this)(dst, dst, src, imm); }
|
|
void operator()(const xRegisterSSE& dst, const xIndirectVoid& src, SSE2_ComparisonType imm) const { (*this)(dst, dst, src, imm); }
|
|
void operator()(const xRegisterSSE& dst, const xRegisterSSE& src1, const xRegisterSSE& src2, SSE2_ComparisonType imm) const;
|
|
void operator()(const xRegisterSSE& dst, const xRegisterSSE& src1, const xIndirectVoid& src2, SSE2_ComparisonType imm) const;
|
|
};
|
|
|
|
// ------------------------------------------------------------------------
|
|
// For implementing SSE/AVX logic operations that have four arguments AVX and two in SSE (with an implicit xmm0)
|
|
// like PBLENDVB, BLENDVPS, etc
|
|
//
|
|
struct xImplSimd_4ArgBlend
|
|
{
|
|
SIMDInstructionInfo sse;
|
|
SIMDInstructionInfo avx;
|
|
|
|
void operator()(const xRegisterSSE& dst, const xRegisterSSE& src) const { (*this)(dst, dst, src, xmm0); }
|
|
void operator()(const xRegisterSSE& dst, const xIndirectVoid& src) const { (*this)(dst, dst, src, xmm0); }
|
|
void operator()(const xRegisterSSE& dst, const xRegisterSSE& src1, const xRegisterSSE& src2, const xRegisterSSE& src3) const;
|
|
void operator()(const xRegisterSSE& dst, const xRegisterSSE& src1, const xIndirectVoid& src2, const xRegisterSSE& src3) const;
|
|
};
|
|
} // end namespace x86Emitter
|