From 33a2fbb89659e41a3ca6aec714a67e61ba0fd7c3 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Wed, 13 Sep 2023 13:50:59 -0700 Subject: [PATCH 1/2] OpcodeDispatcher: Optimize pextr{b,w} Cleans up the code which had special cased some 32-bit optimization which is unnecessary now that both 8-bit and 16-bit are also optimized. When FEX does a VExtractToGPR, the result is zero extended to the full GPR register size. This means we don't need to do a zero extend when storing to a guest GPR. Makes pextr{b,w} optimal now. Needs #3088 merged first. --- .../Core/OpcodeDispatcher/Vector.cpp | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp index 9d90c46b7..090da92b7 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp @@ -1609,34 +1609,36 @@ void OpDispatchBuilder::VINSERTPSOp(OpcodeArgs) { template void OpDispatchBuilder::PExtrOp(OpcodeArgs) { - const auto Size = GetSrcSize(Op); const auto DstSize = GetDstSize(Op); - const auto Is32Bit = ElementSize == 4; OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, -1); LOGMAN_THROW_A_FMT(Op->Src[1].IsLiteral(), "Src1 needs to be literal here"); uint64_t Index = Op->Src[1].Data.Literal.Value; - const uint8_t NumElements = Is32Bit ? Size / DstSize - : Size / ElementSize; - Index &= NumElements - 1; + // Fixup of 32-bit element size. + // When the element size is 32-bit then it can be overriden as 64-bit because the encoding of PEXTRD/PEXTRQ + // is the same except that REX.W or VEX.W is set to 1. Incredibly frustrating. + // Use the destination size as the element size in this case. + size_t OverridenElementSize = ElementSize; + if constexpr (ElementSize == 4) { + OverridenElementSize = DstSize; + } - OrderedNode *Result = Is32Bit ? _VExtractToGPR(16, DstSize, Src, Index) - : _VExtractToGPR(16, ElementSize, Src, Index); + // AVX version only operates on 128-bit. + const uint8_t NumElements = std::min(GetSrcSize(Op), 16) / OverridenElementSize; + Index &= NumElements - 1; if (Op->Dest.IsGPR()) { const uint8_t GPRSize = CTX->GetGPRSize(); - - // If we are storing to a GPR then we zero extend it - if constexpr (ElementSize < 4) { - Result = _Bfe(IR::SizeToOpSize(GPRSize), ElementSize * 8, 0, Result); - } + // Extract already zero extends the result. + OrderedNode *Result = _VExtractToGPR(16, OverridenElementSize, Src, Index); StoreResult_WithOpSize(GPRClass, Op, Op->Dest, Result, GPRSize, -1); - } else { - // If we are storing to memory then we store the size of the element extracted - const auto StoreSize = Is32Bit ? DstSize : ElementSize; - StoreResult_WithOpSize(GPRClass, Op, Op->Dest, Result, StoreSize, -1); + return; } + + // If we are storing to memory then we store the size of the element extracted + OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, -1, false); + _VStoreVectorElement(16, OverridenElementSize, Src, Index, Dest); } template From 3e40713ccc8d3efb2a938e643b7e4bed5eb71d1d Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Wed, 13 Sep 2023 13:52:55 -0700 Subject: [PATCH 2/2] InstCountCI: Update for optimized pextr{b,w} --- unittests/InstructionCountCI/H0F3A.json | 108 +++++++++++++--- unittests/InstructionCountCI/Secondary.json | 35 +++-- .../InstructionCountCI/Secondary_OpSize.json | 120 +++++++++++++----- unittests/InstructionCountCI/VEX_map1.json | 48 +++++-- unittests/InstructionCountCI/VEX_map3.json | 86 +++++++++++-- 5 files changed, 308 insertions(+), 89 deletions(-) diff --git a/unittests/InstructionCountCI/H0F3A.json b/unittests/InstructionCountCI/H0F3A.json index c97ae2551..778d0dad6 100644 --- a/unittests/InstructionCountCI/H0F3A.json +++ b/unittests/InstructionCountCI/H0F3A.json @@ -620,47 +620,43 @@ ] }, "pextrb eax, xmm0, 0000b": { - "ExpectedInstructionCount": 2, - "Optimal": "No", + "ExpectedInstructionCount": 1, + "Optimal": "Yes", "Comment": [ "0x66 0x0f 0x3a 0x14" ], "ExpectedArm64ASM": [ - "umov w20, v16.b[0]", - "uxtb x4, w20" + "umov w4, v16.b[0]" ] }, "pextrb eax, xmm0, 1111b": { - "ExpectedInstructionCount": 2, - "Optimal": "No", + "ExpectedInstructionCount": 1, + "Optimal": "Yes", "Comment": [ "0x66 0x0f 0x3a 0x14" ], "ExpectedArm64ASM": [ - "umov w20, v16.b[15]", - "uxtb x4, w20" + "umov w4, v16.b[15]" ] }, "pextrw eax, xmm0, 000b": { - "ExpectedInstructionCount": 2, - "Optimal": "No", + "ExpectedInstructionCount": 1, + "Optimal": "Yes", "Comment": [ "0x66 0x0f 0x3a 0x15" ], "ExpectedArm64ASM": [ - "umov w20, v16.h[0]", - "uxth x4, w20" + "umov w4, v16.h[0]" ] }, "pextrw eax, xmm0, 111b": { - "ExpectedInstructionCount": 2, - "Optimal": "No", + "ExpectedInstructionCount": 1, + "Optimal": "Yes", "Comment": [ "0x66 0x0f 0x3a 0x15" ], "ExpectedArm64ASM": [ - "umov w20, v16.h[7]", - "uxth x4, w20" + "umov w4, v16.h[7]" ] }, "pextrd eax, xmm0, 00b": { @@ -703,6 +699,86 @@ "mov x4, v16.d[1]" ] }, + "pextrb [rax], xmm0, 0000b": { + "ExpectedInstructionCount": 1, + "Optimal": "Yes", + "Comment": [ + "0x66 0x0f 0x3a 0x14" + ], + "ExpectedArm64ASM": [ + "st1 {v16.b}[0], [x4]" + ] + }, + "pextrb [rax], xmm0, 1111b": { + "ExpectedInstructionCount": 1, + "Optimal": "Yes", + "Comment": [ + "0x66 0x0f 0x3a 0x14" + ], + "ExpectedArm64ASM": [ + "st1 {v16.b}[15], [x4]" + ] + }, + "pextrw [rax], xmm0, 000b": { + "ExpectedInstructionCount": 1, + "Optimal": "Yes", + "Comment": [ + "0x66 0x0f 0x3a 0x15" + ], + "ExpectedArm64ASM": [ + "st1 {v16.h}[0], [x4]" + ] + }, + "pextrw [rax], xmm0, 111b": { + "ExpectedInstructionCount": 1, + "Optimal": "Yes", + "Comment": [ + "0x66 0x0f 0x3a 0x15" + ], + "ExpectedArm64ASM": [ + "st1 {v16.h}[7], [x4]" + ] + }, + "pextrd [rax], xmm0, 00b": { + "ExpectedInstructionCount": 1, + "Optimal": "Yes", + "Comment": [ + "0x66 0x0f 0x3a 0x16" + ], + "ExpectedArm64ASM": [ + "st1 {v16.s}[0], [x4]" + ] + }, + "pextrd [rax], xmm0, 11b": { + "ExpectedInstructionCount": 1, + "Optimal": "Yes", + "Comment": [ + "0x66 0x0f 0x3a 0x16" + ], + "ExpectedArm64ASM": [ + "st1 {v16.s}[3], [x4]" + ] + }, + "pextrq [rax], xmm0, 0b": { + "ExpectedInstructionCount": 1, + "Optimal": "Yes", + "Comment": [ + "0x66 REX.W 0x0f 0x3a 0x16" + ], + "ExpectedArm64ASM": [ + "st1 {v16.d}[0], [x4]" + ] + }, + "pextrq [rax], xmm0, 1b": { + "ExpectedInstructionCount": 1, + "Optimal": "Yes", + "Comment": [ + "0x66 REX.W 0x0f 0x3a 0x16" + ], + "ExpectedArm64ASM": [ + "st1 {v16.d}[1], [x4]" + ] + }, "extractps eax, xmm0, 00b": { "ExpectedInstructionCount": 1, "Optimal": "Yes", diff --git a/unittests/InstructionCountCI/Secondary.json b/unittests/InstructionCountCI/Secondary.json index aaf59879e..ab5d32a8f 100644 --- a/unittests/InstructionCountCI/Secondary.json +++ b/unittests/InstructionCountCI/Secondary.json @@ -3562,53 +3562,48 @@ ] }, "pextrw eax, mm0, 0": { - "ExpectedInstructionCount": 3, - "Optimal": "No", + "ExpectedInstructionCount": 2, + "Optimal": "Yes", "Comment": "0x0f 0xc5", "ExpectedArm64ASM": [ "ldr d2, [x28, #752]", - "umov w20, v2.h[0]", - "uxth x4, w20" + "umov w4, v2.h[0]" ] }, "pextrw eax, mm0, 1": { - "ExpectedInstructionCount": 3, - "Optimal": "No", + "ExpectedInstructionCount": 2, + "Optimal": "Yes", "Comment": "0x0f 0xc5", "ExpectedArm64ASM": [ "ldr d2, [x28, #752]", - "umov w20, v2.h[1]", - "uxth x4, w20" + "umov w4, v2.h[1]" ] }, "pextrw eax, mm0, 2": { - "ExpectedInstructionCount": 3, - "Optimal": "No", + "ExpectedInstructionCount": 2, + "Optimal": "Yes", "Comment": "0x0f 0xc5", "ExpectedArm64ASM": [ "ldr d2, [x28, #752]", - "umov w20, v2.h[2]", - "uxth x4, w20" + "umov w4, v2.h[2]" ] }, "pextrw eax, mm0, 3": { - "ExpectedInstructionCount": 3, - "Optimal": "No", + "ExpectedInstructionCount": 2, + "Optimal": "Yes", "Comment": "0x0f 0xc5", "ExpectedArm64ASM": [ "ldr d2, [x28, #752]", - "umov w20, v2.h[3]", - "uxth x4, w20" + "umov w4, v2.h[3]" ] }, "pextrw eax, mm0, 4": { - "ExpectedInstructionCount": 3, - "Optimal": "No", + "ExpectedInstructionCount": 2, + "Optimal": "Yes", "Comment": "0x0f 0xc5", "ExpectedArm64ASM": [ "ldr d2, [x28, #752]", - "umov w20, v2.h[0]", - "uxth x4, w20" + "umov w4, v2.h[0]" ] }, "shufps xmm0, xmm1, 01000100b": { diff --git a/unittests/InstructionCountCI/Secondary_OpSize.json b/unittests/InstructionCountCI/Secondary_OpSize.json index cb6373d36..add915153 100644 --- a/unittests/InstructionCountCI/Secondary_OpSize.json +++ b/unittests/InstructionCountCI/Secondary_OpSize.json @@ -882,75 +882,131 @@ ] }, "pextrw eax, xmm0, 000b": { - "ExpectedInstructionCount": 2, - "Optimal": "No", + "ExpectedInstructionCount": 1, + "Optimal": "Yes", "Comment": "0x66 0x0f 0xc5", "ExpectedArm64ASM": [ - "umov w20, v16.h[0]", - "uxth x4, w20" + "umov w4, v16.h[0]" ] }, "pextrw eax, xmm0, 001b": { - "ExpectedInstructionCount": 2, - "Optimal": "No", + "ExpectedInstructionCount": 1, + "Optimal": "Yes", "Comment": "0x66 0x0f 0xc5", "ExpectedArm64ASM": [ - "umov w20, v16.h[1]", - "uxth x4, w20" + "umov w4, v16.h[1]" ] }, "pextrw eax, xmm0, 010b": { - "ExpectedInstructionCount": 2, - "Optimal": "No", + "ExpectedInstructionCount": 1, + "Optimal": "Yes", "Comment": "0x66 0x0f 0xc5", "ExpectedArm64ASM": [ - "umov w20, v16.h[2]", - "uxth x4, w20" + "umov w4, v16.h[2]" ] }, "pextrw eax, xmm0, 011b": { - "ExpectedInstructionCount": 2, - "Optimal": "No", + "ExpectedInstructionCount": 1, + "Optimal": "Yes", "Comment": "0x66 0x0f 0xc5", "ExpectedArm64ASM": [ - "umov w20, v16.h[3]", - "uxth x4, w20" + "umov w4, v16.h[3]" ] }, "pextrw eax, xmm0, 100b": { - "ExpectedInstructionCount": 2, - "Optimal": "No", + "ExpectedInstructionCount": 1, + "Optimal": "Yes", "Comment": "0x66 0x0f 0xc5", "ExpectedArm64ASM": [ - "umov w20, v16.h[4]", - "uxth x4, w20" + "umov w4, v16.h[4]" ] }, "pextrw eax, xmm0, 101b": { - "ExpectedInstructionCount": 2, - "Optimal": "No", + "ExpectedInstructionCount": 1, + "Optimal": "Yes", "Comment": "0x66 0x0f 0xc5", "ExpectedArm64ASM": [ - "umov w20, v16.h[5]", - "uxth x4, w20" + "umov w4, v16.h[5]" ] }, "pextrw eax, xmm0, 110b": { - "ExpectedInstructionCount": 2, - "Optimal": "No", + "ExpectedInstructionCount": 1, + "Optimal": "Yes", "Comment": "0x66 0x0f 0xc5", "ExpectedArm64ASM": [ - "umov w20, v16.h[6]", - "uxth x4, w20" + "umov w4, v16.h[6]" ] }, "pextrw eax, xmm0, 111b": { - "ExpectedInstructionCount": 2, - "Optimal": "No", + "ExpectedInstructionCount": 1, + "Optimal": "Yes", "Comment": "0x66 0x0f 0xc5", "ExpectedArm64ASM": [ - "umov w20, v16.h[7]", - "uxth x4, w20" + "umov w4, v16.h[7]" + ] + }, + "pextrw [rax], xmm0, 000b": { + "ExpectedInstructionCount": 1, + "Optimal": "Yes", + "Comment": "0x66 0x0f 0xc5", + "ExpectedArm64ASM": [ + "st1 {v16.h}[0], [x4]" + ] + }, + "pextrw [rax], xmm0, 001b": { + "ExpectedInstructionCount": 1, + "Optimal": "Yes", + "Comment": "0x66 0x0f 0xc5", + "ExpectedArm64ASM": [ + "st1 {v16.h}[1], [x4]" + ] + }, + "pextrw [rax], xmm0, 010b": { + "ExpectedInstructionCount": 1, + "Optimal": "Yes", + "Comment": "0x66 0x0f 0xc5", + "ExpectedArm64ASM": [ + "st1 {v16.h}[2], [x4]" + ] + }, + "pextrw [rax], xmm0, 011b": { + "ExpectedInstructionCount": 1, + "Optimal": "Yes", + "Comment": "0x66 0x0f 0xc5", + "ExpectedArm64ASM": [ + "st1 {v16.h}[3], [x4]" + ] + }, + "pextrw [rax], xmm0, 100b": { + "ExpectedInstructionCount": 1, + "Optimal": "Yes", + "Comment": "0x66 0x0f 0xc5", + "ExpectedArm64ASM": [ + "st1 {v16.h}[4], [x4]" + ] + }, + "pextrw [rax], xmm0, 101b": { + "ExpectedInstructionCount": 1, + "Optimal": "Yes", + "Comment": "0x66 0x0f 0xc5", + "ExpectedArm64ASM": [ + "st1 {v16.h}[5], [x4]" + ] + }, + "pextrw [rax], xmm0, 110b": { + "ExpectedInstructionCount": 1, + "Optimal": "Yes", + "Comment": "0x66 0x0f 0xc5", + "ExpectedArm64ASM": [ + "st1 {v16.h}[6], [x4]" + ] + }, + "pextrw [rax], xmm0, 111b": { + "ExpectedInstructionCount": 1, + "Optimal": "Yes", + "Comment": "0x66 0x0f 0xc5", + "ExpectedArm64ASM": [ + "st1 {v16.h}[7], [x4]" ] }, "shufpd xmm0, xmm1, 00b": { diff --git a/unittests/InstructionCountCI/VEX_map1.json b/unittests/InstructionCountCI/VEX_map1.json index a668a252d..c7d047e7d 100644 --- a/unittests/InstructionCountCI/VEX_map1.json +++ b/unittests/InstructionCountCI/VEX_map1.json @@ -3109,39 +3109,69 @@ ] }, "vpextrw eax, xmm0, 000b": { - "ExpectedInstructionCount": 3, + "ExpectedInstructionCount": 2, "Optimal": "No", "Comment": [ "Map 1 0b01 0xC5 128-bit" ], "ExpectedArm64ASM": [ "mov z2.d, p7/m, z16.d", - "umov w20, v2.h[0]", - "uxth x4, w20" + "umov w4, v2.h[0]" ] }, "vpextrw eax, xmm0, 001b": { - "ExpectedInstructionCount": 3, + "ExpectedInstructionCount": 2, "Optimal": "No", "Comment": [ "Map 1 0b01 0xC5 128-bit" ], "ExpectedArm64ASM": [ "mov z2.d, p7/m, z16.d", - "umov w20, v2.h[1]", - "uxth x4, w20" + "umov w4, v2.h[1]" ] }, "vpextrw eax, xmm0, 111b": { - "ExpectedInstructionCount": 3, + "ExpectedInstructionCount": 2, "Optimal": "No", "Comment": [ "Map 1 0b01 0xC5 128-bit" ], "ExpectedArm64ASM": [ "mov z2.d, p7/m, z16.d", - "umov w20, v2.h[7]", - "uxth x4, w20" + "umov w4, v2.h[7]" + ] + }, + "vpextrw [rax], xmm0, 000b": { + "ExpectedInstructionCount": 2, + "Optimal": "No", + "Comment": [ + "Map 1 0b01 0xC5 128-bit" + ], + "ExpectedArm64ASM": [ + "mov z2.d, p7/m, z16.d", + "st1 {v2.h}[0], [x4]" + ] + }, + "vpextrw [rax], xmm0, 001b": { + "ExpectedInstructionCount": 2, + "Optimal": "No", + "Comment": [ + "Map 1 0b01 0xC5 128-bit" + ], + "ExpectedArm64ASM": [ + "mov z2.d, p7/m, z16.d", + "st1 {v2.h}[1], [x4]" + ] + }, + "vpextrw [rax], xmm0, 111b": { + "ExpectedInstructionCount": 2, + "Optimal": "No", + "Comment": [ + "Map 1 0b01 0xC5 128-bit" + ], + "ExpectedArm64ASM": [ + "mov z2.d, p7/m, z16.d", + "st1 {v2.h}[7], [x4]" ] }, "vshufps xmm0, xmm1, xmm2, 00b": { diff --git a/unittests/InstructionCountCI/VEX_map3.json b/unittests/InstructionCountCI/VEX_map3.json index 3bb36d0f2..d466277d9 100644 --- a/unittests/InstructionCountCI/VEX_map3.json +++ b/unittests/InstructionCountCI/VEX_map3.json @@ -2998,51 +2998,47 @@ ] }, "vpextrb rax, xmm0, 0": { - "ExpectedInstructionCount": 3, + "ExpectedInstructionCount": 2, "Optimal": "No", "Comment": [ "Map 3 0b01 0x14 128-bit" ], "ExpectedArm64ASM": [ "mov z2.d, p7/m, z16.d", - "umov w20, v2.b[0]", - "uxtb x4, w20" + "umov w4, v2.b[0]" ] }, "vpextrb rax, xmm0, 15": { - "ExpectedInstructionCount": 3, + "ExpectedInstructionCount": 2, "Optimal": "No", "Comment": [ "Map 3 0b01 0x14 128-bit" ], "ExpectedArm64ASM": [ "mov z2.d, p7/m, z16.d", - "umov w20, v2.b[15]", - "uxtb x4, w20" + "umov w4, v2.b[15]" ] }, "vpextrw rax, xmm0, 0": { - "ExpectedInstructionCount": 3, + "ExpectedInstructionCount": 2, "Optimal": "No", "Comment": [ "Map 3 0b01 0x15 128-bit" ], "ExpectedArm64ASM": [ "mov z2.d, p7/m, z16.d", - "umov w20, v2.h[0]", - "uxth x4, w20" + "umov w4, v2.h[0]" ] }, "vpextrw rax, xmm0, 7": { - "ExpectedInstructionCount": 3, + "ExpectedInstructionCount": 2, "Optimal": "No", "Comment": [ "Map 3 0b01 0x15 128-bit" ], "ExpectedArm64ASM": [ "mov z2.d, p7/m, z16.d", - "umov w20, v2.h[7]", - "uxth x4, w20" + "umov w4, v2.h[7]" ] }, "vpextrd rax, xmm0, 0": { @@ -3067,6 +3063,72 @@ "mov w4, v2.s[3]" ] }, + "vpextrb [rax], xmm0, 0": { + "ExpectedInstructionCount": 2, + "Optimal": "No", + "Comment": [ + "Map 3 0b01 0x14 128-bit" + ], + "ExpectedArm64ASM": [ + "mov z2.d, p7/m, z16.d", + "st1 {v2.b}[0], [x4]" + ] + }, + "vpextrb [rax], xmm0, 15": { + "ExpectedInstructionCount": 2, + "Optimal": "No", + "Comment": [ + "Map 3 0b01 0x14 128-bit" + ], + "ExpectedArm64ASM": [ + "mov z2.d, p7/m, z16.d", + "st1 {v2.b}[15], [x4]" + ] + }, + "vpextrw [rax], xmm0, 0": { + "ExpectedInstructionCount": 2, + "Optimal": "No", + "Comment": [ + "Map 3 0b01 0x15 128-bit" + ], + "ExpectedArm64ASM": [ + "mov z2.d, p7/m, z16.d", + "st1 {v2.h}[0], [x4]" + ] + }, + "vpextrw [rax], xmm0, 7": { + "ExpectedInstructionCount": 2, + "Optimal": "No", + "Comment": [ + "Map 3 0b01 0x15 128-bit" + ], + "ExpectedArm64ASM": [ + "mov z2.d, p7/m, z16.d", + "st1 {v2.h}[7], [x4]" + ] + }, + "vpextrd [rax], xmm0, 0": { + "ExpectedInstructionCount": 2, + "Optimal": "No", + "Comment": [ + "Map 3 0b01 0x16 128-bit" + ], + "ExpectedArm64ASM": [ + "mov z2.d, p7/m, z16.d", + "st1 {v2.s}[0], [x4]" + ] + }, + "vpextrd [rax], xmm0, 3": { + "ExpectedInstructionCount": 2, + "Optimal": "No", + "Comment": [ + "Map 3 0b01 0x16 128-bit" + ], + "ExpectedArm64ASM": [ + "mov z2.d, p7/m, z16.d", + "st1 {v2.s}[3], [x4]" + ] + }, "vextractps eax, xmm0, 0": { "ExpectedInstructionCount": 2, "Optimal": "No",