mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-02-13 15:59:23 +01:00
x64: support VEX opcode encoding
and add some AVX instructions
This commit is contained in:
parent
22b47d5b9c
commit
ae86850a78
@ -156,6 +156,40 @@ void OpArg::WriteRex(XEmitter *emit, int opBits, int bits, int customOp) const
|
||||
#endif
|
||||
}
|
||||
|
||||
void OpArg::WriteVex(XEmitter* emit, int size, int packed, Gen::X64Reg regOp1, Gen::X64Reg regOp2) const
|
||||
{
|
||||
int R = !(regOp1 & 8);
|
||||
int X = !(indexReg & 8);
|
||||
int B = !(offsetOrBaseReg & 8);
|
||||
|
||||
// not so sure about this one...
|
||||
int W = 0;
|
||||
|
||||
// aka map_select in AMD manuals
|
||||
// only support VEX opcode map 1 for now (analog to secondary opcode map)
|
||||
int mmmmm = 1;
|
||||
|
||||
int vvvv = (regOp2 == X64Reg::INVALID_REG) ? 0xf : (regOp2 ^ 0xf);
|
||||
int L = size == 256;
|
||||
int pp = (packed << 1) | (size == 64);
|
||||
|
||||
// do we need any VEX fields that only appear in the three-byte form?
|
||||
if (X == 1 && B == 1 && W == 0 && mmmmm == 1)
|
||||
{
|
||||
u8 RvvvvLpp = (R << 7) | (vvvv << 3) | (L << 1) | pp;
|
||||
emit->Write8(0xC5);
|
||||
emit->Write8(RvvvvLpp);
|
||||
}
|
||||
else
|
||||
{
|
||||
u8 RXBmmmmm = (R << 7) | (X << 6) | (B << 5) | mmmmm;
|
||||
u8 WvvvvLpp = (W << 7) | (vvvv << 3) | (L << 1) | pp;
|
||||
emit->Write8(0xC4);
|
||||
emit->Write8(RXBmmmmm);
|
||||
emit->Write8(WvvvvLpp);
|
||||
}
|
||||
}
|
||||
|
||||
void OpArg::WriteRest(XEmitter *emit, int extraBytes, X64Reg _operandReg,
|
||||
bool warn_64bit_offset) const
|
||||
{
|
||||
@ -1143,6 +1177,18 @@ void XEmitter::WriteSSEOp(int size, u8 sseOp, bool packed, X64Reg regOp, OpArg a
|
||||
arg.WriteRest(this, extrabytes);
|
||||
}
|
||||
|
||||
void XEmitter::WriteAVXOp(int size, u8 sseOp, bool packed, X64Reg regOp, OpArg arg, int extrabytes)
|
||||
{
|
||||
WriteAVXOp(size, sseOp, packed, regOp, X64Reg::INVALID_REG, arg, extrabytes);
|
||||
}
|
||||
|
||||
void XEmitter::WriteAVXOp(int size, u8 sseOp, bool packed, X64Reg regOp1, X64Reg regOp2, OpArg arg, int extrabytes)
|
||||
{
|
||||
arg.WriteVex(this, size, packed, regOp1, regOp2);
|
||||
Write8(sseOp);
|
||||
arg.WriteRest(this, extrabytes, regOp1);
|
||||
}
|
||||
|
||||
void XEmitter::MOVD_xmm(X64Reg dest, const OpArg &arg) {WriteSSEOp(64, 0x6E, true, dest, arg, 0);}
|
||||
void XEmitter::MOVD_xmm(const OpArg &arg, X64Reg src) {WriteSSEOp(64, 0x7E, true, src, arg, 0);}
|
||||
|
||||
@ -1446,6 +1492,13 @@ void XEmitter::PMOVMSKB(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0xD7, true, d
|
||||
|
||||
void XEmitter::PSHUFLW(X64Reg regOp, OpArg arg, u8 shuffle) {WriteSSEOp(64, 0x70, false, regOp, arg, 1); Write8(shuffle);}
|
||||
|
||||
// VEX
|
||||
void XEmitter::VADDSD(X64Reg regOp1, X64Reg regOp2, OpArg arg) {WriteAVXOp(64, sseADD, false, regOp1, regOp2, arg);}
|
||||
void XEmitter::VSUBSD(X64Reg regOp1, X64Reg regOp2, OpArg arg) {WriteAVXOp(64, sseSUB, false, regOp1, regOp2, arg);}
|
||||
void XEmitter::VMULSD(X64Reg regOp1, X64Reg regOp2, OpArg arg) {WriteAVXOp(64, sseMUL, false, regOp1, regOp2, arg);}
|
||||
void XEmitter::VDIVSD(X64Reg regOp1, X64Reg regOp2, OpArg arg) {WriteAVXOp(64, sseDIV, false, regOp1, regOp2, arg);}
|
||||
void XEmitter::VSQRTSD(X64Reg regOp1, X64Reg regOp2, OpArg arg) {WriteAVXOp(64, sseSQRT, false, regOp1, regOp2, arg);}
|
||||
|
||||
// Prefixes
|
||||
|
||||
void XEmitter::LOCK() { Write8(0xF0); }
|
||||
|
@ -33,6 +33,9 @@ enum X64Reg
|
||||
XMM0=0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7,
|
||||
XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15,
|
||||
|
||||
YMM0=0, YMM1, YMM2, YMM3, YMM4, YMM5, YMM6, YMM7,
|
||||
YMM8, YMM9, YMM10, YMM11, YMM12, YMM13, YMM14, YMM15,
|
||||
|
||||
INVALID_REG = 0xFFFFFFFF
|
||||
};
|
||||
|
||||
@ -111,6 +114,7 @@ struct OpArg
|
||||
offset = _offset;
|
||||
}
|
||||
void WriteRex(XEmitter *emit, int opBits, int bits, int customOp = -1) const;
|
||||
void WriteVex(XEmitter* emit, int size, int packed, Gen::X64Reg regOp1, X64Reg regOp2) const;
|
||||
void WriteRest(XEmitter *emit, int extraBytes=0, X64Reg operandReg=(X64Reg)0xFF, bool warn_64bit_offset = true) const;
|
||||
void WriteSingleByteOp(XEmitter *emit, u8 op, X64Reg operandReg, int bits);
|
||||
// This one is public - must be written to
|
||||
@ -239,6 +243,8 @@ private:
|
||||
void WriteBitTest(int bits, OpArg &dest, OpArg &index, int ext);
|
||||
void WriteMXCSR(OpArg arg, int ext);
|
||||
void WriteSSEOp(int size, u8 sseOp, bool packed, X64Reg regOp, OpArg arg, int extrabytes = 0);
|
||||
void WriteAVXOp(int size, u8 sseOp, bool packed, X64Reg regOp, OpArg arg, int extrabytes = 0);
|
||||
void WriteAVXOp(int size, u8 sseOp, bool packed, X64Reg regOp1, X64Reg regOp2, OpArg arg, int extrabytes = 0);
|
||||
void WriteNormalOp(XEmitter *emit, int bits, NormalOp op, const OpArg &a1, const OpArg &a2);
|
||||
|
||||
protected:
|
||||
@ -616,6 +622,13 @@ public:
|
||||
void PSRAW(X64Reg reg, int shift);
|
||||
void PSRAD(X64Reg reg, int shift);
|
||||
|
||||
// AVX
|
||||
void VADDSD(X64Reg regOp1, X64Reg regOp2, OpArg arg);
|
||||
void VSUBSD(X64Reg regOp1, X64Reg regOp2, OpArg arg);
|
||||
void VMULSD(X64Reg regOp1, X64Reg regOp2, OpArg arg);
|
||||
void VDIVSD(X64Reg regOp1, X64Reg regOp2, OpArg arg);
|
||||
void VSQRTSD(X64Reg regOp1, X64Reg regOp2, OpArg arg);
|
||||
|
||||
void RTDSC();
|
||||
|
||||
// Utility functions
|
||||
|
Loading…
x
Reference in New Issue
Block a user