diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp index 20851c332..ad0b03ecd 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp @@ -1092,8 +1092,8 @@ void OpDispatchBuilder::CQOOp(OpcodeArgs) { void OpDispatchBuilder::XCHGOp(OpcodeArgs) { // Load both the source and the destination - if (Op->OP == 0x90 && GetSrcSize(Op) >= 4 && Op->Src[0].IsGPR() && Op->Src[0].Data.GPR.GPR == FEXCore::X86State::REG_RAX && - Op->Dest.IsGPR() && Op->Dest.Data.GPR.GPR == FEXCore::X86State::REG_RAX) { + if (Op->OP == 0x90 && Op->Src[0].IsGPR() && Op->Src[0].Data.GPR.GPR == FEXCore::X86State::REG_RAX && Op->Dest.IsGPR() && + Op->Dest.Data.GPR.GPR == FEXCore::X86State::REG_RAX) { // This is one heck of a sucky special case // If we are the 0x90 XCHG opcode (Meaning source is GPR RAX) // and destination register is ALSO RAX @@ -1103,6 +1103,14 @@ void OpDispatchBuilder::XCHGOp(OpcodeArgs) { // But this would result in a zext on 64bit, which would ruin the no-op nature of the instruction // So x86-64 spec mandates this special case that even though it is a 32bit instruction and // is supposed to zext the result, it is a true no-op + // + // x86 spec text here: + // + // XCHG (E)AX, (E)AX (encoded instruction byte is 90H) is an alias for + // NOP regardless of data size prefixes, including REX.W. + // + // Note that also includes 16-bit so we don't gate this on size. The + // sequence (66 90) is a valid two-byte nop that we also ignore. if (Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REP_PREFIX) { // If this instruction has a REP prefix then this is architecturally // defined to be a `PAUSE` instruction. On older processors this ends up diff --git a/unittests/InstructionCountCI/FlagM/HotBlocks.json b/unittests/InstructionCountCI/FlagM/HotBlocks.json index 00f3d0edf..a7e5fd6e2 100644 --- a/unittests/InstructionCountCI/FlagM/HotBlocks.json +++ b/unittests/InstructionCountCI/FlagM/HotBlocks.json @@ -437,6 +437,148 @@ "mov x11, x26" ] }, + "bytemark nn": { + "x86InstructionCount": 12, + "ExpectedInstructionCount": 24, + "x86Insts": [ + "mulpd xmm3,xmm2", + "movupd xmm4,oword [rax+rdx*8+0x216190]", + "mulpd xmm4,xmm6", + "addpd xmm4,xmm3", + "movupd xmm3,oword [rax+rdx*8+0x2155d0]", + "addpd xmm3,xmm4", + "movupd oword [rax+rdx*8+0x2155d0],xmm3", + "movupd xmm3,oword [rax+rdx*8+0x217c10]", + "addpd xmm3,xmm4", + "movupd oword [rax+rdx*8+0x217c10],xmm3", + "add rdx,0x2", + "cmp rdx,0x22" + ], + "ExpectedArm64ASM": [ + "fmul v19.2d, v19.2d, v18.2d", + "add x20, x4, x5, lsl #3", + "mov w21, #0x6190", + "movk w21, #0x21, lsl #16", + "ldr q20, [x20, x21, sxtx]", + "fmul v20.2d, v20.2d, v22.2d", + "fadd v20.2d, v20.2d, v19.2d", + "add x20, x4, x5, lsl #3", + "mov w21, #0x55d0", + "movk w21, #0x21, lsl #16", + "ldr q19, [x20, x21, sxtx]", + "fadd v19.2d, v19.2d, v20.2d", + "add x20, x4, x5, lsl #3", + "str q19, [x20, x21, sxtx]", + "add x20, x4, x5, lsl #3", + "mov w21, #0x7c10", + "movk w21, #0x21, lsl #16", + "ldr q19, [x20, x21, sxtx]", + "fadd v19.2d, v19.2d, v20.2d", + "add x20, x4, x5, lsl #3", + "str q19, [x20, x21, sxtx]", + "add x5, x5, #0x2 (2)", + "subs x26, x5, #0x22 (34)", + "mov x27, x5" + ] + }, + "000000000020e9bd :": { + "x86InstructionCount": 35, + "ExpectedInstructionCount": 55, + "x86Insts": [ + "mov rsi,0xfffffffffffffee8", + "xchg ax,ax", + "mov ecx,eax", + "imul eax,edx,0x8149a", + "imul edx,ecx,0x3e322", + "add edx,eax", + "movsxd rax,edx", + "imul rdx,rax,0xffffffff8646c299", + "shr rdx,0x20", + "add edx,eax", + "mov edi,edx", + "shr edi,0x1f", + "sar edx,0x13", + "add edx,edi", + "imul edx,edx,0xf408b", + "sub eax,edx", + "movsxd rdx,eax", + "imul rdi,rdx,0x14f8b589", + "mov r8,rdi", + "shr r8,0x3f", + "sar rdi,0x2d", + "add edi,r8d", + "imul edi,edi,0x186a0", + "sub edx,edi", + "mov edi,edx", + "neg edi", + "cmovs edi,edx", + "xorps xmm0,xmm0", + "cvtsi2sd xmm0,rdi", + "divsd xmm0,xmm1", + "addsd xmm0,xmm2", + "mulsd xmm0,xmm3", + "movsd qword [rsi+0x216428],xmm0", + "mov edx,ecx", + "add rsi,0x8" + ], + "ExpectedArm64ASM": [ + "mov x10, #0xfffffffffffffee8", + "mov w7, w4", + "mov w20, #0x149a", + "movk w20, #0x8, lsl #16", + "mul w4, w5, w20", + "mov w20, #0xe322", + "movk w20, #0x3, lsl #16", + "mul w5, w7, w20", + "add w5, w5, w4", + "sxtw x4, w5", + "mov x20, #0xffffffffffffc299", + "movk x20, #0x8646, lsl #16", + "mul x5, x4, x20", + "lsr x5, x5, #32", + "add w5, w5, w4", + "mov w11, w5", + "lsr w11, w11, #31", + "asr w5, w5, #19", + "add w5, w5, w11", + "mov w20, #0x408b", + "movk w20, #0xf, lsl #16", + "mul w5, w5, w20", + "sub w4, w4, w5", + "sxtw x5, w4", + "mov w20, #0xb589", + "movk w20, #0x14f8, lsl #16", + "mul x11, x5, x20", + "mov x12, x11", + "lsr x12, x12, #63", + "asr x11, x11, #45", + "add w11, w11, w12", + "mov w20, #0x86a0", + "movk w20, #0x1, lsl #16", + "mul w11, w11, w20", + "sub w5, w5, w11", + "mov w11, w5", + "negs w11, w11", + "csel w11, w5, w11, mi", + "movi v16.2d, #0x0", + "scvtf d0, x11", + "mov v16.d[0], v0.d[0]", + "fdiv d0, d16, d17", + "mov v16.d[0], v0.d[0]", + "fadd d0, d16, d18", + "mov v16.d[0], v0.d[0]", + "fmul d0, d16, d19", + "mov v16.d[0], v0.d[0]", + "mov w20, #0x6428", + "movk w20, #0x21, lsl #16", + "str d16, [x10, x20, sxtx]", + "mov w5, w7", + "adds x26, x10, #0x8 (8)", + "cfinv", + "mov x27, x10", + "mov x10, x26" + ] + }, "glibc AVX memcpy block 1": { "x86InstructionCount": 20, "ExpectedInstructionCount": 26,