From b0bd8a62a2b3e2d79efbb65d7b97d7ee6d10a2b0 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Fri, 12 Jul 2024 21:56:53 -0700 Subject: [PATCH] AVX128: Improve VPERMILPS/PD and VPSHUFD VPSHUFD and VPERMILPS are aliases of each other. Reuses the implementation path from the PSHUFD implementation which has a few swizzles and then a table lookup. VPERMILPD is a very simple swizzle per 128-bit lane. Fixes #3797 Fixes #3784 --- .../Source/Interface/Core/OpcodeDispatcher.h | 2 ++ .../Core/OpcodeDispatcher/AVX_128.cpp | 30 ++++++++++--------- .../Core/OpcodeDispatcher/Vector.cpp | 27 +++++++---------- 3 files changed, 29 insertions(+), 30 deletions(-) diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher.h b/FEXCore/Source/Interface/Core/OpcodeDispatcher.h index 3d0bdb6bc..1572c926b 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher.h +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher.h @@ -958,6 +958,8 @@ public: void UnimplementedOp(OpcodeArgs); void PermissionRestrictedOp(OpcodeArgs); + ///< Helper for PSHUD and VPERMILPS(imm) since they are the same instruction + Ref Single128Bit4ByteVectorShuffle(Ref Src, uint8_t Shuffle); // AVX 128-bit operations Ref AVX128_LoadXMMRegister(uint32_t XMM, bool High); void AVX128_StoreXMMRegister(uint32_t XMM, const Ref Src, bool High); diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher/AVX_128.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher/AVX_128.cpp index 7c3ccd9bd..db1ad3b8a 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher/AVX_128.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher/AVX_128.cpp @@ -158,7 +158,7 @@ void OpDispatchBuilder::InstallAVX128Handlers() { {OPD(1, 0b01, 0x6F), 1, &OpDispatchBuilder::AVX128_VMOVAPS}, {OPD(1, 0b10, 0x6F), 1, &OpDispatchBuilder::AVX128_VMOVAPS}, - {OPD(1, 0b01, 0x70), 1, &OpDispatchBuilder::AVX128_VPSHUF<4, true>}, + {OPD(1, 0b01, 0x70), 1, &OpDispatchBuilder::AVX128_VPERMILImm<4>}, {OPD(1, 0b10, 0x70), 1, &OpDispatchBuilder::AVX128_VPSHUF<2, false>}, {OPD(1, 0b11, 0x70), 1, &OpDispatchBuilder::AVX128_VPSHUF<2, true>}, @@ -1937,26 +1937,28 @@ void OpDispatchBuilder::AVX128_VPERMILImm(OpcodeArgs) { RefPair Result = AVX128_Zext(LoadZeroVector(OpSize::i128Bit)); - ///< TODO: This could be optimized. if constexpr (ElementSize == OpSize::i64Bit) { - Result.Low = _VInsElement(OpSize::i128Bit, ElementSize, 0, Selector & 0b0001, Result.Low, Src.Low); - Result.Low = _VInsElement(OpSize::i128Bit, ElementSize, 1, (Selector & 0b0010) >> 1, Result.Low, Src.Low); + auto DoSwizzle64 = [this](Ref Src, uint8_t Selector) -> Ref { + switch (Selector) { + case 0b00: + case 0b11: return _VDupElement(OpSize::i128Bit, OpSize::i64Bit, Src, Selector & 1); + case 0b01: return _VExtr(OpSize::i128Bit, OpSize::i8Bit, Src, Src, 8); + case 0b10: + // No swizzle + return Src; + default: FEX_UNREACHABLE; + } + }; + Result.Low = DoSwizzle64(Src.Low, Selector & 0b11); if (!Is128Bit) { - Result.High = _VInsElement(OpSize::i128Bit, ElementSize, 0, ((Selector & 0b0100) >> 2), Result.High, Src.High); - Result.High = _VInsElement(OpSize::i128Bit, ElementSize, 1, ((Selector & 0b1000) >> 3), Result.High, Src.High); + Result.High = DoSwizzle64(Src.High, (Selector >> 2) & 0b11); } } else { - Result.Low = _VInsElement(OpSize::i128Bit, ElementSize, 0, Selector & 0b00000011, Result.Low, Src.Low); - Result.Low = _VInsElement(OpSize::i128Bit, ElementSize, 1, (Selector & 0b00001100) >> 2, Result.Low, Src.Low); - Result.Low = _VInsElement(OpSize::i128Bit, ElementSize, 2, (Selector & 0b00110000) >> 4, Result.Low, Src.Low); - Result.Low = _VInsElement(OpSize::i128Bit, ElementSize, 3, (Selector & 0b11000000) >> 6, Result.Low, Src.Low); + Result.Low = Single128Bit4ByteVectorShuffle(Src.Low, Selector); if (!Is128Bit) { - Result.High = _VInsElement(OpSize::i128Bit, ElementSize, 0, (Selector & 0b00000011), Result.High, Src.High); - Result.High = _VInsElement(OpSize::i128Bit, ElementSize, 1, ((Selector & 0b00001100) >> 2), Result.High, Src.High); - Result.High = _VInsElement(OpSize::i128Bit, ElementSize, 2, ((Selector & 0b00110000) >> 4), Result.High, Src.High); - Result.High = _VInsElement(OpSize::i128Bit, ElementSize, 3, ((Selector & 0b11000000) >> 6), Result.High, Src.High); + Result.High = Single128Bit4ByteVectorShuffle(Src.High, Selector); } } diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp index 95cfaf699..ee5150807 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp @@ -1003,20 +1003,14 @@ void OpDispatchBuilder::PSHUFWOp(OpcodeArgs) { template void OpDispatchBuilder::PSHUFWOp(OpcodeArgs); template void OpDispatchBuilder::PSHUFWOp(OpcodeArgs); -void OpDispatchBuilder::PSHUFDOp(OpcodeArgs) { +Ref OpDispatchBuilder::Single128Bit4ByteVectorShuffle(Ref Src, uint8_t Shuffle) { constexpr auto IdentityCopy = 0b11'10'01'00; - uint16_t Shuffle = Op->Src[1].Data.Literal.Value; - const auto Size = GetSrcSize(Op); - Ref Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); - Ref Dest {}; - // TODO: There can be more optimized copies here. switch (Shuffle) { case IdentityCopy: { // Special case identity copy. - Dest = Src; - break; + return Src; } case 0b01'01'00'00: { // Zip with self. @@ -1024,27 +1018,28 @@ void OpDispatchBuilder::PSHUFDOp(OpcodeArgs) { // Dest[1] = Src[0] // Dest[2] = Src[1] // Dest[3] = Src[1] - Dest = _VZip(Size, 4, Src, Src); - break; + return _VZip(OpSize::i128Bit, OpSize::i32Bit, Src, Src); } case 0b00'00'00'00: case 0b01'01'01'01: case 0b10'10'10'10: case 0b11'11'11'11: { // Special case element duplicate and broadcast to low or high 64-bits. - Dest = _VDupElement(Size, 4, Src, Shuffle & 0b11); - break; + return _VDupElement(OpSize::i128Bit, OpSize::i32Bit, Src, Shuffle & 0b11); } default: { // PSHUFD needs to scale index by 16. auto LookupIndexes = - LoadAndCacheIndexedNamedVectorConstant(Size, FEXCore::IR::IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_PSHUFD, Shuffle * 16); - Dest = _VTBL1(Size, Src, LookupIndexes); - break; + LoadAndCacheIndexedNamedVectorConstant(OpSize::i128Bit, FEXCore::IR::IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_PSHUFD, Shuffle * 16); + return _VTBL1(OpSize::i128Bit, Src, LookupIndexes); } } +} - StoreResult(FPRClass, Op, Dest, -1); +void OpDispatchBuilder::PSHUFDOp(OpcodeArgs) { + uint16_t Shuffle = Op->Src[1].Data.Literal.Value; + Ref Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); + StoreResult(FPRClass, Op, Single128Bit4ByteVectorShuffle(Src, Shuffle), -1); } template