diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher.h b/FEXCore/Source/Interface/Core/OpcodeDispatcher.h index df7b96325..d7f8c315a 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher.h +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher.h @@ -1118,6 +1118,8 @@ public: template void AVX128_Vector_CVT_Int_To_Float(OpcodeArgs); + void AVX128_VEXTRACT128(OpcodeArgs); + // End of AVX 128-bit implementation void InvalidOp(OpcodeArgs); diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher/AVX_128.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher/AVX_128.cpp index ab90feaa0..fe2f5a5b8 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher/AVX_128.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher/AVX_128.cpp @@ -354,13 +354,13 @@ void OpDispatchBuilder::InstallAVX128Handlers() { {OPD(3, 0b01, 0x17), 1, &OpDispatchBuilder::AVX128_PExtr<4>}, {OPD(3, 0b01, 0x18), 1, &OpDispatchBuilder::AVX128_VINSERT}, - // TODO: {OPD(3, 0b01, 0x19), 1, &OpDispatchBuilder::VEXTRACT128Op}, + {OPD(3, 0b01, 0x19), 1, &OpDispatchBuilder::AVX128_VEXTRACT128}, {OPD(3, 0b01, 0x20), 1, &OpDispatchBuilder::AVX128_VPINSRB}, {OPD(3, 0b01, 0x21), 1, &OpDispatchBuilder::VINSERTPSOp}, {OPD(3, 0b01, 0x22), 1, &OpDispatchBuilder::AVX128_VPINSRDQ}, {OPD(3, 0b01, 0x38), 1, &OpDispatchBuilder::AVX128_VINSERT}, - // TODO: {OPD(3, 0b01, 0x39), 1, &OpDispatchBuilder::VEXTRACT128Op}, + {OPD(3, 0b01, 0x39), 1, &OpDispatchBuilder::AVX128_VEXTRACT128}, // TODO: {OPD(3, 0b01, 0x40), 1, &OpDispatchBuilder::VDPPOp<4>}, // TODO: {OPD(3, 0b01, 0x41), 1, &OpDispatchBuilder::VDPPOp<8>}, @@ -1578,4 +1578,26 @@ void OpDispatchBuilder::AVX128_Vector_CVT_Int_To_Float(OpcodeArgs) { AVX128_StoreResult_WithOpSize(Op, Op->Dest, Result); } +void OpDispatchBuilder::AVX128_VEXTRACT128(OpcodeArgs) { + const auto DstIsXMM = Op->Dest.IsGPR(); + const auto Selector = Op->Src[1].Literal() & 0b1; + + ///< TODO: Once we support loading only upper-half of the ymm register we can load the half depending on selection literal. + auto Src = AVX128_LoadSource_WithOpSize(Op, Op->Src[0], Op->Flags, true); + + RefPair Result {}; + if (Selector == 0) { + Result.Low = Src.Low; + } else { + Result.Low = Src.High; + } + + if (DstIsXMM) { + // Only zero the upper-half when destination is XMM, otherwise this is a memory store. + Result = AVX128_Zext(Result.Low); + } + + AVX128_StoreResult_WithOpSize(Op, Op->Dest, Result); +} + } // namespace FEXCore::IR