First Commit
This commit is contained in:
101
common/emitter/implement/avx.h
Normal file
101
common/emitter/implement/avx.h
Normal file
@@ -0,0 +1,101 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace x86Emitter
|
||||
{
|
||||
struct xImplAVX_Move
|
||||
{
|
||||
u8 Prefix;
|
||||
u8 LoadOpcode;
|
||||
u8 StoreOpcode;
|
||||
|
||||
void operator()(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||
void operator()(const xRegisterSSE& to, const xIndirectVoid& from) const;
|
||||
void operator()(const xIndirectVoid& to, const xRegisterSSE& from) const;
|
||||
};
|
||||
|
||||
struct xImplAVX_ThreeArg
|
||||
{
|
||||
u8 Prefix;
|
||||
u8 Opcode;
|
||||
|
||||
void operator()(const xRegisterSSE& to, const xRegisterSSE& from1, const xRegisterSSE& from2) const;
|
||||
void operator()(const xRegisterSSE& to, const xRegisterSSE& from1, const xIndirectVoid& from2) const;
|
||||
};
|
||||
|
||||
struct xImplAVX_ThreeArgYMM : xImplAVX_ThreeArg
|
||||
{
|
||||
void operator()(const xRegisterSSE& to, const xRegisterSSE& from1, const xRegisterSSE& from2) const;
|
||||
void operator()(const xRegisterSSE& to, const xRegisterSSE& from1, const xIndirectVoid& from2) const;
|
||||
};
|
||||
|
||||
struct xImplAVX_ArithFloat
|
||||
{
|
||||
xImplAVX_ThreeArgYMM PS;
|
||||
xImplAVX_ThreeArgYMM PD;
|
||||
xImplAVX_ThreeArg SS;
|
||||
xImplAVX_ThreeArg SD;
|
||||
};
|
||||
|
||||
struct xImplAVX_CmpFloatHelper
|
||||
{
|
||||
SSE2_ComparisonType CType;
|
||||
|
||||
void PS(const xRegisterSSE& to, const xRegisterSSE& from1, const xRegisterSSE& from2) const;
|
||||
void PS(const xRegisterSSE& to, const xRegisterSSE& from1, const xIndirectVoid& from2) const;
|
||||
void PD(const xRegisterSSE& to, const xRegisterSSE& from1, const xRegisterSSE& from2) const;
|
||||
void PD(const xRegisterSSE& to, const xRegisterSSE& from1, const xIndirectVoid& from2) const;
|
||||
|
||||
void SS(const xRegisterSSE& to, const xRegisterSSE& from1, const xRegisterSSE& from2) const;
|
||||
void SS(const xRegisterSSE& to, const xRegisterSSE& from1, const xIndirectVoid& from2) const;
|
||||
void SD(const xRegisterSSE& to, const xRegisterSSE& from1, const xRegisterSSE& from2) const;
|
||||
void SD(const xRegisterSSE& to, const xRegisterSSE& from1, const xIndirectVoid& from2) const;
|
||||
};
|
||||
|
||||
struct xImplAVX_CmpFloat
|
||||
{
|
||||
xImplAVX_CmpFloatHelper EQ;
|
||||
xImplAVX_CmpFloatHelper LT;
|
||||
xImplAVX_CmpFloatHelper LE;
|
||||
xImplAVX_CmpFloatHelper UO;
|
||||
xImplAVX_CmpFloatHelper NE;
|
||||
xImplAVX_CmpFloatHelper GE;
|
||||
xImplAVX_CmpFloatHelper GT;
|
||||
xImplAVX_CmpFloatHelper OR;
|
||||
};
|
||||
|
||||
struct xImplAVX_CmpInt
|
||||
{
|
||||
// Compare packed bytes for equality.
|
||||
// If a data element in dest is equal to the corresponding date element src, the
|
||||
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
|
||||
const xImplAVX_ThreeArgYMM EQB;
|
||||
|
||||
// Compare packed words for equality.
|
||||
// If a data element in dest is equal to the corresponding date element src, the
|
||||
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
|
||||
const xImplAVX_ThreeArgYMM EQW;
|
||||
|
||||
// Compare packed doublewords [32-bits] for equality.
|
||||
// If a data element in dest is equal to the corresponding date element src, the
|
||||
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
|
||||
const xImplAVX_ThreeArgYMM EQD;
|
||||
|
||||
// Compare packed signed bytes for greater than.
|
||||
// If a data element in dest is greater than the corresponding date element src, the
|
||||
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
|
||||
const xImplAVX_ThreeArgYMM GTB;
|
||||
|
||||
// Compare packed signed words for greater than.
|
||||
// If a data element in dest is greater than the corresponding date element src, the
|
||||
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
|
||||
const xImplAVX_ThreeArgYMM GTW;
|
||||
|
||||
// Compare packed signed doublewords [32-bits] for greater than.
|
||||
// If a data element in dest is greater than the corresponding date element src, the
|
||||
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
|
||||
const xImplAVX_ThreeArgYMM GTD;
|
||||
};
|
||||
} // namespace x86Emitter
|
||||
49
common/emitter/implement/bmi.h
Normal file
49
common/emitter/implement/bmi.h
Normal file
@@ -0,0 +1,49 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
// Implement BMI1/BMI2 instruction set
|
||||
|
||||
namespace x86Emitter
|
||||
{
|
||||
|
||||
struct xImplBMI_RVM
|
||||
{
|
||||
u8 Prefix;
|
||||
u8 MbPrefix;
|
||||
u8 Opcode;
|
||||
|
||||
// RVM
|
||||
// MULX Unsigned multiply without affecting flags, and arbitrary destination registers
|
||||
// PDEP Parallel bits deposit
|
||||
// PEXT Parallel bits extract
|
||||
// ANDN Logical and not ~x & y
|
||||
void operator()(const xRegisterInt& to, const xRegisterInt& from1, const xRegisterInt& from2) const;
|
||||
void operator()(const xRegisterInt& to, const xRegisterInt& from1, const xIndirectVoid& from2) const;
|
||||
|
||||
#if 0
|
||||
// RMV
|
||||
// BEXTR Bit field extract (with register) (src >> start) & ((1 << len)-1)[9]
|
||||
// BZHI Zero high bits starting with specified bit position
|
||||
// SARX Shift arithmetic right without affecting flags
|
||||
// SHRX Shift logical right without affecting flags
|
||||
// SHLX Shift logical left without affecting flags
|
||||
// FIXME: WARNING same as above but V and M are inverted
|
||||
//void operator()( const xRegisterInt& to, const xRegisterInt& from1, const xRegisterInt& from2) const;
|
||||
//void operator()( const xRegisterInt& to, const xIndirectVoid& from1, const xRegisterInt& from2) const;
|
||||
|
||||
// VM
|
||||
// BLSI Extract lowest set isolated bit x & -x
|
||||
// BLSMSK Get mask up to lowest set bit x ^ (x - 1)
|
||||
// BLSR Reset lowest set bit x & (x - 1)
|
||||
void operator()( const xRegisterInt& to, const xRegisterInt& from) const;
|
||||
void operator()( const xRegisterInt& to, const xIndirectVoid& from) const;
|
||||
|
||||
// RMI
|
||||
//RORX Rotate right logical without affecting flags
|
||||
void operator()( const xRegisterInt& to, const xRegisterInt& from, u8 imm) const;
|
||||
void operator()( const xRegisterInt& to, const xIndirectVoid& from, u8 imm) const;
|
||||
#endif
|
||||
};
|
||||
} // namespace x86Emitter
|
||||
32
common/emitter/implement/dwshift.h
Normal file
32
common/emitter/implement/dwshift.h
Normal file
@@ -0,0 +1,32 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace x86Emitter
|
||||
{
|
||||
|
||||
// Implementations here cover SHLD and SHRD.
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_DowrdShift
|
||||
// --------------------------------------------------------------------------------------
|
||||
// I use explicit method declarations here instead of templates, in order to provide
|
||||
// *only* 32 and 16 bit register operand forms (8 bit registers are not valid in SHLD/SHRD).
|
||||
//
|
||||
// Optimization Note: Imm shifts by 0 are ignore (no code generated). This is a safe optimization
|
||||
// because shifts by 0 do *not* affect flags status (intel docs cited).
|
||||
//
|
||||
struct xImpl_DwordShift
|
||||
{
|
||||
u16 OpcodeBase;
|
||||
|
||||
void operator()(const xRegister16or32or64& to, const xRegister16or32or64& from, const xRegisterCL& clreg) const;
|
||||
|
||||
void operator()(const xRegister16or32or64& to, const xRegister16or32or64& from, u8 shiftcnt) const;
|
||||
|
||||
void operator()(const xIndirectVoid& dest, const xRegister16or32or64& from, const xRegisterCL& clreg) const;
|
||||
void operator()(const xIndirectVoid& dest, const xRegister16or32or64& from, u8 shiftcnt) const;
|
||||
};
|
||||
|
||||
} // End namespace x86Emitter
|
||||
131
common/emitter/implement/group1.h
Normal file
131
common/emitter/implement/group1.h
Normal file
@@ -0,0 +1,131 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace x86Emitter
|
||||
{
|
||||
|
||||
enum G1Type
|
||||
{
|
||||
G1Type_ADD = 0,
|
||||
G1Type_OR,
|
||||
G1Type_ADC,
|
||||
G1Type_SBB,
|
||||
G1Type_AND,
|
||||
G1Type_SUB,
|
||||
G1Type_XOR,
|
||||
G1Type_CMP
|
||||
};
|
||||
|
||||
extern void _g1_EmitOp(G1Type InstType, const xRegisterInt& to, const xRegisterInt& from);
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_Group1
|
||||
// --------------------------------------------------------------------------------------
|
||||
struct xImpl_Group1
|
||||
{
|
||||
G1Type InstType;
|
||||
|
||||
void operator()(const xRegisterInt& to, const xRegisterInt& from) const;
|
||||
|
||||
void operator()(const xIndirectVoid& to, const xRegisterInt& from) const;
|
||||
void operator()(const xRegisterInt& to, const xIndirectVoid& from) const;
|
||||
void operator()(const xRegisterInt& to, int imm) const;
|
||||
void operator()(const xIndirect64orLess& to, int imm) const;
|
||||
|
||||
#if 0
|
||||
// ------------------------------------------------------------------------
|
||||
template< typename T > __noinline void operator()( const ModSibBase& to, const xImmReg<T>& immOrReg ) const
|
||||
{
|
||||
_DoI_helpermess( *this, to, immOrReg );
|
||||
}
|
||||
|
||||
template< typename T > __noinline void operator()( const xDirectOrIndirect<T>& to, const xImmReg<T>& immOrReg ) const
|
||||
{
|
||||
_DoI_helpermess( *this, to, immOrReg );
|
||||
}
|
||||
|
||||
template< typename T > __noinline void operator()( const xDirectOrIndirect<T>& to, int imm ) const
|
||||
{
|
||||
_DoI_helpermess( *this, to, imm );
|
||||
}
|
||||
|
||||
template< typename T > __noinline void operator()( const xDirectOrIndirect<T>& to, const xDirectOrIndirect<T>& from ) const
|
||||
{
|
||||
_DoI_helpermess( *this, to, from );
|
||||
}
|
||||
|
||||
// FIXME : Make this struct to 8, 16, and 32 bit registers
|
||||
template< typename T > __noinline void operator()( const xRegisterBase& to, const xDirectOrIndirect<T>& from ) const
|
||||
{
|
||||
_DoI_helpermess( *this, xDirectOrIndirect<T>( to ), from );
|
||||
}
|
||||
|
||||
// FIXME : Make this struct to 8, 16, and 32 bit registers
|
||||
template< typename T > __noinline void operator()( const xDirectOrIndirect<T>& to, const xRegisterBase& from ) const
|
||||
{
|
||||
_DoI_helpermess( *this, to, xDirectOrIndirect<T>( from ) );
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// This class combines x86 with SSE/SSE2 logic operations (ADD, OR, and NOT).
|
||||
// Note: ANDN [AndNot] is handled below separately.
|
||||
//
|
||||
struct xImpl_G1Logic
|
||||
{
|
||||
G1Type InstType;
|
||||
|
||||
void operator()(const xRegisterInt& to, const xRegisterInt& from) const;
|
||||
|
||||
void operator()(const xIndirectVoid& to, const xRegisterInt& from) const;
|
||||
void operator()(const xRegisterInt& to, const xIndirectVoid& from) const;
|
||||
void operator()(const xRegisterInt& to, int imm) const;
|
||||
|
||||
void operator()(const xIndirect64orLess& to, int imm) const;
|
||||
|
||||
xImplSimd_DestRegSSE PS; // packed single precision
|
||||
xImplSimd_DestRegSSE PD; // packed double precision
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// This class combines x86 with SSE/SSE2 arithmetic operations (ADD/SUB).
|
||||
//
|
||||
struct xImpl_G1Arith
|
||||
{
|
||||
G1Type InstType;
|
||||
|
||||
void operator()(const xRegisterInt& to, const xRegisterInt& from) const;
|
||||
|
||||
void operator()(const xIndirectVoid& to, const xRegisterInt& from) const;
|
||||
void operator()(const xRegisterInt& to, const xIndirectVoid& from) const;
|
||||
void operator()(const xRegisterInt& to, int imm) const;
|
||||
|
||||
void operator()(const xIndirect64orLess& to, int imm) const;
|
||||
|
||||
xImplSimd_DestRegSSE PS; // packed single precision
|
||||
xImplSimd_DestRegSSE PD; // packed double precision
|
||||
xImplSimd_DestRegSSE SS; // scalar single precision
|
||||
xImplSimd_DestRegSSE SD; // scalar double precision
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
struct xImpl_G1Compare
|
||||
{
|
||||
void operator()(const xRegisterInt& to, const xRegisterInt& from) const;
|
||||
|
||||
void operator()(const xIndirectVoid& to, const xRegisterInt& from) const;
|
||||
void operator()(const xRegisterInt& to, const xIndirectVoid& from) const;
|
||||
void operator()(const xRegisterInt& to, int imm) const;
|
||||
|
||||
void operator()(const xIndirect64orLess& to, int imm) const;
|
||||
|
||||
xImplSimd_DestSSE_CmpImm PS;
|
||||
xImplSimd_DestSSE_CmpImm PD;
|
||||
xImplSimd_DestSSE_CmpImm SS;
|
||||
xImplSimd_DestSSE_CmpImm SD;
|
||||
};
|
||||
|
||||
} // End namespace x86Emitter
|
||||
51
common/emitter/implement/group2.h
Normal file
51
common/emitter/implement/group2.h
Normal file
@@ -0,0 +1,51 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace x86Emitter
|
||||
{
|
||||
|
||||
enum G2Type
|
||||
{
|
||||
G2Type_ROL = 0,
|
||||
G2Type_ROR,
|
||||
G2Type_RCL,
|
||||
G2Type_RCR,
|
||||
G2Type_SHL,
|
||||
G2Type_SHR,
|
||||
G2Type_Unused,
|
||||
G2Type_SAR
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_Group2
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Group 2 (shift) instructions have no Sib/ModRM forms.
|
||||
// Optimization Note: For Imm forms, we ignore the instruction if the shift count is zero.
|
||||
// This is a safe optimization since any zero-value shift does not affect any flags.
|
||||
//
|
||||
struct xImpl_Group2
|
||||
{
|
||||
G2Type InstType;
|
||||
|
||||
void operator()(const xRegisterInt& to, const xRegisterCL& from) const;
|
||||
void operator()(const xIndirect64orLess& to, const xRegisterCL& from) const;
|
||||
void operator()(const xRegisterInt& to, u8 imm) const;
|
||||
void operator()(const xIndirect64orLess& to, u8 imm) const;
|
||||
|
||||
#if 0
|
||||
// ------------------------------------------------------------------------
|
||||
template< typename T > __noinline void operator()( const xDirectOrIndirect<T>& to, u8 imm ) const
|
||||
{
|
||||
_DoI_helpermess( *this, to, imm );
|
||||
}
|
||||
|
||||
template< typename T > __noinline void operator()( const xDirectOrIndirect<T>& to, const xRegisterCL& from ) const
|
||||
{
|
||||
_DoI_helpermess( *this, to, from );
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
} // End namespace x86Emitter
|
||||
97
common/emitter/implement/group3.h
Normal file
97
common/emitter/implement/group3.h
Normal file
@@ -0,0 +1,97 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace x86Emitter
|
||||
{
|
||||
|
||||
enum G3Type
|
||||
{
|
||||
G3Type_NOT = 2,
|
||||
G3Type_NEG = 3,
|
||||
G3Type_MUL = 4,
|
||||
G3Type_iMUL = 5, // partial implementation, iMul has additional forms in ix86.cpp
|
||||
G3Type_DIV = 6,
|
||||
G3Type_iDIV = 7
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_Group3
|
||||
// --------------------------------------------------------------------------------------
|
||||
struct xImpl_Group3
|
||||
{
|
||||
G3Type InstType;
|
||||
|
||||
void operator()(const xRegisterInt& from) const;
|
||||
void operator()(const xIndirect64orLess& from) const;
|
||||
|
||||
#if 0
|
||||
template< typename T >
|
||||
void operator()( const xDirectOrIndirect<T>& from ) const
|
||||
{
|
||||
_DoI_helpermess( *this, from );
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_MulDivBase
|
||||
// --------------------------------------------------------------------------------------
|
||||
// This class combines x86 and SSE/SSE2 instructions for iMUL and iDIV.
|
||||
//
|
||||
struct xImpl_MulDivBase
|
||||
{
|
||||
G3Type InstType;
|
||||
u16 OpcodeSSE;
|
||||
|
||||
void operator()(const xRegisterInt& from) const;
|
||||
void operator()(const xIndirect64orLess& from) const;
|
||||
|
||||
const xImplSimd_DestRegSSE PS;
|
||||
const xImplSimd_DestRegSSE PD;
|
||||
const xImplSimd_DestRegSSE SS;
|
||||
const xImplSimd_DestRegSSE SD;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_iDiv
|
||||
// --------------------------------------------------------------------------------------
|
||||
struct xImpl_iDiv
|
||||
{
|
||||
void operator()(const xRegisterInt& from) const;
|
||||
void operator()(const xIndirect64orLess& from) const;
|
||||
|
||||
const xImplSimd_DestRegSSE PS;
|
||||
const xImplSimd_DestRegSSE PD;
|
||||
const xImplSimd_DestRegSSE SS;
|
||||
const xImplSimd_DestRegSSE SD;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_iMul
|
||||
// --------------------------------------------------------------------------------------
|
||||
//
|
||||
struct xImpl_iMul
|
||||
{
|
||||
void operator()(const xRegisterInt& from) const;
|
||||
void operator()(const xIndirect64orLess& from) const;
|
||||
|
||||
// The following iMul-specific forms are valid for 16 and 32 bit register operands only!
|
||||
|
||||
void operator()(const xRegister32& to, const xRegister32& from) const;
|
||||
void operator()(const xRegister32& to, const xIndirectVoid& src) const;
|
||||
void operator()(const xRegister16& to, const xRegister16& from) const;
|
||||
void operator()(const xRegister16& to, const xIndirectVoid& src) const;
|
||||
|
||||
void operator()(const xRegister32& to, const xRegister32& from, s32 imm) const;
|
||||
void operator()(const xRegister32& to, const xIndirectVoid& from, s32 imm) const;
|
||||
void operator()(const xRegister16& to, const xRegister16& from, s16 imm) const;
|
||||
void operator()(const xRegister16& to, const xIndirectVoid& from, s16 imm) const;
|
||||
|
||||
const xImplSimd_DestRegSSE PS;
|
||||
const xImplSimd_DestRegSSE PD;
|
||||
const xImplSimd_DestRegSSE SS;
|
||||
const xImplSimd_DestRegSSE SD;
|
||||
};
|
||||
} // namespace x86Emitter
|
||||
80
common/emitter/implement/helpers.h
Normal file
80
common/emitter/implement/helpers.h
Normal file
@@ -0,0 +1,80 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace x86Emitter
|
||||
{
|
||||
|
||||
// helpermess is currently broken >_<
|
||||
|
||||
#if 0
|
||||
|
||||
template< typename xImpl, typename T >
|
||||
void _DoI_helpermess( const xImpl& helpme, const xDirectOrIndirect& to, const xImmReg<T>& immOrReg )
|
||||
{
|
||||
if( to.IsDirect() )
|
||||
{
|
||||
if( immOrReg.IsReg() )
|
||||
helpme( to.GetReg(), immOrReg.GetReg() );
|
||||
else
|
||||
helpme( to.GetReg(), immOrReg.GetImm() );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( immOrReg.IsReg() )
|
||||
helpme( to.GetMem(), immOrReg.GetReg() );
|
||||
else
|
||||
helpme( to.GetMem(), immOrReg.GetImm() );
|
||||
}
|
||||
}
|
||||
|
||||
template< typename xImpl, typename T >
|
||||
void _DoI_helpermess( const xImpl& helpme, const ModSibBase& to, const xImmReg<T>& immOrReg )
|
||||
{
|
||||
if( immOrReg.IsReg() )
|
||||
helpme( to, immOrReg.GetReg() );
|
||||
else
|
||||
helpme( (ModSibStrict)to, immOrReg.GetImm() );
|
||||
}
|
||||
|
||||
template< typename xImpl, typename T >
|
||||
void _DoI_helpermess( const xImpl& helpme, const xDirectOrIndirect<T>& to, int imm )
|
||||
{
|
||||
if( to.IsDirect() )
|
||||
helpme( to.GetReg(), imm );
|
||||
else
|
||||
helpme( to.GetMem(), imm );
|
||||
}
|
||||
|
||||
template< typename xImpl, typename T >
|
||||
void _DoI_helpermess( const xImpl& helpme, const xDirectOrIndirect<T>& parm )
|
||||
{
|
||||
if( parm.IsDirect() )
|
||||
helpme( parm.GetReg() );
|
||||
else
|
||||
helpme( parm.GetMem() );
|
||||
}
|
||||
|
||||
template< typename xImpl, typename T >
|
||||
void _DoI_helpermess( const xImpl& helpme, const xDirectOrIndirect<T>& to, const xDirectOrIndirect<T>& from )
|
||||
{
|
||||
if( to.IsDirect() && from.IsDirect() )
|
||||
helpme( to.GetReg(), from.GetReg() );
|
||||
|
||||
else if( to.IsDirect() )
|
||||
helpme( to.GetReg(), from.GetMem() );
|
||||
|
||||
else if( from.IsDirect() )
|
||||
helpme( to.GetMem(), from.GetReg() );
|
||||
|
||||
else
|
||||
|
||||
// One of the fields needs to be direct, or else we cannot complete the operation.
|
||||
// (intel doesn't support indirects in both fields)
|
||||
|
||||
pxFailDev( "Invalid asm instruction: Both operands are indirect memory addresses." );
|
||||
}
|
||||
#endif
|
||||
|
||||
} // End namespace x86Emitter
|
||||
23
common/emitter/implement/incdec.h
Normal file
23
common/emitter/implement/incdec.h
Normal file
@@ -0,0 +1,23 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
// Implementations found here: Increment and Decrement Instructions!
|
||||
// (They're soooo lonely... but I dunno where else to stick this class!)
|
||||
|
||||
namespace x86Emitter
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_IncDec
|
||||
// --------------------------------------------------------------------------------------
|
||||
struct xImpl_IncDec
|
||||
{
|
||||
bool isDec;
|
||||
|
||||
void operator()(const xRegisterInt& to) const;
|
||||
void operator()(const xIndirect64orLess& to) const;
|
||||
};
|
||||
|
||||
} // End namespace x86Emitter
|
||||
80
common/emitter/implement/jmpcall.h
Normal file
80
common/emitter/implement/jmpcall.h
Normal file
@@ -0,0 +1,80 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
// Implementations found here: CALL and JMP! (unconditional only)
|
||||
|
||||
namespace x86Emitter
|
||||
{
|
||||
|
||||
extern void xJccKnownTarget(JccComparisonType comparison, const void* target, bool slideForward);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
struct xImpl_JmpCall
|
||||
{
|
||||
bool isJmp;
|
||||
|
||||
void operator()(const xAddressReg& absreg) const;
|
||||
void operator()(const xIndirectNative& src) const;
|
||||
|
||||
// Special form for calling functions. This form automatically resolves the
|
||||
// correct displacement based on the size of the instruction being generated.
|
||||
void operator()(const void* func) const
|
||||
{
|
||||
if (isJmp)
|
||||
xJccKnownTarget(Jcc_Unconditional, (const void*)(uptr)func, false); // double cast to/from (uptr) needed to appease GCC
|
||||
else
|
||||
{
|
||||
// calls are relative to the instruction after this one, and length is
|
||||
// always 5 bytes (16 bit calls are bad mojo, so no bother to do special logic).
|
||||
|
||||
sptr dest = (sptr)func - ((sptr)xGetPtr() + 5);
|
||||
pxAssertMsg(dest == (s32)dest, "Indirect jump is too far, must use a register!");
|
||||
xWrite8(0xe8);
|
||||
xWrite32(dest);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// yes it is awful. Due to template code is in a header with a nice circular dep.
|
||||
extern const xImpl_Mov xMOV;
|
||||
extern const xImpl_JmpCall xCALL;
|
||||
|
||||
struct xImpl_FastCall
|
||||
{
|
||||
// FIXME: current 64 bits is mostly a copy/past potentially it would require to push/pop
|
||||
// some registers. But I think it is enough to handle the first call.
|
||||
|
||||
void operator()(const void* f, const xRegister32& a1 = xEmptyReg, const xRegister32& a2 = xEmptyReg) const;
|
||||
|
||||
void operator()(const void* f, u32 a1, const xRegister32& a2) const;
|
||||
void operator()(const void* f, const xIndirect32& a1) const;
|
||||
void operator()(const void* f, u32 a1, u32 a2) const;
|
||||
void operator()(const void* f, void* a1) const;
|
||||
|
||||
void operator()(const void* f, const xRegisterLong& a1, const xRegisterLong& a2 = xEmptyReg) const;
|
||||
void operator()(const void* f, u32 a1, const xRegisterLong& a2) const;
|
||||
|
||||
template <typename T>
|
||||
__fi void operator()(T* func, u32 a1, const xRegisterLong& a2 = xEmptyReg) const
|
||||
{
|
||||
(*this)((const void*)func, a1, a2);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__fi void operator()(T* func, const xIndirect32& a1) const
|
||||
{
|
||||
(*this)((const void*)func, a1);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__fi void operator()(T* func, u32 a1, u32 a2) const
|
||||
{
|
||||
(*this)((const void*)func, a1, a2);
|
||||
}
|
||||
|
||||
void operator()(const xIndirectNative& f, const xRegisterLong& a1 = xEmptyReg, const xRegisterLong& a2 = xEmptyReg) const;
|
||||
};
|
||||
|
||||
} // End namespace x86Emitter
|
||||
128
common/emitter/implement/movs.h
Normal file
128
common/emitter/implement/movs.h
Normal file
@@ -0,0 +1,128 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
// Header: ix86_impl_movs.h -- covers mov, cmov, movsx/movzx, and SETcc (which shares
|
||||
// with cmov many similarities).
|
||||
|
||||
namespace x86Emitter
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// MovImplAll
|
||||
// --------------------------------------------------------------------------------------
|
||||
// MOV instruction Implementation, plus many SIMD sub-mov variants.
|
||||
//
|
||||
struct xImpl_Mov
|
||||
{
|
||||
xImpl_Mov() {} // Satisfy GCC's whims.
|
||||
|
||||
void operator()(const xRegisterInt& to, const xRegisterInt& from) const;
|
||||
void operator()(const xIndirectVoid& dest, const xRegisterInt& from) const;
|
||||
void operator()(const xRegisterInt& to, const xIndirectVoid& src) const;
|
||||
void operator()(const xIndirect64orLess& dest, sptr imm) const;
|
||||
void operator()(const xRegisterInt& to, sptr imm, bool preserve_flags = false) const;
|
||||
|
||||
#if 0
|
||||
template< typename T > __noinline void operator()( const ModSibBase& to, const xImmReg<T>& immOrReg ) const
|
||||
{
|
||||
_DoI_helpermess( *this, to, immOrReg );
|
||||
}
|
||||
|
||||
template< typename T > __noinline void operator()( const xDirectOrIndirect<T>& to, const xImmReg<T>& immOrReg ) const
|
||||
{
|
||||
_DoI_helpermess( *this, to, immOrReg );
|
||||
}
|
||||
|
||||
template< typename T > __noinline void operator()( const xDirectOrIndirect<T>& to, int imm ) const
|
||||
{
|
||||
_DoI_helpermess( *this, to, imm );
|
||||
}
|
||||
|
||||
template< typename T > __noinline void operator()( const xDirectOrIndirect<T>& to, const xDirectOrIndirect<T>& from ) const
|
||||
{
|
||||
if( to == from ) return;
|
||||
_DoI_helpermess( *this, to, from );
|
||||
}
|
||||
|
||||
/*template< typename T > __noinline void operator()( const xRegister<T>& to, const xDirectOrIndirect<T>& from ) const
|
||||
{
|
||||
_DoI_helpermess( *this, xDirectOrIndirect<T>( to ), from );
|
||||
}
|
||||
|
||||
template< typename T > __noinline void operator()( const xDirectOrIndirect<T>& to, const xRegister<T>& from ) const
|
||||
{
|
||||
_DoI_helpermess( *this, to, xDirectOrIndirect<T>( from ) );
|
||||
}*/
|
||||
#endif
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_MovImm64
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Mov with 64-bit immediates (only available on 64-bit platforms)
|
||||
//
|
||||
struct xImpl_MovImm64
|
||||
{
|
||||
xImpl_MovImm64() {} // Satisfy GCC's whims.
|
||||
|
||||
void operator()(const xRegister64& to, s64 imm, bool preserve_flags = false) const;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_CMov
|
||||
// --------------------------------------------------------------------------------------
|
||||
// CMOVcc !! [in all of it's disappointing lack-of glory] .. and ..
|
||||
// SETcc !! [more glory, less lack!]
|
||||
//
|
||||
// CMOV Disclaimer: Caution! This instruction can look exciting and cool, until you
|
||||
// realize that it cannot load immediate values into registers. -_-
|
||||
//
|
||||
// I use explicit method declarations here instead of templates, in order to provide
|
||||
// *only* 32 and 16 bit register operand forms (8 bit registers are not valid in CMOV).
|
||||
//
|
||||
|
||||
struct xImpl_CMov
|
||||
{
|
||||
JccComparisonType ccType;
|
||||
void operator()(const xRegister16or32or64& to, const xRegister16or32or64& from) const;
|
||||
void operator()(const xRegister16or32or64& to, const xIndirectVoid& sibsrc) const;
|
||||
|
||||
//void operator()( const xDirectOrIndirect32& to, const xDirectOrIndirect32& from );
|
||||
//void operator()( const xDirectOrIndirect16& to, const xDirectOrIndirect16& from ) const;
|
||||
};
|
||||
|
||||
struct xImpl_Set
|
||||
{
|
||||
JccComparisonType ccType;
|
||||
|
||||
void operator()(const xRegister8& to) const;
|
||||
void operator()(const xIndirect8& dest) const;
|
||||
|
||||
//void operator()( const xDirectOrIndirect8& dest ) const;
|
||||
};
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_MovExtend
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Mov with sign/zero extension implementations (movsx / movzx)
|
||||
//
|
||||
struct xImpl_MovExtend
|
||||
{
|
||||
bool SignExtend;
|
||||
|
||||
void operator()(const xRegister16or32or64& to, const xRegister8& from) const;
|
||||
void operator()(const xRegister16or32or64& to, const xIndirect8& sibsrc) const;
|
||||
void operator()(const xRegister32or64& to, const xRegister16& from) const;
|
||||
void operator()(const xRegister32or64& to, const xIndirect16& sibsrc) const;
|
||||
void operator()(const xRegister64& to, const xRegister32& from) const;
|
||||
void operator()(const xRegister64& to, const xIndirect32& sibsrc) const;
|
||||
|
||||
//void operator()( const xRegister32& to, const xDirectOrIndirect16& src ) const;
|
||||
//void operator()( const xRegister16or32& to, const xDirectOrIndirect8& src ) const;
|
||||
//void operator()( const xRegister16& to, const xDirectOrIndirect8& src ) const;
|
||||
};
|
||||
|
||||
} // End namespace x86Emitter
|
||||
304
common/emitter/implement/simd_arithmetic.h
Normal file
304
common/emitter/implement/simd_arithmetic.h
Normal file
@@ -0,0 +1,304 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace x86Emitter
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// _SimdShiftHelper
|
||||
// --------------------------------------------------------------------------------------
|
||||
struct _SimdShiftHelper
|
||||
{
|
||||
u8 Prefix;
|
||||
u16 Opcode;
|
||||
u16 OpcodeImm;
|
||||
u8 Modcode;
|
||||
|
||||
void operator()(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||
void operator()(const xRegisterSSE& to, const xIndirectVoid& from) const;
|
||||
|
||||
void operator()(const xRegisterSSE& to, u8 imm8) const;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImplSimd_Shift / xImplSimd_ShiftWithoutQ
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
// Used for PSRA, which lacks the Q form.
|
||||
//
|
||||
struct xImplSimd_ShiftWithoutQ
|
||||
{
|
||||
const _SimdShiftHelper W;
|
||||
const _SimdShiftHelper D;
|
||||
};
|
||||
|
||||
// Implements PSRL and PSLL
|
||||
//
|
||||
struct xImplSimd_Shift
|
||||
{
|
||||
const _SimdShiftHelper W;
|
||||
const _SimdShiftHelper D;
|
||||
const _SimdShiftHelper Q;
|
||||
|
||||
void DQ(const xRegisterSSE& to, u8 imm8) const;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
struct xImplSimd_AddSub
|
||||
{
|
||||
const xImplSimd_DestRegEither B;
|
||||
const xImplSimd_DestRegEither W;
|
||||
const xImplSimd_DestRegEither D;
|
||||
const xImplSimd_DestRegEither Q;
|
||||
|
||||
// Add/Sub packed signed byte [8bit] integers from src into dest, and saturate the results.
|
||||
const xImplSimd_DestRegEither SB;
|
||||
|
||||
// Add/Sub packed signed word [16bit] integers from src into dest, and saturate the results.
|
||||
const xImplSimd_DestRegEither SW;
|
||||
|
||||
// Add/Sub packed unsigned byte [8bit] integers from src into dest, and saturate the results.
|
||||
const xImplSimd_DestRegEither USB;
|
||||
|
||||
// Add/Sub packed unsigned word [16bit] integers from src into dest, and saturate the results.
|
||||
const xImplSimd_DestRegEither USW;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
struct xImplSimd_PMul
|
||||
{
|
||||
const xImplSimd_DestRegEither LW;
|
||||
const xImplSimd_DestRegEither HW;
|
||||
const xImplSimd_DestRegEither HUW;
|
||||
const xImplSimd_DestRegEither UDQ;
|
||||
|
||||
// [SSE-3] PMULHRSW multiplies vertically each signed 16-bit integer from dest with the
|
||||
// corresponding signed 16-bit integer of source, producing intermediate signed 32-bit
|
||||
// integers. Each intermediate 32-bit integer is truncated to the 18 most significant
|
||||
// bits. Rounding is always performed by adding 1 to the least significant bit of the
|
||||
// 18-bit intermediate result. The final result is obtained by selecting the 16 bits
|
||||
// immediately to the right of the most significant bit of each 18-bit intermediate
|
||||
// result and packed to the destination operand.
|
||||
//
|
||||
// Both operands can be MMX or XMM registers. Source can be register or memory.
|
||||
//
|
||||
const xImplSimd_DestRegEither HRSW;
|
||||
|
||||
// [SSE-4.1] Multiply the packed dword signed integers in dest with src, and store
|
||||
// the low 32 bits of each product in xmm1.
|
||||
const xImplSimd_DestRegSSE LD;
|
||||
|
||||
// [SSE-4.1] Multiply the packed signed dword integers in dest with src.
|
||||
const xImplSimd_DestRegSSE DQ;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// For instructions that have PS/SS form only (most commonly reciprocal Sqrt functions)
|
||||
//
|
||||
struct xImplSimd_rSqrt
|
||||
{
|
||||
const xImplSimd_DestRegSSE PS;
|
||||
const xImplSimd_DestRegSSE SS;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SQRT has PS/SS/SD forms, but not the PD form.
|
||||
//
|
||||
struct xImplSimd_Sqrt
|
||||
{
|
||||
const xImplSimd_DestRegSSE PS;
|
||||
const xImplSimd_DestRegSSE SS;
|
||||
const xImplSimd_DestRegSSE SD;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
struct xImplSimd_AndNot
|
||||
{
|
||||
const xImplSimd_DestRegSSE PS;
|
||||
const xImplSimd_DestRegSSE PD;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Packed absolute value. [sSSE3 only]
|
||||
//
|
||||
struct xImplSimd_PAbsolute
|
||||
{
|
||||
// [sSSE-3] Computes the absolute value of bytes in the src, and stores the result
|
||||
// in dest, as UNSIGNED.
|
||||
const xImplSimd_DestRegEither B;
|
||||
|
||||
// [sSSE-3] Computes the absolute value of word in the src, and stores the result
|
||||
// in dest, as UNSIGNED.
|
||||
const xImplSimd_DestRegEither W;
|
||||
|
||||
// [sSSE-3] Computes the absolute value of doublewords in the src, and stores the
|
||||
// result in dest, as UNSIGNED.
|
||||
const xImplSimd_DestRegEither D;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Packed Sign [sSSE3 only] - Negate/zero/preserve packed integers in dest depending on the
|
||||
// corresponding sign in src.
|
||||
//
|
||||
struct xImplSimd_PSign
|
||||
{
|
||||
// [sSSE-3] negates each byte element of dest if the signed integer value of the
|
||||
// corresponding data element in src is less than zero. If the signed integer value
|
||||
// of a data element in src is positive, the corresponding data element in dest is
|
||||
// unchanged. If a data element in src is zero, the corresponding data element in
|
||||
// dest is set to zero.
|
||||
const xImplSimd_DestRegEither B;
|
||||
|
||||
// [sSSE-3] negates each word element of dest if the signed integer value of the
|
||||
// corresponding data element in src is less than zero. If the signed integer value
|
||||
// of a data element in src is positive, the corresponding data element in dest is
|
||||
// unchanged. If a data element in src is zero, the corresponding data element in
|
||||
// dest is set to zero.
|
||||
const xImplSimd_DestRegEither W;
|
||||
|
||||
// [sSSE-3] negates each doubleword element of dest if the signed integer value
|
||||
// of the corresponding data element in src is less than zero. If the signed integer
|
||||
// value of a data element in src is positive, the corresponding data element in dest
|
||||
// is unchanged. If a data element in src is zero, the corresponding data element in
|
||||
// dest is set to zero.
|
||||
const xImplSimd_DestRegEither D;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Packed Multiply and Add!!
|
||||
//
|
||||
struct xImplSimd_PMultAdd
|
||||
{
|
||||
// Multiplies the individual signed words of dest by the corresponding signed words
|
||||
// of src, producing temporary signed, doubleword results. The adjacent doubleword
|
||||
// results are then summed and stored in the destination operand.
|
||||
//
|
||||
// DEST[31:0] = ( DEST[15:0] * SRC[15:0]) + (DEST[31:16] * SRC[31:16] );
|
||||
// DEST[63:32] = ( DEST[47:32] * SRC[47:32]) + (DEST[63:48] * SRC[63:48] );
|
||||
// [.. repeat in the case of XMM src/dest operands ..]
|
||||
//
|
||||
const xImplSimd_DestRegEither WD;
|
||||
|
||||
// [sSSE-3] multiplies vertically each unsigned byte of dest with the corresponding
|
||||
// signed byte of src, producing intermediate signed 16-bit integers. Each adjacent
|
||||
// pair of signed words is added and the saturated result is packed to dest.
|
||||
// For example, the lowest-order bytes (bits 7-0) in src and dest are multiplied
|
||||
// and the intermediate signed word result is added with the corresponding
|
||||
// intermediate result from the 2nd lowest-order bytes (bits 15-8) of the operands;
|
||||
// the sign-saturated result is stored in the lowest word of dest (bits 15-0).
|
||||
// The same operation is performed on the other pairs of adjacent bytes.
|
||||
//
|
||||
// In Coder Speak:
|
||||
// DEST[15-0] = SaturateToSignedWord( SRC[15-8] * DEST[15-8] + SRC[7-0] * DEST[7-0] );
|
||||
// DEST[31-16] = SaturateToSignedWord( SRC[31-24] * DEST[31-24] + SRC[23-16] * DEST[23-16] );
|
||||
// [.. repeat for each 16 bits up to 64 (mmx) or 128 (xmm) ..]
|
||||
//
|
||||
const xImplSimd_DestRegEither UBSW;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Packed Horizontal Add [SSE3 only]
|
||||
//
|
||||
struct xImplSimd_HorizAdd
|
||||
{
|
||||
// [SSE-3] Horizontal Add of Packed Data. A three step process:
|
||||
// * Adds the single-precision floating-point values in the first and second dwords of
|
||||
// dest and stores the result in the first dword of dest.
|
||||
// * Adds single-precision floating-point values in the third and fourth dword of dest
|
||||
// stores the result in the second dword of dest.
|
||||
// * Adds single-precision floating-point values in the first and second dword of *src*
|
||||
// and stores the result in the third dword of dest.
|
||||
const xImplSimd_DestRegSSE PS;
|
||||
|
||||
// [SSE-3] Horizontal Add of Packed Data. A two step process:
|
||||
// * Adds the double-precision floating-point values in the high and low quadwords of
|
||||
// dest and stores the result in the low quadword of dest.
|
||||
// * Adds the double-precision floating-point values in the high and low quadwords of
|
||||
// *src* stores the result in the high quadword of dest.
|
||||
const xImplSimd_DestRegSSE PD;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// DotProduct calculation (SSE4.1 only!)
|
||||
//
|
||||
struct xImplSimd_DotProduct
|
||||
{
|
||||
// [SSE-4.1] Conditionally multiplies the packed single precision floating-point
|
||||
// values in dest with the packed single-precision floats in src depending on a
|
||||
// mask extracted from the high 4 bits of the immediate byte. If a condition mask
|
||||
// bit in Imm8[7:4] is zero, the corresponding multiplication is replaced by a value
|
||||
// of 0.0. The four resulting single-precision values are summed into an inter-
|
||||
// mediate result.
|
||||
//
|
||||
// The intermediate result is conditionally broadcasted to the destination using a
|
||||
// broadcast mask specified by bits [3:0] of the immediate byte. If a broadcast
|
||||
// mask bit is 1, the intermediate result is copied to the corresponding dword
|
||||
// element in dest. If a broadcast mask bit is zero, the corresponding element in
|
||||
// the destination is set to zero.
|
||||
//
|
||||
xImplSimd_DestRegImmSSE PS;
|
||||
|
||||
// [SSE-4.1]
|
||||
xImplSimd_DestRegImmSSE PD;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Rounds floating point values (packed or single scalar) by an arbitrary rounding mode.
|
||||
// (SSE4.1 only!)
|
||||
struct xImplSimd_Round
|
||||
{
|
||||
// [SSE-4.1] Rounds the 4 packed single-precision src values and stores them in dest.
|
||||
//
|
||||
// Imm8 specifies control fields for the rounding operation:
|
||||
// Bit 3 - processor behavior for a precision exception (0: normal, 1: inexact)
|
||||
// Bit 2 - If enabled, use MXCSR.RC, else use RC specified in bits 1:0 of this Imm8.
|
||||
// Bits 1:0 - Specifies a rounding mode for this instruction only.
|
||||
//
|
||||
// Rounding Mode Reference:
|
||||
// 0 - Nearest, 1 - Negative Infinity, 2 - Positive infinity, 3 - Truncate.
|
||||
//
|
||||
const xImplSimd_DestRegImmSSE PS;
|
||||
|
||||
// [SSE-4.1] Rounds the 2 packed double-precision src values and stores them in dest.
|
||||
//
|
||||
// Imm8 specifies control fields for the rounding operation:
|
||||
// Bit 3 - processor behavior for a precision exception (0: normal, 1: inexact)
|
||||
// Bit 2 - If enabled, use MXCSR.RC, else use RC specified in bits 1:0 of this Imm8.
|
||||
// Bits 1:0 - Specifies a rounding mode for this instruction only.
|
||||
//
|
||||
// Rounding Mode Reference:
|
||||
// 0 - Nearest, 1 - Negative Infinity, 2 - Positive infinity, 3 - Truncate.
|
||||
//
|
||||
const xImplSimd_DestRegImmSSE PD;
|
||||
|
||||
// [SSE-4.1] Rounds the single-precision src value and stores in dest.
|
||||
//
|
||||
// Imm8 specifies control fields for the rounding operation:
|
||||
// Bit 3 - processor behavior for a precision exception (0: normal, 1: inexact)
|
||||
// Bit 2 - If enabled, use MXCSR.RC, else use RC specified in bits 1:0 of this Imm8.
|
||||
// Bits 1:0 - Specifies a rounding mode for this instruction only.
|
||||
//
|
||||
// Rounding Mode Reference:
|
||||
// 0 - Nearest, 1 - Negative Infinity, 2 - Positive infinity, 3 - Truncate.
|
||||
//
|
||||
const xImplSimd_DestRegImmSSE SS;
|
||||
|
||||
// [SSE-4.1] Rounds the double-precision src value and stores in dest.
|
||||
//
|
||||
// Imm8 specifies control fields for the rounding operation:
|
||||
// Bit 3 - processor behavior for a precision exception (0: normal, 1: inexact)
|
||||
// Bit 2 - If enabled, use MXCSR.RC, else use RC specified in bits 1:0 of this Imm8.
|
||||
// Bits 1:0 - Specifies a rounding mode for this instruction only.
|
||||
//
|
||||
// Rounding Mode Reference:
|
||||
// 0 - Nearest, 1 - Negative Infinity, 2 - Positive infinity, 3 - Truncate.
|
||||
//
|
||||
const xImplSimd_DestRegImmSSE SD;
|
||||
};
|
||||
|
||||
} // End namespace x86Emitter
|
||||
111
common/emitter/implement/simd_comparisons.h
Normal file
111
common/emitter/implement/simd_comparisons.h
Normal file
@@ -0,0 +1,111 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace x86Emitter
|
||||
{
|
||||
|
||||
struct xImplSimd_MinMax
|
||||
{
|
||||
const xImplSimd_DestRegSSE PS; // packed single precision
|
||||
const xImplSimd_DestRegSSE PD; // packed double precision
|
||||
const xImplSimd_DestRegSSE SS; // scalar single precision
|
||||
const xImplSimd_DestRegSSE SD; // scalar double precision
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
struct xImplSimd_Compare
|
||||
{
|
||||
SSE2_ComparisonType CType;
|
||||
|
||||
void PS(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||
void PS(const xRegisterSSE& to, const xIndirectVoid& from) const;
|
||||
|
||||
void PD(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||
void PD(const xRegisterSSE& to, const xIndirectVoid& from) const;
|
||||
|
||||
void SS(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||
void SS(const xRegisterSSE& to, const xIndirectVoid& from) const;
|
||||
|
||||
void SD(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||
void SD(const xRegisterSSE& to, const xIndirectVoid& from) const;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Compare scalar floating point values and set EFLAGS (Ordered or Unordered)
|
||||
//
|
||||
struct xImplSimd_COMI
|
||||
{
|
||||
const xImplSimd_DestRegSSE SS;
|
||||
const xImplSimd_DestRegSSE SD;
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
struct xImplSimd_PCompare
|
||||
{
|
||||
public:
|
||||
// Compare packed bytes for equality.
|
||||
// If a data element in dest is equal to the corresponding date element src, the
|
||||
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
|
||||
const xImplSimd_DestRegEither EQB;
|
||||
|
||||
// Compare packed words for equality.
|
||||
// If a data element in dest is equal to the corresponding date element src, the
|
||||
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
|
||||
const xImplSimd_DestRegEither EQW;
|
||||
|
||||
// Compare packed doublewords [32-bits] for equality.
|
||||
// If a data element in dest is equal to the corresponding date element src, the
|
||||
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
|
||||
const xImplSimd_DestRegEither EQD;
|
||||
|
||||
// Compare packed signed bytes for greater than.
|
||||
// If a data element in dest is greater than the corresponding date element src, the
|
||||
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
|
||||
const xImplSimd_DestRegEither GTB;
|
||||
|
||||
// Compare packed signed words for greater than.
|
||||
// If a data element in dest is greater than the corresponding date element src, the
|
||||
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
|
||||
const xImplSimd_DestRegEither GTW;
|
||||
|
||||
// Compare packed signed doublewords [32-bits] for greater than.
|
||||
// If a data element in dest is greater than the corresponding date element src, the
|
||||
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
|
||||
const xImplSimd_DestRegEither GTD;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
struct xImplSimd_PMinMax
|
||||
{
|
||||
// Compare packed unsigned byte integers in dest to src and store packed min/max
|
||||
// values in dest.
|
||||
const xImplSimd_DestRegEither UB;
|
||||
|
||||
// Compare packed signed word integers in dest to src and store packed min/max
|
||||
// values in dest.
|
||||
const xImplSimd_DestRegEither SW;
|
||||
|
||||
// [SSE-4.1] Compare packed signed byte integers in dest to src and store
|
||||
// packed min/max values in dest. (SSE operands only)
|
||||
const xImplSimd_DestRegSSE SB;
|
||||
|
||||
// [SSE-4.1] Compare packed signed doubleword integers in dest to src and store
|
||||
// packed min/max values in dest. (SSE operands only)
|
||||
const xImplSimd_DestRegSSE SD;
|
||||
|
||||
// [SSE-4.1] Compare packed unsigned word integers in dest to src and store
|
||||
// packed min/max values in dest. (SSE operands only)
|
||||
const xImplSimd_DestRegSSE UW;
|
||||
|
||||
// [SSE-4.1] Compare packed unsigned doubleword integers in dest to src and store
|
||||
// packed min/max values in dest. (SSE operands only)
|
||||
const xImplSimd_DestRegSSE UD;
|
||||
};
|
||||
|
||||
} // end namespace x86Emitter
|
||||
61
common/emitter/implement/simd_helpers.h
Normal file
61
common/emitter/implement/simd_helpers.h
Normal file
@@ -0,0 +1,61 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace x86Emitter
|
||||
{
|
||||
|
||||
// =====================================================================================================
|
||||
// xImpl_SIMD Types (template free!)
|
||||
// =====================================================================================================
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// For implementing SSE-only logic operations that have xmmreg,xmmreg/rm forms only,
|
||||
// like ANDPS/ANDPD
|
||||
//
|
||||
struct xImplSimd_DestRegSSE
|
||||
{
|
||||
u8 Prefix;
|
||||
u16 Opcode;
|
||||
|
||||
void operator()(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||
void operator()(const xRegisterSSE& to, const xIndirectVoid& from) const;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// For implementing SSE-only logic operations that have xmmreg,reg/rm,imm forms only
|
||||
// (PSHUFD / PSHUFHW / etc).
|
||||
//
|
||||
struct xImplSimd_DestRegImmSSE
|
||||
{
|
||||
u8 Prefix;
|
||||
u16 Opcode;
|
||||
|
||||
void operator()(const xRegisterSSE& to, const xRegisterSSE& from, u8 imm) const;
|
||||
void operator()(const xRegisterSSE& to, const xIndirectVoid& from, u8 imm) const;
|
||||
};
|
||||
|
||||
struct xImplSimd_DestSSE_CmpImm
|
||||
{
|
||||
u8 Prefix;
|
||||
u16 Opcode;
|
||||
|
||||
void operator()(const xRegisterSSE& to, const xRegisterSSE& from, SSE2_ComparisonType imm) const;
|
||||
void operator()(const xRegisterSSE& to, const xIndirectVoid& from, SSE2_ComparisonType imm) const;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// For implementing SSE operations that have reg,reg/rm forms only,
|
||||
// but accept either MM or XMM destinations (most PADD/PSUB and other P arithmetic ops).
|
||||
//
|
||||
struct xImplSimd_DestRegEither
|
||||
{
|
||||
u8 Prefix;
|
||||
u16 Opcode;
|
||||
|
||||
void operator()(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||
void operator()(const xRegisterSSE& to, const xIndirectVoid& from) const;
|
||||
};
|
||||
|
||||
} // end namespace x86Emitter
|
||||
167
common/emitter/implement/simd_moremovs.h
Normal file
167
common/emitter/implement/simd_moremovs.h
Normal file
@@ -0,0 +1,167 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace x86Emitter
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImplSimd_MovHL
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Moves to/from high/low portions of an xmm register.
|
||||
// These instructions cannot be used in reg/reg form.
|
||||
//
|
||||
struct xImplSimd_MovHL
|
||||
{
|
||||
u16 Opcode;
|
||||
|
||||
void PS(const xRegisterSSE& to, const xIndirectVoid& from) const;
|
||||
void PS(const xIndirectVoid& to, const xRegisterSSE& from) const;
|
||||
|
||||
void PD(const xRegisterSSE& to, const xIndirectVoid& from) const;
|
||||
void PD(const xIndirectVoid& to, const xRegisterSSE& from) const;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImplSimd_MovHL_RtoR
|
||||
// --------------------------------------------------------------------------------------
|
||||
// RegtoReg forms of MOVHL/MOVLH -- these are the same opcodes as MOVH/MOVL but
|
||||
// do something kinda different! Fun!
|
||||
//
|
||||
struct xImplSimd_MovHL_RtoR
|
||||
{
|
||||
u16 Opcode;
|
||||
|
||||
void PS(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||
void PD(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImplSimd_MoveSSE
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Legends in their own right: MOVAPS / MOVAPD / MOVUPS / MOVUPD
|
||||
//
|
||||
// All implementations of Unaligned Movs will, when possible, use aligned movs instead.
|
||||
// This happens when using Mem,Reg or Reg,Mem forms where the address is simple displacement
|
||||
// which can be checked for alignment at runtime.
|
||||
//
|
||||
struct xImplSimd_MoveSSE
|
||||
{
|
||||
u8 Prefix;
|
||||
bool isAligned;
|
||||
|
||||
void operator()(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||
void operator()(const xRegisterSSE& to, const xIndirectVoid& from) const;
|
||||
void operator()(const xIndirectVoid& to, const xRegisterSSE& from) const;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImplSimd_MoveDQ
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Implementations for MOVDQA / MOVDQU
|
||||
//
|
||||
// All implementations of Unaligned Movs will, when possible, use aligned movs instead.
|
||||
// This happens when using Mem,Reg or Reg,Mem forms where the address is simple displacement
|
||||
// which can be checked for alignment at runtime.
|
||||
|
||||
struct xImplSimd_MoveDQ
|
||||
{
|
||||
u8 Prefix;
|
||||
bool isAligned;
|
||||
|
||||
void operator()(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||
void operator()(const xRegisterSSE& to, const xIndirectVoid& from) const;
|
||||
void operator()(const xIndirectVoid& to, const xRegisterSSE& from) const;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImplSimd_Blend
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Blend - Conditional copying of values in src into dest.
|
||||
//
|
||||
struct xImplSimd_Blend
|
||||
{
|
||||
// [SSE-4.1] Conditionally copies dword values from src to dest, depending on the
|
||||
// mask bits in the immediate operand (bits [3:0]). Each mask bit corresponds to a
|
||||
// dword element in a 128-bit operand.
|
||||
//
|
||||
// If a mask bit is 1, then the corresponding dword in the source operand is copied
|
||||
// to dest, else the dword element in dest is left unchanged.
|
||||
//
|
||||
xImplSimd_DestRegImmSSE PS;
|
||||
|
||||
// [SSE-4.1] Conditionally copies quadword values from src to dest, depending on the
|
||||
// mask bits in the immediate operand (bits [1:0]). Each mask bit corresponds to a
|
||||
// quadword element in a 128-bit operand.
|
||||
//
|
||||
// If a mask bit is 1, then the corresponding dword in the source operand is copied
|
||||
// to dest, else the dword element in dest is left unchanged.
|
||||
//
|
||||
xImplSimd_DestRegImmSSE PD;
|
||||
|
||||
// [SSE-4.1] Conditionally copies dword values from src to dest, depending on the
|
||||
// mask (bits [3:0]) in XMM0 (yes, the fixed register). Each mask bit corresponds
|
||||
// to a dword element in the 128-bit operand.
|
||||
//
|
||||
// If a mask bit is 1, then the corresponding dword in the source operand is copied
|
||||
// to dest, else the dword element in dest is left unchanged.
|
||||
//
|
||||
xImplSimd_DestRegSSE VPS;
|
||||
|
||||
// [SSE-4.1] Conditionally copies quadword values from src to dest, depending on the
|
||||
// mask (bits [1:0]) in XMM0 (yes, the fixed register). Each mask bit corresponds
|
||||
// to a quadword element in the 128-bit operand.
|
||||
//
|
||||
// If a mask bit is 1, then the corresponding dword in the source operand is copied
|
||||
// to dest, else the dword element in dest is left unchanged.
|
||||
//
|
||||
xImplSimd_DestRegSSE VPD;
|
||||
};
|
||||
|
||||
struct xImplSimd_PBlend
|
||||
{
|
||||
xImplSimd_DestRegImmSSE W;
|
||||
xImplSimd_DestRegSSE VB;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImplSimd_PMove
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Packed Move with Sign or Zero extension.
|
||||
//
|
||||
struct xImplSimd_PMove
|
||||
{
|
||||
u16 OpcodeBase;
|
||||
|
||||
// [SSE-4.1] Zero/Sign-extend the low byte values in src into word integers
|
||||
// and store them in dest.
|
||||
void BW(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||
void BW(const xRegisterSSE& to, const xIndirect64& from) const;
|
||||
|
||||
// [SSE-4.1] Zero/Sign-extend the low byte values in src into dword integers
|
||||
// and store them in dest.
|
||||
void BD(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||
void BD(const xRegisterSSE& to, const xIndirect32& from) const;
|
||||
|
||||
// [SSE-4.1] Zero/Sign-extend the low byte values in src into qword integers
|
||||
// and store them in dest.
|
||||
void BQ(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||
void BQ(const xRegisterSSE& to, const xIndirect16& from) const;
|
||||
|
||||
// [SSE-4.1] Zero/Sign-extend the low word values in src into dword integers
|
||||
// and store them in dest.
|
||||
void WD(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||
void WD(const xRegisterSSE& to, const xIndirect64& from) const;
|
||||
|
||||
// [SSE-4.1] Zero/Sign-extend the low word values in src into qword integers
|
||||
// and store them in dest.
|
||||
void WQ(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||
void WQ(const xRegisterSSE& to, const xIndirect32& from) const;
|
||||
|
||||
// [SSE-4.1] Zero/Sign-extend the low dword values in src into qword integers
|
||||
// and store them in dest.
|
||||
void DQ(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||
void DQ(const xRegisterSSE& to, const xIndirect64& from) const;
|
||||
};
|
||||
} // namespace x86Emitter
|
||||
226
common/emitter/implement/simd_shufflepack.h
Normal file
226
common/emitter/implement/simd_shufflepack.h
Normal file
@@ -0,0 +1,226 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace x86Emitter
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImplSimd_Shuffle
|
||||
// --------------------------------------------------------------------------------------
|
||||
struct xImplSimd_Shuffle
|
||||
{
|
||||
inline void _selector_assertion_check(u8 selector) const;
|
||||
|
||||
void PS(const xRegisterSSE& to, const xRegisterSSE& from, u8 selector) const;
|
||||
void PS(const xRegisterSSE& to, const xIndirectVoid& from, u8 selector) const;
|
||||
|
||||
void PD(const xRegisterSSE& to, const xRegisterSSE& from, u8 selector) const;
|
||||
void PD(const xRegisterSSE& to, const xIndirectVoid& from, u8 selector) const;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImplSimd_PShuffle
|
||||
// --------------------------------------------------------------------------------------
|
||||
struct xImplSimd_PShuffle
|
||||
{
|
||||
// Copies doublewords from src and inserts them into dest at dword locations selected
|
||||
// with the order operand (8 bit immediate).
|
||||
const xImplSimd_DestRegImmSSE D;
|
||||
|
||||
// Copies words from the low quadword of src and inserts them into the low quadword
|
||||
// of dest at word locations selected with the order operand (8 bit immediate).
|
||||
// The high quadword of src is copied to the high quadword of dest.
|
||||
const xImplSimd_DestRegImmSSE LW;
|
||||
|
||||
// Copies words from the high quadword of src and inserts them into the high quadword
|
||||
// of dest at word locations selected with the order operand (8 bit immediate).
|
||||
// The low quadword of src is copied to the low quadword of dest.
|
||||
const xImplSimd_DestRegImmSSE HW;
|
||||
|
||||
// [sSSE-3] Performs in-place shuffles of bytes in dest according to the shuffle
|
||||
// control mask in src. If the most significant bit (bit[7]) of each byte of the
|
||||
// shuffle control mask is set, then constant zero is written in the result byte.
|
||||
// Each byte in the shuffle control mask forms an index to permute the corresponding
|
||||
// byte in dest. The value of each index is the least significant 4 bits (128-bit
|
||||
// operation) or 3 bits (64-bit operation) of the shuffle control byte.
|
||||
//
|
||||
const xImplSimd_DestRegEither B;
|
||||
|
||||
// below is my test bed for a new system, free of subclasses. Was supposed to improve intellisense
|
||||
// but it doesn't (makes it worse). Will try again in MSVC 2010. --air
|
||||
|
||||
#if 0
|
||||
// Copies words from src and inserts them into dest at word locations selected with
|
||||
// the order operand (8 bit immediate).
|
||||
|
||||
// Copies doublewords from src and inserts them into dest at dword locations selected
|
||||
// with the order operand (8 bit immediate).
|
||||
void D( const xRegisterSSE& to, const xRegisterSSE& from, u8 imm ) const { xOpWrite0F( 0x66, 0x70, to, from, imm ); }
|
||||
void D( const xRegisterSSE& to, const xIndirectVoid& from, u8 imm ) const { xOpWrite0F( 0x66, 0x70, to, from, imm ); }
|
||||
|
||||
// Copies words from the low quadword of src and inserts them into the low quadword
|
||||
// of dest at word locations selected with the order operand (8 bit immediate).
|
||||
// The high quadword of src is copied to the high quadword of dest.
|
||||
void LW( const xRegisterSSE& to, const xRegisterSSE& from, u8 imm ) const { xOpWrite0F( 0xf2, 0x70, to, from, imm ); }
|
||||
void LW( const xRegisterSSE& to, const xIndirectVoid& from, u8 imm ) const { xOpWrite0F( 0xf2, 0x70, to, from, imm ); }
|
||||
|
||||
// Copies words from the high quadword of src and inserts them into the high quadword
|
||||
// of dest at word locations selected with the order operand (8 bit immediate).
|
||||
// The low quadword of src is copied to the low quadword of dest.
|
||||
void HW( const xRegisterSSE& to, const xRegisterSSE& from, u8 imm ) const { xOpWrite0F( 0xf3, 0x70, to, from, imm ); }
|
||||
void HW( const xRegisterSSE& to, const xIndirectVoid& from, u8 imm ) const { xOpWrite0F( 0xf3, 0x70, to, from, imm ); }
|
||||
|
||||
// [sSSE-3] Performs in-place shuffles of bytes in dest according to the shuffle
|
||||
// control mask in src. If the most significant bit (bit[7]) of each byte of the
|
||||
// shuffle control mask is set, then constant zero is written in the result byte.
|
||||
// Each byte in the shuffle control mask forms an index to permute the corresponding
|
||||
// byte in dest. The value of each index is the least significant 4 bits (128-bit
|
||||
// operation) or 3 bits (64-bit operation) of the shuffle control byte.
|
||||
//
|
||||
void B( const xRegisterSSE& to, const xRegisterSSE& from ) const { OpWriteSSE( 0x66, 0x0038 ); }
|
||||
void B( const xRegisterSSE& to, const xIndirectVoid& from ) const { OpWriteSSE( 0x66, 0x0038 ); }
|
||||
#endif
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SimdImpl_PUnpack
|
||||
// --------------------------------------------------------------------------------------
|
||||
struct SimdImpl_PUnpack
|
||||
{
|
||||
// Unpack and interleave low-order bytes from src and dest into dest.
|
||||
const xImplSimd_DestRegEither LBW;
|
||||
// Unpack and interleave low-order words from src and dest into dest.
|
||||
const xImplSimd_DestRegEither LWD;
|
||||
// Unpack and interleave low-order doublewords from src and dest into dest.
|
||||
const xImplSimd_DestRegEither LDQ;
|
||||
// Unpack and interleave low-order quadwords from src and dest into dest.
|
||||
const xImplSimd_DestRegSSE LQDQ;
|
||||
|
||||
// Unpack and interleave high-order bytes from src and dest into dest.
|
||||
const xImplSimd_DestRegEither HBW;
|
||||
// Unpack and interleave high-order words from src and dest into dest.
|
||||
const xImplSimd_DestRegEither HWD;
|
||||
// Unpack and interleave high-order doublewords from src and dest into dest.
|
||||
const xImplSimd_DestRegEither HDQ;
|
||||
// Unpack and interleave high-order quadwords from src and dest into dest.
|
||||
const xImplSimd_DestRegSSE HQDQ;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SimdImpl_Pack
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Pack with Signed or Unsigned Saturation
|
||||
//
|
||||
struct SimdImpl_Pack
|
||||
{
|
||||
// Converts packed signed word integers from src and dest into packed signed
|
||||
// byte integers in dest, using signed saturation.
|
||||
const xImplSimd_DestRegEither SSWB;
|
||||
|
||||
// Converts packed signed dword integers from src and dest into packed signed
|
||||
// word integers in dest, using signed saturation.
|
||||
const xImplSimd_DestRegEither SSDW;
|
||||
|
||||
// Converts packed unsigned word integers from src and dest into packed unsigned
|
||||
// byte integers in dest, using unsigned saturation.
|
||||
const xImplSimd_DestRegEither USWB;
|
||||
|
||||
// [SSE-4.1] Converts packed unsigned dword integers from src and dest into packed
|
||||
// unsigned word integers in dest, using signed saturation.
|
||||
const xImplSimd_DestRegSSE USDW;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SimdImpl_Unpack
|
||||
// --------------------------------------------------------------------------------------
|
||||
struct xImplSimd_Unpack
|
||||
{
|
||||
// Unpacks the high doubleword [single-precision] values from src and dest into
|
||||
// dest, such that the result of dest looks like this:
|
||||
// dest[0] <- dest[2]
|
||||
// dest[1] <- src[2]
|
||||
// dest[2] <- dest[3]
|
||||
// dest[3] <- src[3]
|
||||
//
|
||||
const xImplSimd_DestRegSSE HPS;
|
||||
|
||||
// Unpacks the high quadword [double-precision] values from src and dest into
|
||||
// dest, such that the result of dest looks like this:
|
||||
// dest.lo <- dest.hi
|
||||
// dest.hi <- src.hi
|
||||
//
|
||||
const xImplSimd_DestRegSSE HPD;
|
||||
|
||||
// Unpacks the low doubleword [single-precision] values from src and dest into
|
||||
// dest, such that the result of dest looks like this:
|
||||
// dest[3] <- src[1]
|
||||
// dest[2] <- dest[1]
|
||||
// dest[1] <- src[0]
|
||||
// dest[0] <- dest[0]
|
||||
//
|
||||
const xImplSimd_DestRegSSE LPS;
|
||||
|
||||
// Unpacks the low quadword [double-precision] values from src and dest into
|
||||
// dest, effectively moving the low portion of src into the upper portion of dest.
|
||||
// The result of dest is loaded as such:
|
||||
// dest.hi <- src.lo
|
||||
// dest.lo <- dest.lo [remains unchanged!]
|
||||
//
|
||||
const xImplSimd_DestRegSSE LPD;
|
||||
};
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SimdImpl_PInsert
|
||||
// --------------------------------------------------------------------------------------
|
||||
// PINSRW/B/D [all but Word form are SSE4.1 only!]
|
||||
//
|
||||
struct xImplSimd_PInsert
|
||||
{
|
||||
void B(const xRegisterSSE& to, const xRegister32& from, u8 imm8) const;
|
||||
void B(const xRegisterSSE& to, const xIndirect32& from, u8 imm8) const;
|
||||
|
||||
void W(const xRegisterSSE& to, const xRegister32& from, u8 imm8) const;
|
||||
void W(const xRegisterSSE& to, const xIndirect32& from, u8 imm8) const;
|
||||
|
||||
void D(const xRegisterSSE& to, const xRegister32& from, u8 imm8) const;
|
||||
void D(const xRegisterSSE& to, const xIndirect32& from, u8 imm8) const;
|
||||
|
||||
void Q(const xRegisterSSE& to, const xRegister64& from, u8 imm8) const;
|
||||
void Q(const xRegisterSSE& to, const xIndirect64& from, u8 imm8) const;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PEXTRW/B/D [all but Word form are SSE4.1 only!]
|
||||
//
|
||||
// Note: Word form's indirect memory form is only available in SSE4.1.
|
||||
//
|
||||
struct SimdImpl_PExtract
|
||||
{
|
||||
// [SSE-4.1] Copies the byte element specified by imm8 from src to dest. The upper bits
|
||||
// of dest are zero-extended (cleared). This can be used to extract any single packed
|
||||
// byte value from src into an x86 32 bit register.
|
||||
void B(const xRegister32& to, const xRegisterSSE& from, u8 imm8) const;
|
||||
void B(const xIndirect32& dest, const xRegisterSSE& from, u8 imm8) const;
|
||||
|
||||
// Copies the word element specified by imm8 from src to dest. The upper bits
|
||||
// of dest are zero-extended (cleared). This can be used to extract any single packed
|
||||
// word value from src into an x86 32 bit register.
|
||||
//
|
||||
// [SSE-4.1] Note: Indirect memory forms of this instruction are an SSE-4.1 extension!
|
||||
//
|
||||
void W(const xRegister32& to, const xRegisterSSE& from, u8 imm8) const;
|
||||
void W(const xIndirect32& dest, const xRegisterSSE& from, u8 imm8) const;
|
||||
|
||||
// [SSE-4.1] Copies the dword element specified by imm8 from src to dest. This can be
|
||||
// used to extract any single packed dword value from src into an x86 32 bit register.
|
||||
void D(const xRegister32& to, const xRegisterSSE& from, u8 imm8) const;
|
||||
void D(const xIndirect32& dest, const xRegisterSSE& from, u8 imm8) const;
|
||||
|
||||
// Insert a qword integer value from r/m64 into the xmm1 at the destination element specified by imm8.
|
||||
void Q(const xRegister64& to, const xRegisterSSE& from, u8 imm8) const;
|
||||
void Q(const xIndirect64& dest, const xRegisterSSE& from, u8 imm8) const;
|
||||
};
|
||||
} // namespace x86Emitter
|
||||
26
common/emitter/implement/simd_templated_helpers.h
Normal file
26
common/emitter/implement/simd_templated_helpers.h
Normal file
@@ -0,0 +1,26 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// MMX / SSE Helper Functions!
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// For implementing SSE-only logic operations that have xmmreg,xmmreg/rm forms only,
|
||||
// like ANDPS/ANDPD
|
||||
//
|
||||
template <u8 Prefix, u16 Opcode>
|
||||
class SimdImpl_DestRegSSE
|
||||
{
|
||||
public:
|
||||
__forceinline void operator()(const xRegisterSSE& to, const xRegisterSSE& from) const { xOpWrite0F(Prefix, Opcode, to, from); }
|
||||
__forceinline void operator()(const xRegisterSSE& to, const ModSibBase& from) const
|
||||
{
|
||||
bool isReallyAligned = ((from.Displacement & 0x0f) == 0) && from.Index.IsEmpty() && from.Base.IsEmpty();
|
||||
pxAssertMsg(isReallyAligned, "Alignment check failed on SSE indirect load.");
|
||||
xOpWrite0F(Prefix, Opcode, to, from);
|
||||
}
|
||||
|
||||
SimdImpl_DestRegSSE() {} //GCWho?
|
||||
};
|
||||
63
common/emitter/implement/test.h
Normal file
63
common/emitter/implement/test.h
Normal file
@@ -0,0 +1,63 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
// Implementations found here: TEST + BTS/BT/BTC/BTR + BSF/BSR! (for lack of better location)
|
||||
|
||||
namespace x86Emitter
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_Test
|
||||
// --------------------------------------------------------------------------------------
|
||||
//
|
||||
struct xImpl_Test
|
||||
{
|
||||
void operator()(const xRegisterInt& to, const xRegisterInt& from) const;
|
||||
void operator()(const xIndirect64orLess& dest, int imm) const;
|
||||
void operator()(const xRegisterInt& to, int imm) const;
|
||||
};
|
||||
|
||||
enum G8Type
|
||||
{
|
||||
G8Type_BT = 4,
|
||||
G8Type_BTS,
|
||||
G8Type_BTR,
|
||||
G8Type_BTC,
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// BSF / BSR
|
||||
// --------------------------------------------------------------------------------------
|
||||
// 16/32 operands are available. No 8 bit ones, not that any of you cared, I bet.
|
||||
//
|
||||
struct xImpl_BitScan
|
||||
{
|
||||
// 0xbc [fwd] / 0xbd [rev]
|
||||
u16 Opcode;
|
||||
|
||||
void operator()(const xRegister16or32or64& to, const xRegister16or32or64& from) const;
|
||||
void operator()(const xRegister16or32or64& to, const xIndirectVoid& sibsrc) const;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_Group8
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Bit Test Instructions - Valid on 16/32 bit instructions only.
|
||||
//
|
||||
struct xImpl_Group8
|
||||
{
|
||||
G8Type InstType;
|
||||
|
||||
void operator()(const xRegister16or32or64& bitbase, const xRegister16or32or64& bitoffset) const;
|
||||
void operator()(const xRegister16or32or64& bitbase, u8 bitoffset) const;
|
||||
|
||||
void operator()(const xIndirectVoid& bitbase, const xRegister16or32or64& bitoffset) const;
|
||||
|
||||
void operator()(const xIndirect64& bitbase, u8 bitoffset) const;
|
||||
void operator()(const xIndirect32& bitbase, u8 bitoffset) const;
|
||||
void operator()(const xIndirect16& bitbase, u8 bitoffset) const;
|
||||
};
|
||||
|
||||
} // End namespace x86Emitter
|
||||
13
common/emitter/implement/xchg.h
Normal file
13
common/emitter/implement/xchg.h
Normal file
@@ -0,0 +1,13 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
// This header file is intended to be the future home of xchg, cmpxchg, xadd, and
|
||||
// other threading-related exchange instructions.
|
||||
|
||||
namespace x86Emitter
|
||||
{
|
||||
|
||||
|
||||
} // End namespace x86Emitter
|
||||
Reference in New Issue
Block a user