From c25c4a6e20fb2c776f112cac5bcd4351b0a73703 Mon Sep 17 00:00:00 2001 From: Tillmann Karras Date: Sat, 25 Jan 2014 18:38:06 +0100 Subject: [PATCH] x64: add support for some x87 instructions --- Source/Core/Common/x64Emitter.cpp | 21 +++++++++++++++++++-- Source/Core/Common/x64Emitter.h | 12 ++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/Source/Core/Common/x64Emitter.cpp b/Source/Core/Common/x64Emitter.cpp index 76e235ebcd..09f9097d7f 100644 --- a/Source/Core/Common/x64Emitter.cpp +++ b/Source/Core/Common/x64Emitter.cpp @@ -204,7 +204,7 @@ void OpArg::WriteRest(XEmitter *emit, int extraBytes, X64Reg _operandReg, { // Oh, RIP addressing. _offsetOrBaseReg = 5; - emit->WriteModRM(0, _operandReg&7, 5); + emit->WriteModRM(0, _operandReg, _offsetOrBaseReg); //TODO : add some checks #ifdef _M_X64 u64 ripAddr = (u64)emit->GetCodePtr() + 4 + extraBytes; @@ -328,7 +328,6 @@ void OpArg::WriteRest(XEmitter *emit, int extraBytes, X64Reg _operandReg, } } - // W = operand extended width (1 if 64-bit) // R = register# upper bit // X = scale amnt upper bit @@ -1510,6 +1509,24 @@ void XEmitter::FWAIT() Write8(0x9B); } +// TODO: make this more generic +void XEmitter::WriteFloatLoadStore(int bits, FloatOp op, OpArg arg) +{ + int mf = 0; + switch (bits) { + case 32: mf = 0; break; + case 64: mf = 2; break; + default: _assert_msg_(DYNA_REC, 0, "WriteFloatLoadStore: bits is not 32 or 64"); + } + Write8(0xd9 | (mf << 1)); + // x87 instructions use the reg field of the ModR/M byte as opcode: + arg.WriteRest(this, 0, (X64Reg) op); +} + +void XEmitter::FLD(int bits, OpArg src) {WriteFloatLoadStore(bits, floatLD, src);} +void XEmitter::FST(int bits, OpArg dest) {WriteFloatLoadStore(bits, floatST, dest);} +void XEmitter::FSTP(int bits, OpArg dest) {WriteFloatLoadStore(bits, floatSTP, dest);} + void XEmitter::RTDSC() { Write8(0x0F); Write8(0x31); } // helper routines for setting pointers diff --git a/Source/Core/Common/x64Emitter.h b/Source/Core/Common/x64Emitter.h index bdf82442b4..fee21a24db 100644 --- a/Source/Core/Common/x64Emitter.h +++ b/Source/Core/Common/x64Emitter.h @@ -97,6 +97,12 @@ enum NormalOp { nrmXCHG, }; +enum FloatOp { + floatLD = 0, + floatST = 2, + floatSTP = 3, +}; + class XEmitter; // RIP addressing does not benefit from micro op fusion on Core arch @@ -115,6 +121,7 @@ struct OpArg 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 WriteFloatModRM(XEmitter *emit, FloatOp op); void WriteSingleByteOp(XEmitter *emit, u8 op, X64Reg operandReg, int bits); // This one is public - must be written to u64 offset; // use RIP-relative as much as possible - 64-bit immediates are not available. @@ -244,6 +251,7 @@ private: 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 WriteFloatLoadStore(int bits, FloatOp op, OpArg arg); void WriteNormalOp(XEmitter *emit, int bits, NormalOp op, const OpArg &a1, const OpArg &a2); protected: @@ -424,6 +432,10 @@ public: void REP(); void REPNE(); + // x87 + void FLD(int bits, OpArg src); + void FST(int bits, OpArg dest); + void FSTP(int bits, OpArg dest); void FWAIT(); // SSE/SSE2: Floating point arithmetic