diff --git a/Source/Core/Common/x64Emitter.cpp b/Source/Core/Common/x64Emitter.cpp index 0b2ca9c4a6..2bbd0a5990 100644 --- a/Source/Core/Common/x64Emitter.cpp +++ b/Source/Core/Common/x64Emitter.cpp @@ -76,6 +76,32 @@ enum NormalSSEOps sseMOVNTP = 0x2B, }; +enum class NormalOp +{ + ADD, + ADC, + SUB, + SBB, + AND, + OR, + XOR, + MOV, + TEST, + CMP, + XCHG, +}; + +enum class FloatOp +{ + LD = 0, + ST = 2, + STP = 3, + LD80 = 5, + STP80 = 7, + + Invalid = -1, +}; + void XEmitter::SetCodePtr(u8* ptr) { code = ptr; @@ -1353,6 +1379,7 @@ void OpArg::WriteNormalOp(XEmitter* emit, bool toRM, NormalOp op, const OpArg& o emit->Write8(0x66); int immToWrite = 0; + const NormalOpDef& op_def = normalops[static_cast(op)]; if (operand.IsImm()) { @@ -1366,21 +1393,21 @@ void OpArg::WriteNormalOp(XEmitter* emit, bool toRM, NormalOp op, const OpArg& o if (operand.scale == SCALE_IMM8 && bits == 8) { // op al, imm8 - if (!scale && offsetOrBaseReg == AL && normalops[op].eaximm8 != 0xCC) + if (!scale && offsetOrBaseReg == AL && op_def.eaximm8 != 0xCC) { - emit->Write8(normalops[op].eaximm8); + emit->Write8(op_def.eaximm8); emit->Write8((u8)operand.offset); return; } // mov reg, imm8 - if (!scale && op == nrmMOV) + if (!scale && op == NormalOp::MOV) { emit->Write8(0xB0 + (offsetOrBaseReg & 7)); emit->Write8((u8)operand.offset); return; } // op r/m8, imm8 - emit->Write8(normalops[op].imm8); + emit->Write8(op_def.imm8); immToWrite = 8; } else if ((operand.scale == SCALE_IMM16 && bits == 16) || @@ -1390,17 +1417,17 @@ void OpArg::WriteNormalOp(XEmitter* emit, bool toRM, NormalOp op, const OpArg& o // Try to save immediate size if we can, but first check to see // if the instruction supports simm8. // op r/m, imm8 - if (normalops[op].simm8 != 0xCC && + if (op_def.simm8 != 0xCC && ((operand.scale == SCALE_IMM16 && (s16)operand.offset == (s8)operand.offset) || (operand.scale == SCALE_IMM32 && (s32)operand.offset == (s8)operand.offset))) { - emit->Write8(normalops[op].simm8); + emit->Write8(op_def.simm8); immToWrite = 8; } else { // mov reg, imm - if (!scale && op == nrmMOV && bits != 64) + if (!scale && op == NormalOp::MOV && bits != 64) { emit->Write8(0xB8 + (offsetOrBaseReg & 7)); if (bits == 16) @@ -1410,9 +1437,9 @@ void OpArg::WriteNormalOp(XEmitter* emit, bool toRM, NormalOp op, const OpArg& o return; } // op eax, imm - if (!scale && offsetOrBaseReg == EAX && normalops[op].eaximm32 != 0xCC) + if (!scale && offsetOrBaseReg == EAX && op_def.eaximm32 != 0xCC) { - emit->Write8(normalops[op].eaximm32); + emit->Write8(op_def.eaximm32); if (bits == 16) emit->Write16((u16)operand.offset); else @@ -1420,7 +1447,7 @@ void OpArg::WriteNormalOp(XEmitter* emit, bool toRM, NormalOp op, const OpArg& o return; } // op r/m, imm - emit->Write8(normalops[op].imm32); + emit->Write8(op_def.imm32); immToWrite = bits == 16 ? 16 : 32; } } @@ -1429,7 +1456,7 @@ void OpArg::WriteNormalOp(XEmitter* emit, bool toRM, NormalOp op, const OpArg& o (operand.scale == SCALE_IMM8 && bits == 64)) { // op r/m, imm8 - emit->Write8(normalops[op].simm8); + emit->Write8(op_def.simm8); immToWrite = 8; } else if (operand.scale == SCALE_IMM64 && bits == 64) @@ -1440,7 +1467,7 @@ void OpArg::WriteNormalOp(XEmitter* emit, bool toRM, NormalOp op, const OpArg& o "WriteNormalOp - MOV with 64-bit imm requires register destination"); } // mov reg64, imm64 - else if (op == nrmMOV) + else if (op == NormalOp::MOV) { emit->Write8(0xB8 + (offsetOrBaseReg & 7)); emit->Write64((u64)operand.offset); @@ -1452,7 +1479,9 @@ void OpArg::WriteNormalOp(XEmitter* emit, bool toRM, NormalOp op, const OpArg& o { ASSERT_MSG(DYNA_REC, 0, "WriteNormalOp - Unhandled case %d %d", operand.scale, bits); } - _operandReg = (X64Reg)normalops[op].ext; // pass extension in REG of ModRM + + // pass extension in REG of ModRM + _operandReg = static_cast(op_def.ext); } else { @@ -1461,12 +1490,12 @@ void OpArg::WriteNormalOp(XEmitter* emit, bool toRM, NormalOp op, const OpArg& o // op r/m, reg if (toRM) { - emit->Write8(bits == 8 ? normalops[op].toRm8 : normalops[op].toRm32); + emit->Write8(bits == 8 ? op_def.toRm8 : op_def.toRm32); } // op reg, r/m else { - emit->Write8(bits == 8 ? normalops[op].fromRm8 : normalops[op].fromRm32); + emit->Write8(bits == 8 ? op_def.fromRm8 : op_def.fromRm32); } } WriteRest(emit, immToWrite >> 3, _operandReg); @@ -1518,57 +1547,57 @@ void XEmitter::WriteNormalOp(int bits, NormalOp op, const OpArg& a1, const OpArg void XEmitter::ADD(int bits, const OpArg& a1, const OpArg& a2) { CheckFlags(); - WriteNormalOp(bits, nrmADD, a1, a2); + WriteNormalOp(bits, NormalOp::ADD, a1, a2); } void XEmitter::ADC(int bits, const OpArg& a1, const OpArg& a2) { CheckFlags(); - WriteNormalOp(bits, nrmADC, a1, a2); + WriteNormalOp(bits, NormalOp::ADC, a1, a2); } void XEmitter::SUB(int bits, const OpArg& a1, const OpArg& a2) { CheckFlags(); - WriteNormalOp(bits, nrmSUB, a1, a2); + WriteNormalOp(bits, NormalOp::SUB, a1, a2); } void XEmitter::SBB(int bits, const OpArg& a1, const OpArg& a2) { CheckFlags(); - WriteNormalOp(bits, nrmSBB, a1, a2); + WriteNormalOp(bits, NormalOp::SBB, a1, a2); } void XEmitter::AND(int bits, const OpArg& a1, const OpArg& a2) { CheckFlags(); - WriteNormalOp(bits, nrmAND, a1, a2); + WriteNormalOp(bits, NormalOp::AND, a1, a2); } void XEmitter::OR(int bits, const OpArg& a1, const OpArg& a2) { CheckFlags(); - WriteNormalOp(bits, nrmOR, a1, a2); + WriteNormalOp(bits, NormalOp::OR, a1, a2); } void XEmitter::XOR(int bits, const OpArg& a1, const OpArg& a2) { CheckFlags(); - WriteNormalOp(bits, nrmXOR, a1, a2); + WriteNormalOp(bits, NormalOp::XOR, a1, a2); } void XEmitter::MOV(int bits, const OpArg& a1, const OpArg& a2) { if (a1.IsSimpleReg() && a2.IsSimpleReg() && a1.GetSimpleReg() == a2.GetSimpleReg()) ERROR_LOG(DYNA_REC, "Redundant MOV @ %p - bug in JIT?", code); - WriteNormalOp(bits, nrmMOV, a1, a2); + WriteNormalOp(bits, NormalOp::MOV, a1, a2); } void XEmitter::TEST(int bits, const OpArg& a1, const OpArg& a2) { CheckFlags(); - WriteNormalOp(bits, nrmTEST, a1, a2); + WriteNormalOp(bits, NormalOp::TEST, a1, a2); } void XEmitter::CMP(int bits, const OpArg& a1, const OpArg& a2) { CheckFlags(); - WriteNormalOp(bits, nrmCMP, a1, a2); + WriteNormalOp(bits, NormalOp::CMP, a1, a2); } void XEmitter::XCHG(int bits, const OpArg& a1, const OpArg& a2) { - WriteNormalOp(bits, nrmXCHG, a1, a2); + WriteNormalOp(bits, NormalOp::XCHG, a1, a2); } void XEmitter::CMP_or_TEST(int bits, const OpArg& a1, const OpArg& a2) { @@ -1576,11 +1605,11 @@ void XEmitter::CMP_or_TEST(int bits, const OpArg& a1, const OpArg& a2) if (a1.IsSimpleReg() && a2.IsImm() && a2.offset == 0) // turn 'CMP reg, 0' into shorter 'TEST reg, reg' { - WriteNormalOp(bits, nrmTEST, a1, a1); + WriteNormalOp(bits, NormalOp::TEST, a1, a1); } else { - WriteNormalOp(bits, nrmCMP, a1, a2); + WriteNormalOp(bits, NormalOp::CMP, a1, a2); } } @@ -3248,7 +3277,7 @@ void XEmitter::FWAIT() void XEmitter::WriteFloatLoadStore(int bits, FloatOp op, FloatOp op_80b, const OpArg& arg) { int mf = 0; - ASSERT_MSG(DYNA_REC, !(bits == 80 && op_80b == floatINVALID), + ASSERT_MSG(DYNA_REC, !(bits == 80 && op_80b == FloatOp::Invalid), "WriteFloatLoadStore: 80 bits not supported for this instruction"); switch (bits) { @@ -3268,20 +3297,20 @@ void XEmitter::WriteFloatLoadStore(int bits, FloatOp op, FloatOp op_80b, const O // x87 instructions use the reg field of the ModR/M byte as opcode: if (bits == 80) op = op_80b; - arg.WriteRest(this, 0, (X64Reg)op); + arg.WriteRest(this, 0, static_cast(op)); } void XEmitter::FLD(int bits, const OpArg& src) { - WriteFloatLoadStore(bits, floatLD, floatLD80, src); + WriteFloatLoadStore(bits, FloatOp::LD, FloatOp::LD80, src); } void XEmitter::FST(int bits, const OpArg& dest) { - WriteFloatLoadStore(bits, floatST, floatINVALID, dest); + WriteFloatLoadStore(bits, FloatOp::ST, FloatOp::Invalid, dest); } void XEmitter::FSTP(int bits, const OpArg& dest) { - WriteFloatLoadStore(bits, floatSTP, floatSTP80, dest); + WriteFloatLoadStore(bits, FloatOp::STP, FloatOp::STP80, dest); } void XEmitter::FNSTSW_AX() { diff --git a/Source/Core/Common/x64Emitter.h b/Source/Core/Common/x64Emitter.h index e7c1408a1b..90a678e1d4 100644 --- a/Source/Core/Common/x64Emitter.h +++ b/Source/Core/Common/x64Emitter.h @@ -78,21 +78,6 @@ enum SCALE_IMM64 = 0xF3, }; -enum NormalOp -{ - nrmADD, - nrmADC, - nrmSUB, - nrmSBB, - nrmAND, - nrmOR, - nrmXOR, - nrmMOV, - nrmTEST, - nrmCMP, - nrmXCHG, -}; - enum SSECompare { CMP_EQ = 0, @@ -105,18 +90,9 @@ enum SSECompare CMP_ORD = 7, }; -enum FloatOp -{ - floatLD = 0, - floatST = 2, - floatSTP = 3, - floatLD80 = 5, - floatSTP80 = 7, - - floatINVALID = -1, -}; - class XEmitter; +enum class FloatOp; +enum class NormalOp; // Information about a generated MOV op struct MovInfo final @@ -130,7 +106,9 @@ struct MovInfo final // RIP addressing does not benefit from micro op fusion on Core arch struct OpArg { - friend class XEmitter; // For accessing offset and operandReg + // For accessing offset and operandReg. + // This also allows us to keep the op writing functions private. + friend class XEmitter; OpArg() {} // dummy op arg, used for storage OpArg(u64 _offset, int _scale, X64Reg rmReg = RAX, X64Reg scaledReg = RAX) @@ -147,13 +125,6 @@ struct OpArg return operandReg == b.operandReg && scale == b.scale && offsetOrBaseReg == b.offsetOrBaseReg && indexReg == b.indexReg && offset == b.offset; } - void WriteREX(XEmitter* emit, int opBits, int bits, int customOp = -1) const; - void WriteVEX(XEmitter* emit, X64Reg regOp1, X64Reg regOp2, int L, int pp, int mmmmm, - int W = 0) const; - void WriteRest(XEmitter* emit, int extraBytes = 0, X64Reg operandReg = INVALID_REG, - bool warn_64bit_offset = true) const; - void WriteSingleByteOp(XEmitter* emit, u8 op, X64Reg operandReg, int bits); - u64 Imm64() const { DEBUG_ASSERT(scale == SCALE_IMM64); @@ -217,7 +188,6 @@ struct OpArg return OpArg((u8)offset, SCALE_IMM8); } - void WriteNormalOp(XEmitter* emit, bool toRM, NormalOp op, const OpArg& operand, int bits) const; bool IsImm() const { return scale == SCALE_IMM8 || scale == SCALE_IMM16 || scale == SCALE_IMM32 || @@ -259,6 +229,14 @@ struct OpArg } private: + void WriteREX(XEmitter* emit, int opBits, int bits, int customOp = -1) const; + void WriteVEX(XEmitter* emit, X64Reg regOp1, X64Reg regOp2, int L, int pp, int mmmmm, + int W = 0) const; + void WriteRest(XEmitter* emit, int extraBytes = 0, X64Reg operandReg = INVALID_REG, + bool warn_64bit_offset = true) const; + void WriteSingleByteOp(XEmitter* emit, u8 op, X64Reg operandReg, int bits); + void WriteNormalOp(XEmitter* emit, bool toRM, NormalOp op, const OpArg& operand, int bits) const; + u8 scale; u16 offsetOrBaseReg; u16 indexReg;