From b0b3335178c3f99c8e477c6b5930d6dfafce7760 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Sun, 27 Sep 2020 16:53:25 -0700 Subject: [PATCH 1/3] Fixes VADDV in the x86_64 JIT --- External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp b/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp index 50c008d3c..d0bd55e4d 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp +++ b/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp @@ -2723,9 +2723,10 @@ void *JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const auto Src = GetSrc(Op->Header.Args[0].ID()); auto Dest = GetDst(Node); vpxor(xmm15, xmm15, xmm15); + uint8_t Elements = OpSize / Op->Header.ElementSize; switch (Op->Header.ElementSize) { case 2: { - for (int i = 0; i < (Op->Header.Size / 4); ++i) { + for (int i = Elements; i > 1; i >>= 1) { phaddw(Dest, Src); Src = Dest; } @@ -2734,7 +2735,7 @@ void *JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const break; } case 4: { - for (int i = 0; i < (Op->Header.Size / 8); ++i) { + for (int i = Elements; i > 1; i >>= 1) { phaddd(Dest, Src); Src = Dest; } From d404da1bf1c5333b7f18867ce15206714cdabde5 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Sun, 27 Sep 2020 16:53:50 -0700 Subject: [PATCH 2/3] Fixes PSADBW in the opdispatcher Documentation in the x86 manuals implied operating at 8bit --- .../Interface/Core/OpcodeDispatcher.cpp | 57 ++++++++----------- 1 file changed, 25 insertions(+), 32 deletions(-) diff --git a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp index 5d6b18664..45b86d56a 100644 --- a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp +++ b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp @@ -7922,53 +7922,46 @@ void OpDispatchBuilder::FenceOp(OpcodeArgs) { } void OpDispatchBuilder::PSADBW(OpcodeArgs) { + // The documentation is actually incorrect in how this instruction operates + // It strongly implies that the `abs(dest[i] - src[i])` operates in 8bit space + // but it actually operates in more than 8bit space + // This can be seen with `abs(0 - 0xFF)` returning a different result depending + // on bit length auto Size = GetSrcSize(Op); OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags, -1); OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, -1); - OrderedNode *SubResult = _VSub(Size, 1, Dest, Src); - OrderedNode *AbsResult = _VAbs(Size, 1, SubResult); - OrderedNode *Result{}; if (Size == 8) { - // First we need to extract the 8bit values and extend them to 16bits - OrderedNode *Result_Low = _VUXTL(Size, 1, AbsResult); - // Now extract the upper 8bits and extend to 16bits - OrderedNode *Result_High = _VUShrI(Size, 2, AbsResult, 8); + Dest = _VUXTL(Size*2, 1, Dest); + Src = _VUXTL(Size*2, 1, Src); + + OrderedNode *SubResult = _VSub(Size*2, 2, Dest, Src); + OrderedNode *AbsResult = _VAbs(Size*2, 2, SubResult); + // Now vector-wide add the results for each - Result_Low = _VAddV(Size, 2, Result_Low); - Result_High = _VAddV(Size, 2, Result_High); - // Now add the two scalar results back together - // Easy with only 8 byte registers - Result = _VAdd(Size, 2, Result_Low, Result_High); + Result = _VAddV(Size * 2, 2, AbsResult); } else { - // For 16byte registers we need to do a bit more work - // First we need to extract the 8bit values and extend them to 16bits - OrderedNode *Result_Low_Low = _VUXTL(Size, 1, AbsResult); - //// Then we need to extract the upper 8 bits of the lower 64bit result and extend them to 16bits - OrderedNode *Result_Low_High = _VUShrI(Size, 2, AbsResult, 8); + OrderedNode *Dest_Low = _VUXTL(Size, 1, Dest); + OrderedNode *Dest_High = _VUXTL2(Size, 1, Dest); - // Now we need to extract the upper 64bits and do the same thing - OrderedNode *Result_High = _VExtractElement(Size, 8, AbsResult, 1); - OrderedNode *Result_High_Low = _VUXTL(Size, 1, Result_High); - OrderedNode *Result_High_High = _VUShrI(Size, 2, Result_High, 8); + OrderedNode *Src_Low = _VUXTL(Size, 1, Src); + OrderedNode *Src_High = _VUXTL2(Size, 1, Src); + + OrderedNode *SubResult_Low = _VSub(Size, 2, Dest_Low, Src_Low); + OrderedNode *SubResult_High = _VSub(Size, 2, Dest_High, Src_High); + + OrderedNode *AbsResult_Low = _VAbs(Size, 2, SubResult_Low); + OrderedNode *AbsResult_High = _VAbs(Size, 2, SubResult_High); // Now vector pairwise add all four of these - Result_Low_Low = _VAddV(8, 2, Result_Low_Low); - Result_Low_High = _VAddV(8, 2, Result_Low_High); + OrderedNode * Result_Low = _VAddV(Size, 2, AbsResult_Low); + OrderedNode * Result_High = _VAddV(Size, 2, AbsResult_High); - Result_High_Low = _VAddV(8, 2, Result_High_Low); - Result_High_High = _VAddV(8, 2, Result_High_High); - - //// Now add the low and high scalar results together - OrderedNode * Added_Result = _VAdd(8, 2, Result_Low_Low, Result_Low_High); - OrderedNode * Added_Result_High = _VAdd(8, 2, Result_High_Low, Result_High_High); - - // Now generate a new 128bit value for this - Result = _VInsElement(Size, 8, 1, 0, Added_Result, Added_Result_High); + Result = _VInsElement(Size, 8, 1, 0, Result_Low, Result_High); } StoreResult(FPRClass, Op, Result, -1); From b878006f1817897a5b3159c78d98210b8dc1f775 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Sun, 27 Sep 2020 16:54:57 -0700 Subject: [PATCH 3/3] Extends the PSADBW unit tests Weren't quite extensive enough --- unittests/ASM/OpSize/66_F6.asm | 53 +++++++++++++++++++++++++++- unittests/ASM/TwoByte/0F_F6.asm | 58 ++++++++++++++++++++++++++++++- unittests/ASM/TwoByte/0F_F6_2.asm | 23 ++++++++++++ 3 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 unittests/ASM/TwoByte/0F_F6_2.asm diff --git a/unittests/ASM/OpSize/66_F6.asm b/unittests/ASM/OpSize/66_F6.asm index b221f444a..3fe7cccac 100644 --- a/unittests/ASM/OpSize/66_F6.asm +++ b/unittests/ASM/OpSize/66_F6.asm @@ -1,7 +1,15 @@ %ifdef CONFIG { "RegData": { - "XMM0": ["0x100", "0x100"] + "XMM0": ["0x100", "0x100"], + "XMM1": ["0xC5", "0x88"], + "XMM2": ["0x66", "0x5A"], + "XMM3": ["0x6B", "0x68"], + "XMM4": ["0x60", "0x68"], + "XMM5": ["0x65", "0x65"], + "XMM6": ["0x33", "0x57"], + "XMM7": ["0x38", "0x5C"], + "XMM8": ["0x3B", "0x6D"] }, "MemoryRegions": { "0x100000000": "4096" @@ -25,4 +33,47 @@ movaps xmm0, [rdx + 8 * 2] psadbw xmm0, [rdx + 8 * 0] +lea rdx, [rel .data] + +movaps xmm1, [rdx + 16 * 0] +movaps xmm2, [rdx + 16 * 1] +movaps xmm3, [rdx + 16 * 2] +movaps xmm4, [rdx + 16 * 3] +movaps xmm5, [rdx + 16 * 4] +movaps xmm6, [rdx + 16 * 5] +movaps xmm7, [rdx + 16 * 6] +movaps xmm8, [rdx + 16 * 7] + +psadbw xmm1, [rdx + 16 * 8] +psadbw xmm2, [rdx + 16 * 9] +psadbw xmm3, [rdx + 16 * 10] +psadbw xmm4, [rdx + 16 * 11] +psadbw xmm5, [rdx + 16 * 12] +psadbw xmm6, [rdx + 16 * 13] +psadbw xmm7, [rdx + 16 * 14] +psadbw xmm8, [rdx + 16 * 15] + hlt + +; align directive isn't aligning the data to 16bytes +nop +nop +; 256bytes of random data +.data: +db '\xe0\xfc\x2b\xa1\x06\x4f\x6c\xa7\x0f\x06\x6a\x1e\x7f\x76\x80\x9b' +db '\xe0\x56\xed\xaa\xf3\xc3\x68\x68\xde\xe6\xe6\x94\xe2\xe9\xfc\xf0' +db '\x6e\x35\xa8\x54\xd7\xab\x8b\x6c\x77\x5f\x92\xca\x25\xa6\x7e\x27' +db '\xc7\xcd\x73\xec\x95\xd6\x6f\x6a\xbb\xae\xf2\xbb\x27\xb9\xa1\xdd' +db '\x73\x4d\xd1\xc7\xd5\x2c\x31\x88\xfe\xe7\xdb\xfd\x1e\x1e\x09\x7f' +db '\x14\xfa\x4e\x95\xef\xe6\x9a\xf2\xa0\x42\x62\x9a\xa4\xa8\x73\x82' +db '\x0e\x0f\x16\x82\x38\x07\x12\x32\x07\x35\x92\xc1\x63\x07\x78\xb3' +db '\xcb\x46\x19\x57\x2b\x37\x2a\x46\x1f\x04\x0e\x79\x3d\xcd\x8d\xa3' +db '\x2b\xf3\x86\x2f\xab\xba\x57\x30\x2e\xd6\x2c\xf0\x46\x4f\x3f\xef' +db '\xef\xd1\xbb\x85\x34\x4b\x3c\xde\x9e\x48\xa3\xb9\x8d\x71\xe3\x9d' +db '\x09\x72\xfb\xde\x8a\x32\x50\x9d\x69\x98\xf1\xf6\x52\xeb\xf7\xee' +db '\xd6\x99\xc2\xff\x30\x1c\x02\xce\x70\x05\xb2\xf1\x56\x9c\x0e\xa6' +db '\x18\x62\xc4\xe2\x86\x38\x76\x30\x2f\xa1\xe4\xa7\x0e\x5d\x53\xeb' +db '\x14\x45\xe0\xb7\xe1\xe8\x02\x68\x1a\xfe\x8e\xc1\x8f\xf2\xeb\x46' +db '\x7f\x5d\x6a\x23\x46\x97\x2e\x03\x98\x12\x32\x8f\x54\x76\x59\xac' +db '\xc8\x76\x5f\xc8\x71\x0c\xd3\xb6\xc5\x19\xea\xab\xa6\x2c\x1d\x88' + diff --git a/unittests/ASM/TwoByte/0F_F6.asm b/unittests/ASM/TwoByte/0F_F6.asm index 8b6d304c5..50612ad12 100644 --- a/unittests/ASM/TwoByte/0F_F6.asm +++ b/unittests/ASM/TwoByte/0F_F6.asm @@ -1,7 +1,14 @@ %ifdef CONFIG { "RegData": { - "MM0": "0x80" + "MM0": "0x0000000000000080", + "MM1": "0x0000000000000083", + "MM2": "0x0000000000000134", + "MM3": "0x0000000000000156", + "MM4": "0x0000000000000140", + "MM5": "0x000000000000013F", + "MM6": "0x000000000000008F", + "MM7": "0x00000000000000D1" }, "MemoryRegions": { "0x100000000": "4096" @@ -15,9 +22,58 @@ mov rax, 0x4142434445464748 mov [rdx + 8 * 0], rax mov rax, 0x5152535455565758 mov [rdx + 8 * 1], rax +mov rax, 0x912277A763B4EB8C +mov [rdx + 8 * 2], rax +mov rax, 0x589490D442F54AFD +mov [rdx + 8 * 3], rax +mov rax, 0xB5E43417A3F6706C +mov [rdx + 8 * 4], rax +mov rax, 0xB4F4B827515F5BFA +mov [rdx + 8 * 5], rax +mov rax, 0x52D0EF1BCB906B6A +mov [rdx + 8 * 6], rax +mov rax, 0x1D0FDF5D05D39C64 +mov [rdx + 8 * 7], rax +mov rax, 0xAEFEDEA21EF08810 +mov [rdx + 8 * 8], rax +mov rax, 0xF7D80319B125BDE5 movq mm0, [rdx + 8 * 1] +movq mm1, [rdx + 8 * 2] +movq mm2, [rdx + 8 * 3] +movq mm3, [rdx + 8 * 4] +movq mm4, [rdx + 8 * 5] +movq mm5, [rdx + 8 * 6] +movq mm6, [rdx + 8 * 7] +movq mm7, [rdx + 8 * 8] psadbw mm0, [rdx + 8 * 0] +lea rdx, [rel .data] +movq mm1, [rdx + 8 * 0] +movq mm2, [rdx + 8 * 1] +movq mm3, [rdx + 8 * 2] +movq mm4, [rdx + 8 * 3] +movq mm5, [rdx + 8 * 4] +movq mm6, [rdx + 8 * 5] +movq mm7, [rdx + 8 * 6] + +psadbw mm1, [rdx + 8 * 7] +psadbw mm2, [rdx + 8 * 8] +psadbw mm3, [rdx + 8 * 9] +psadbw mm4, [rdx + 8 * 10] +psadbw mm5, [rdx + 8 * 11] +psadbw mm6, [rdx + 8 * 12] +psadbw mm7, [rdx + 8 * 13] hlt + +.data: +; 128bytes of random numbers +db 'ba\xa7\x5e\xc8\x0f\x90\x25\xf1\xf8\x49\xbd\xab\x4d\x2b\xa1\xc4' +db 'e4\x69\xe3\x2a\x80\x8d\xd6\x0b\xb2\x6d\xea\xae\x2e\x23\xc2\x2c' +db 'f9\xc6\xee\x06\x53\x96\x00\xae\x8d\x06\xdc\xe1\x11\x06\x0c\x40' +db 'a5\x61\x83\x7c\x13\x25\x43\xea\xa7\x08\x52\xc4\x0f\x91\x2c\x2c' +db '5a\xe7\xcf\xf6\xe3\x6b\x9e\x9e\xd8\x85\xf7\xfd\x4a\x17\xb4\xc9' +db '16\x07\x13\x8c\x83\x89\xc3\x5e\x46\x63\x1a\x31\xb9\x2c\x72\x18' +db '23\xa2\xf0\x4d\x22\x2a\xe4\x86\x84\x1a\xae\xfc\x65\x49\x17\x8e' +db 'c8\xb0\xe3\x6c\xb3\xce\xa1\x2f\xce\x5f\xae\x06\xac\x28\x7d\xb5' diff --git a/unittests/ASM/TwoByte/0F_F6_2.asm b/unittests/ASM/TwoByte/0F_F6_2.asm new file mode 100644 index 000000000..a50d1648e --- /dev/null +++ b/unittests/ASM/TwoByte/0F_F6_2.asm @@ -0,0 +1,23 @@ +%ifdef CONFIG +{ + "RegData": { + "MM0": "0x00000000000007F8" + }, + "MemoryRegions": { + "0x100000000": "4096" + } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x0 +mov [rdx + 8 * 0], rax +mov rax, -1 +mov [rdx + 8 * 1], rax + +movq mm0, [rdx + 8 * 0] + +psadbw mm0, [rdx + 8 * 1] + +hlt