From 38c9f14dbd1ab5d97bc266ffb07f48e1ef5c1478 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Fri, 4 Sep 2026 12:19:21 -0700 Subject: [PATCH] OpcodeDispatcher: Explicitly handle no-nop vector moves Just be very explicit about this rather than questioning why MMX moves can't be a nop in the regular vector move code. Doesn't change codegen so binarycacheversion doesn't need to change. --- FEXCore/Source/Interface/Core/OpcodeDispatcher.h | 1 + .../Interface/Core/OpcodeDispatcher/DDDTables.h | 6 +++--- .../Source/Interface/Core/OpcodeDispatcher/Vector.cpp | 11 +++++++---- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher.h b/FEXCore/Source/Interface/Core/OpcodeDispatcher.h index 94efddd47..4a298a812 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher.h +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher.h @@ -360,6 +360,7 @@ public: void MOVGPRNTOp(OpcodeArgs); void MOVVectorAlignedOp(OpcodeArgs); void MOVVectorUnalignedOp(OpcodeArgs); + void MOVVectorUnalignedNoNopOp(OpcodeArgs); void MOVVectorNTOp(OpcodeArgs, bool IsAVX); void ALUOp(OpcodeArgs, FEXCore::IR::IROps ALUIROp, FEXCore::IR::IROps AtomicFetchOp, unsigned SrcIdx); void LSLOp(OpcodeArgs); diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher/DDDTables.h b/FEXCore/Source/Interface/Core/OpcodeDispatcher/DDDTables.h index 413d7a6cf..844c301c2 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher/DDDTables.h +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher/DDDTables.h @@ -26,8 +26,8 @@ constexpr DispatchTableEntry OpDispatch_DDDTable[] = { {0xA0, 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::VPFCMPOp, 2>}, {0xA4, 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::VectorALUOp, IR::OP_VFMAX, OpSize::i32Bit>}, // Can be treated as a move - {0xA6, 1, &OpDispatchBuilder::MOVVectorUnalignedOp}, - {0xA7, 1, &OpDispatchBuilder::MOVVectorUnalignedOp}, + {0xA6, 1, &OpDispatchBuilder::MOVVectorUnalignedNoNopOp}, + {0xA7, 1, &OpDispatchBuilder::MOVVectorUnalignedNoNopOp}, {0xAA, 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::VectorALUROp, IR::OP_VFSUB, OpSize::i32Bit>}, {0xAE, 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::VectorALUOp, IR::OP_VFADDP, OpSize::i32Bit>}, @@ -35,7 +35,7 @@ constexpr DispatchTableEntry OpDispatch_DDDTable[] = { {0xB0, 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::VPFCMPOp, 0>}, {0xB4, 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::VectorALUOp, IR::OP_VFMUL, OpSize::i32Bit>}, // Can be treated as a move - {0xB6, 1, &OpDispatchBuilder::MOVVectorUnalignedOp}, + {0xB6, 1, &OpDispatchBuilder::MOVVectorUnalignedNoNopOp}, {0xB7, 1, &OpDispatchBuilder::PMULHRWOp}, {0xBB, 1, &OpDispatchBuilder::PSWAPDOp}, diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp index 22e4cb95e..97d12922b 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp @@ -34,10 +34,7 @@ void OpDispatchBuilder::MOVVectorAlignedOp(OpcodeArgs) { } void OpDispatchBuilder::MOVVectorUnalignedOp(OpcodeArgs) { - const bool DestIsMMX = - Op->Dest.IsGPR() && Op->Dest.Data.GPR.GPR >= FEXCore::X86State::REG_MM_0 && Op->Dest.Data.GPR.GPR <= FEXCore::X86State::REG_MM_7; - - if (!DestIsMMX && Op->Dest.IsGPR() && Op->Src[0].IsGPR() && Op->Dest.Data.GPR.GPR == Op->Src[0].Data.GPR.GPR) { + if (Op->Dest.IsGPR() && Op->Src[0].IsGPR() && Op->Dest.Data.GPR.GPR == Op->Src[0].Data.GPR.GPR) { // Nop return; } @@ -45,6 +42,12 @@ void OpDispatchBuilder::MOVVectorUnalignedOp(OpcodeArgs) { StoreResult_WithAVXInsert(VectorOpType::SSE, RegClass::FPR, Op, Src); } +void OpDispatchBuilder::MOVVectorUnalignedNoNopOp(OpcodeArgs) { + // Moves to same register might have secondary-effects and can't convert to a nop. + Ref Src = LoadSourceFPR(Op, Op->Src[0], Op->Flags, {.Align = OpSize::i8Bit}); + StoreResult_WithAVXInsert(VectorOpType::SSE, RegClass::FPR, Op, Src); +} + void OpDispatchBuilder::MOVVectorNTOp(OpcodeArgs, bool IsAVX) { const auto Size = OpSizeFromDst(Op);