diff --git a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp index e3e835b74..03f084f85 100644 --- a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp +++ b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp @@ -5978,6 +5978,8 @@ void OpDispatchBuilder::InstallHostSpecificOpcodeHandlers() { {OPD(3, 0b01, 0x4B), 1, &OpDispatchBuilder::AVXVectorVariableBlend<8>}, {OPD(3, 0b01, 0x4C), 1, &OpDispatchBuilder::AVXVectorVariableBlend<1>}, + {OPD(3, 0b01, 0x61), 1, &OpDispatchBuilder::VPCMPESTRIOp}, + {OPD(3, 0b01, 0xDF), 1, &OpDispatchBuilder::VAESKeyGenAssistOp}, }; #undef OPD @@ -7266,6 +7268,8 @@ constexpr uint16_t PF_F2 = 3; {OPD(0, PF_3A_66, 0x41), 1, &OpDispatchBuilder::DPPOp<8>}, {OPD(0, PF_3A_66, 0x42), 1, &OpDispatchBuilder::MPSADBWOp}, + {OPD(0, PF_3A_66, 0x61), 1, &OpDispatchBuilder::VPCMPESTRIOp}, + {OPD(0, PF_3A_NONE, 0xCC), 1, &OpDispatchBuilder::SHA1RNDS4Op}, }; #undef PF_3A_NONE diff --git a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h index af2fcc241..eea102dc2 100644 --- a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h +++ b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h @@ -487,6 +487,8 @@ public: void VPALIGNROp(OpcodeArgs); + void VPCMPESTRIOp(OpcodeArgs); + void VPERM2Op(OpcodeArgs); void VPERMDOp(OpcodeArgs); void VPERMQOp(OpcodeArgs); @@ -853,6 +855,11 @@ private: const X86Tables::DecodedOperand& Src2, const X86Tables::DecodedOperand& Imm); + OrderedNode* PCMPESTRXOpImpl(OpcodeArgs, + const X86Tables::DecodedOperand& Src1, + const X86Tables::DecodedOperand& Src2, + const X86Tables::DecodedOperand& Imm); + OrderedNode* PHADDSOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1, const X86Tables::DecodedOperand& Src2); diff --git a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp index 723e4f5c3..27b05baf9 100644 --- a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp +++ b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp @@ -4552,4 +4552,77 @@ void OpDispatchBuilder::VPERMILRegOp<4>(OpcodeArgs); template void OpDispatchBuilder::VPERMILRegOp<8>(OpcodeArgs); +OrderedNode* OpDispatchBuilder::PCMPESTRXOpImpl(OpcodeArgs, + const X86Tables::DecodedOperand& Src1Op, + const X86Tables::DecodedOperand& Src2Op, + const X86Tables::DecodedOperand& Imm) { + LOGMAN_THROW_A_FMT(Imm.IsLiteral(), "Imm needs to be a literal"); + const auto Control = Imm.Data.Literal.Value; + + // Will be 4 in the absence of a REX.W bit and 8 in the presence of a REX.W bit. + const auto SrcSize = GetSrcSize(Op); + + // SSE4.2 string instructions modify flags, so invalidate + // any previously deferred flags. + InvalidateDeferredFlags(); + + // NOTE: Unlike most other SSE/AVX instructions, the SSE4.2 string and text + // instructions do *not* require memory operands to be aligned on a 16 byte + // boundary (see "Other Exceptions" descriptions for the relevant + // instructions in the Intel Software Development Manual). + // + // So, we specify Src2 as having an alignment of 1 to indicate this. + OrderedNode *Src1 = LoadSource_WithOpSize(FPRClass, Op, Src1Op, 16, Op->Flags, -1); + OrderedNode *Src2 = LoadSource_WithOpSize(FPRClass, Op, Src2Op, 16, Op->Flags, 1); + + OrderedNode *SrcRAX = LoadGPRRegister(X86State::REG_RAX); + OrderedNode *SrcRDX = LoadGPRRegister(X86State::REG_RDX); + + OrderedNode *IntermediateResult = _VPCMPESTRX(SrcSize, Src1, Src2, SrcRAX, SrcRDX, Control); + OrderedNode *ResultNoFlags = _And(IntermediateResult, _Constant(0xFFFF)); + + // For the indexed variant of the instructions, if control[6] is set, then we + // store the index of the most significant bit into ECX. If it's not set, + // then we store the least significant bit. + OrderedNode *ZeroConst = _Constant(0); + + const auto ECXResult = [&]() -> OrderedNode* { + const auto UseMSBIndex = (Control & 0b0100'0000) != 0; + + OrderedNode *IfZero = _Constant(16 >> (Control & 1)); + OrderedNode *IfNotZero = UseMSBIndex ? _FindMSB(ResultNoFlags) + : _FindLSB(ResultNoFlags); + + return _Select(IR::COND_EQ, ResultNoFlags, ZeroConst, + IfZero, IfNotZero); + }(); + + // Set all of the necessary flags. + // We use the top 16-bits of the result to store the flags + // in the form: + // + // Bit: 19 18 17 16 + // [OF | CF | SF | ZF] + // + const auto GetFlagBit = [this, IntermediateResult](int BitIndex) { + return _Bfe(1, BitIndex, IntermediateResult); + }; + + SetRFLAG(GetFlagBit(16)); + SetRFLAG(GetFlagBit(17)); + SetRFLAG(GetFlagBit(18)); + SetRFLAG(GetFlagBit(19)); + + SetRFLAG(ZeroConst); + SetRFLAG(ZeroConst); + + // ... and we're done! + return ECXResult; +} + +void OpDispatchBuilder::VPCMPESTRIOp(OpcodeArgs) { + OrderedNode *Result = PCMPESTRXOpImpl(Op, Op->Dest, Op->Src[0], Op->Src[1]); + StoreGPRRegister(X86State::REG_RCX, Result, 4); +} + } diff --git a/External/FEXCore/Source/Interface/Core/X86Tables/H0F3ATables.cpp b/External/FEXCore/Source/Interface/Core/X86Tables/H0F3ATables.cpp index 98f29d3de..7575f9167 100644 --- a/External/FEXCore/Source/Interface/Core/X86Tables/H0F3ATables.cpp +++ b/External/FEXCore/Source/Interface/Core/X86Tables/H0F3ATables.cpp @@ -45,9 +45,9 @@ void InitializeH0F3ATables(Context::OperatingMode Mode) { {OPD(0, PF_3A_66, 0x44), 1, X86InstInfo{"PCLMULQDQ", TYPE_INST, GenFlagsSameSize(SIZE_128BIT) | FLAGS_MODRM | FLAGS_XMM_FLAGS, 1, nullptr}}, {OPD(0, PF_3A_66, 0x60), 1, X86InstInfo{"PCMPESTRM", TYPE_UNDEC, FLAGS_NONE, 0, nullptr}}, - {OPD(0, PF_3A_66, 0x61), 1, X86InstInfo{"PCMPESTRI", TYPE_UNDEC, FLAGS_NONE, 0, nullptr}}, + {OPD(0, PF_3A_66, 0x61), 1, X86InstInfo{"PCMPESTRI", TYPE_INST, GenFlagsSizes(SIZE_128BIT, SIZE_32BIT) | FLAGS_MODRM | FLAGS_XMM_FLAGS, 1, nullptr}}, {OPD(0, PF_3A_66, 0x62), 1, X86InstInfo{"PCMPISTRM", TYPE_UNDEC, FLAGS_NONE, 0, nullptr}}, - {OPD(0, PF_3A_66, 0x63), 1, X86InstInfo{"PCMPISTRI", TYPE_INST, GenFlagsSameSize(SIZE_128BIT) | FLAGS_MODRM | FLAGS_XMM_FLAGS, 1, nullptr}}, + {OPD(0, PF_3A_66, 0x63), 1, X86InstInfo{"PCMPISTRI", TYPE_UNDEC, FLAGS_NONE, 0, nullptr}}, {OPD(0, PF_3A_NONE, 0xCC), 1, X86InstInfo{"SHA1RNDS4", TYPE_INST, GenFlagsSameSize(SIZE_128BIT) | FLAGS_MODRM | FLAGS_XMM_FLAGS, 1, nullptr}}, diff --git a/External/FEXCore/Source/Interface/Core/X86Tables/VEXTables.cpp b/External/FEXCore/Source/Interface/Core/X86Tables/VEXTables.cpp index 8c3aa3e93..874757ea8 100644 --- a/External/FEXCore/Source/Interface/Core/X86Tables/VEXTables.cpp +++ b/External/FEXCore/Source/Interface/Core/X86Tables/VEXTables.cpp @@ -453,9 +453,9 @@ void InitializeVEXTables() { {OPD(3, 0b01, 0x5F), 1, X86InstInfo{"VFMSUBADDPD", TYPE_UNDEC, FLAGS_NONE, 0, nullptr}}, {OPD(3, 0b01, 0x60), 1, X86InstInfo{"VPCMPESTRM", TYPE_UNDEC, FLAGS_NONE, 0, nullptr}}, - {OPD(3, 0b01, 0x61), 1, X86InstInfo{"VPCMPESTRI", TYPE_UNDEC, FLAGS_NONE, 0, nullptr}}, + {OPD(3, 0b01, 0x61), 1, X86InstInfo{"VPCMPESTRI", TYPE_INST, GenFlagsSizes(SIZE_128BIT, SIZE_32BIT) | FLAGS_MODRM | FLAGS_XMM_FLAGS, 1, nullptr}}, {OPD(3, 0b01, 0x62), 1, X86InstInfo{"VPCMPISTRM", TYPE_UNDEC, FLAGS_NONE, 0, nullptr}}, - {OPD(3, 0b01, 0x63), 1, X86InstInfo{"VPCMPISTRI", TYPE_INST, FLAGS_MODRM | FLAGS_XMM_FLAGS, 1, nullptr}}, + {OPD(3, 0b01, 0x63), 1, X86InstInfo{"VPCMPISTRI", TYPE_UNDEC, FLAGS_NONE, 0, nullptr}}, {OPD(3, 0b01, 0x68), 1, X86InstInfo{"VFMADDPS", TYPE_UNDEC, FLAGS_NONE, 0, nullptr}}, {OPD(3, 0b01, 0x69), 1, X86InstInfo{"VFMADDPD", TYPE_UNDEC, FLAGS_NONE, 0, nullptr}}, diff --git a/unittests/ASM/H0F3A/pcmpestri_equal_any.asm b/unittests/ASM/H0F3A/pcmpestri_equal_any.asm new file mode 100644 index 000000000..fc4862898 --- /dev/null +++ b/unittests/ASM/H0F3A/pcmpestri_equal_any.asm @@ -0,0 +1,153 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["15"], + "RDX": ["16"], + "XMM0": ["0x04070F000F000E05", "0x0000000000040404"], + "XMM1": ["0x0121313131311111", "0x0000000000010101"], + "XMM2": ["0x306F8A9E672C65E5", "0x000030443057697D"], + "XMM3": ["0x306F8A9E672C65E5", "0x00003044305796E3"] + } +} +%endif + +; Adjusts the result from LAHF and SETO so that we have a set of flags organized +; like [OF, SF, ZF, AF, PF, CF] for storing into the .flags region +; of memory. +; +; The first parameter is the byte offset to store the flag result +; at in the .flags region of memory. +; +%macro ArrangeAndStoreFLAGS 1 + lahf + seto bl + movzx bx, bl + + shr ax, 8 + shl bx, 5 + + mov di, ax + mov si, ax + + ; Mask and shift + and di, 0b0000_0000_0000_0100 ; PF + and si, 0b0000_0000_0001_0000 ; AF + shr di, 1 + shr si, 2 + + ; OR all of them together + or bx, di + or bx, si + + ; Reclaim DI for getting ZF/SF and shift into place + mov di, ax + and di, 0b0000_0000_1100_0000 ; ZF and SF + shr di, 3 + + ; Finally mask and OR all of the bits together + and ax, 0b0000_0000_0000_0001 ; CF + or bx, ax + or bx, di + + ; Store result to .flags memory + mov [rel .flags + %1], bl +%endmacro + +; Performs the string comparison and moves the result from RCX to +; a region of memory in the .indices section specified by a byte +; offset. +; +; The first parameter is the byte offset to store the RCX result to. +; The second parameter is the control values to pass to pcmpestri +; +%macro CompareAndStore 2 + pcmpestri xmm2, xmm3, %2 + mov [rel .indices + %1], cl + + mov r15, rax + ArrangeAndStoreFLAGS %1 + mov rax, r15 +%endmacro + +movaps xmm2, [rel .data] +movaps xmm3, [rel .data + 32] + +; Unsigned byte character check (lsb, positive polarity) +mov rax, 15 ; Exclude 'l' +mov rdx, 16 +CompareAndStore 0, 0b00000000 + +; Unsigned byte character check (msb, positive polarity) +CompareAndStore 1, 0b01000000 + +; Unsigned byte character check (lsb, negative polarity) +CompareAndStore 2, 0b00010000 + +; Unsigned byte character check (msb, negative polarity) +CompareAndStore 3, 0b01010000 + +; Unsigned byte character check (lsb, negative masked) +CompareAndStore 4, 0b00110000 + +; Unsigned byte character check (msb, negative masked) +CompareAndStore 5, 0b01110000 + +; --- 16-bit unsigned word tests --- +movaps xmm2, [rel .data16] +movaps xmm3, [rel .data16 + 32] + +; Unsigned word character check (msb, positive polarity) +CompareAndStore 6, 0b01000001 + +; Unsigned word character check (lsb, negative polarity) +CompareAndStore 7, 0b00010001 + +; Unsigned word character check (msb, negative polarity) +CompareAndStore 8, 0b01010001 + +; Unsigned word character check (lsb, negative masked) +CompareAndStore 9, 0b00110001 + +; Unsigned word character check (msb, negative masked) +CompareAndStore 10, 0b01110001 + +; Load all our stored indices and flags for result comparing +movaps xmm0, [rel .indices] +movaps xmm1, [rel .flags] + +hlt + +align 32 +.data: +dq 0x6463626144434241 ; "ABCDabcd" +dq 0x6C6B6A694C4B4A49 ; "IJKLijkl" +dq 0xFFFFFFFFFFFFFFFF +dq 0xEEEEEEEEEEEEEEEE + +dq 0x4120492065726548 ; "Here I A" +dq 0x6C4C612759202C6D ; "m, Y'aLl" +dq 0xDDDDDDDDDDDDDDDD +dq 0xCCCCCCCCCCCCCCCC + +.data16: +dq 0x306F8A9E672C65E5 ; "日本語は" +dq 0x000030443057697D ; "楽しい\0" (Japanese is fun) +dq 0xAAAAAAAAAAAAAAAA +dq 0xBBBBBBBBBBBBBBBB + +dq 0x306F8A9E672C65E5 ; "日本語は" +dq 0x00003044305796E3 ; "難しい\0" (Japanese is hard) +dq 0x8888888888888888 +dq 0x9999999999999999 + +.indices: +dq 0x0000000000000000 +dq 0x0000000000000000 +dq 0x0000000000000000 +dq 0x0000000000000000 + +.flags: +dq 0x0000000000000000 +dq 0x0000000000000000 +dq 0x0000000000000000 +dq 0x0000000000000000 diff --git a/unittests/ASM/H0F3A/pcmpestri_equal_each.asm b/unittests/ASM/H0F3A/pcmpestri_equal_each.asm new file mode 100644 index 000000000..e34efd842 --- /dev/null +++ b/unittests/ASM/H0F3A/pcmpestri_equal_each.asm @@ -0,0 +1,203 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["4"], + "RDX": ["3"], + "XMM0": ["0x0F000B060B060F00", "0x040407000F060706"], + "XMM1": ["0x3939010101012121", "0x0101212119191919"], + "XMM2": ["0x306F8A9E672C65E5", "0x000030443057697D"], + "XMM3": ["0x306F8A9E672C65E5", "0x00003044305796E3"], + "XMM4": ["0x0704030307000404", "0x0000000000000000"], + "XMM5": ["0x1919191939390101", "0x0000000000000000"] + } +} +%endif + +; Adjusts the result from LAHF and SETO so that we have a set of flags organized +; like [OF, SF, ZF, AF, PF, CF] for storing into the .flags region +; of memory. +; +; The first parameter is the byte offset to store the flag result +; at in the .flags region of memory. +; +%macro ArrangeAndStoreFLAGS 1 + lahf + seto bl + movzx bx, bl + + shr ax, 8 + shl bx, 5 + + mov di, ax + mov si, ax + + ; Mask and shift + and di, 0b0000_0000_0000_0100 ; PF + and si, 0b0000_0000_0001_0000 ; AF + shr di, 1 + shr si, 2 + + ; OR all of them together + or bx, di + or bx, si + + ; Reclaim DI for getting ZF/SF and shift into place + mov di, ax + and di, 0b0000_0000_1100_0000 ; ZF and SF + shr di, 3 + + ; Finally mask and OR all of the bits together + and ax, 0b0000_0000_0000_0001 ; CF + or bx, ax + or bx, di + + ; Store result to .flags memory + mov [rel .flags + %1], bl +%endmacro + +; Performs the string comparison and moves the result from RCX to +; a region of memory in the .indices section specified by a byte +; offset. +; +; The first parameter is the byte offset to store the RCX result to. +; The second parameter is the control values to pass to pcmpestri +; +%macro CompareAndStore 2 + pcmpestri xmm2, xmm3, %2 + mov [rel .indices + %1], cl + + mov r15, rax + ArrangeAndStoreFLAGS %1 + mov rax, r15 +%endmacro + +movaps xmm2, [rel .data] +movaps xmm3, [rel .data + 32] + +; Full length unsigned byte string check (lsb, positive polarity) +mov rax, 16 +mov rdx, 16 +CompareAndStore 0, 0b00001000 + +; Full length unsigned byte string check (msb, positive polarity) +CompareAndStore 1, 0b01001000 + +; Full length unsigned byte string check (lsb, negative polarity) +CompareAndStore 2, 0b00011000 + +; Full length unsigned byte string check (msb, negative polarity) +CompareAndStore 3, 0b01011000 + +; Full length unsigned byte string check (lsb, negative masked) +CompareAndStore 4, 0b00111000 + +; Full length unsigned byte string check (msb, negative masked) +CompareAndStore 5, 0b01111000 + +; Non-full length unsigned byte string check (lsb, positive polarity) +mov rax, 8 +mov rdx, 7 +CompareAndStore 6, 0b00001000 + +; Non-full length unsigned byte string check (msb, positive polarity) +CompareAndStore 7, 0b01001000 + +; Non-full length unsigned byte string check (lsb, negative polarity) +CompareAndStore 8, 0b00011000 + +; Non-full length unsigned byte string check (msb, negative polarity) +CompareAndStore 9, 0b01011000 + +; Non-full length unsigned byte string check (lsb, negative masked) +CompareAndStore 10, 0b00111000 + +; Non-full length unsigned byte string check (msb, negative masked) +CompareAndStore 11, 0b01111000 + +; --- 16-bit unsigned word tests --- + +movaps xmm2, [rel .data16] +movaps xmm3, [rel .data16 + 32] + +; Full length unsigned word string check (lsb, positive polarity) +mov rax, 8 +mov rdx, 8 +CompareAndStore 12, 0b00001001 + +; Full length unsigned word string check (msb, positive polarity) +CompareAndStore 13, 0b01001001 + +; Full length unsigned word string check (lsb, negative polarity) +CompareAndStore 14, 0b00011001 + +; Full length unsigned word string check (msb, negative polarity) +CompareAndStore 15, 0b01011001 + +; Full length unsigned word string check (lsb, negative masked) +CompareAndStore 16, 0b00111001 + +; Full length unsigned word string check (msb, negative masked) +CompareAndStore 17, 0b01111001 + +; Non-full length unsigned word string check (lsb, positive polarity) +mov rax, 4 +mov rdx, 3 +CompareAndStore 18, 0b00001001 + +; Non-full length unsigned word string check (msb, positive polarity) +CompareAndStore 19, 0b01001001 + +; Non-full length unsigned word string check (lsb, negative polarity) +CompareAndStore 20, 0b00011001 + +; Non-full length unsigned word string check (msb, negative polarity) +CompareAndStore 21, 0b01011001 + +; Non-full length unsigned word string check (lsb, negative masked) +CompareAndStore 22, 0b00111001 + +; Non-full length unsigned word string check (msb, negative masked) +CompareAndStore 23, 0b01111001 + +; Load all our stored indices and flags for result comparing +movaps xmm0, [rel .indices] +movaps xmm4, [rel .indices + 16] +movaps xmm1, [rel .flags] +movaps xmm5, [rel .flags + 16] + +hlt + +align 32 +.data: +dq 0x6550206F6C6C6548 ; "Hello Pe" +dq 0x21212121656C706F ; "ople!!!!" +dq 0xFFFFFFFFFFFFFFFF +dq 0xEEEEEEEEEEEEEEEE + +dq 0x2759206F6C6C6548 ; "Hello Y'" +dq 0x21212121216C6C61 ; "all!!!!!" +dq 0xDDDDDDDDDDDDDDDD +dq 0xCCCCCCCCCCCCCCCC + +.data16: +dq 0x306F8A9E672C65E5 ; "日本語は" +dq 0x000030443057697D ; "楽しい\0" (Japanese is fun) +dq 0xAAAAAAAAAAAAAAAA +dq 0xBBBBBBBBBBBBBBBB + +dq 0x306F8A9E672C65E5 ; "日本語は" +dq 0x00003044305796E3 ; "難しい\0" (Japanese is hard) +dq 0x8888888888888888 +dq 0x9999999999999999 + +.indices: +dq 0x0000000000000000 +dq 0x0000000000000000 +dq 0x0000000000000000 +dq 0x0000000000000000 + +.flags: +dq 0x0000000000000000 +dq 0x0000000000000000 +dq 0x0000000000000000 +dq 0x0000000000000000 diff --git a/unittests/ASM/H0F3A/pcmpestri_equal_ordered.asm b/unittests/ASM/H0F3A/pcmpestri_equal_ordered.asm new file mode 100644 index 000000000..5f045c415 --- /dev/null +++ b/unittests/ASM/H0F3A/pcmpestri_equal_ordered.asm @@ -0,0 +1,156 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["2"], + "RDX": ["16"], + "XMM0": ["0x05050F000F000902", "0x0000000007000700"], + "XMM1": ["0x1111313131311111", "0x0000000031313131"], + "XMM2": ["0x306F8A9E30443057", "0x000030443057697D"], + "XMM3": ["0x306F8A9E672C65E5", "0x00003044305796E3"] + } +} +%endif + +; Adjusts the result from LAHF and SETO so that we have a set of flags organized +; like [OF, SF, ZF, AF, PF, CF] for storing into the .flags region +; of memory. +; +; The first parameter is the byte offset to store the flag result +; at in the .flags region of memory. +; +%macro ArrangeAndStoreFLAGS 1 + lahf + seto bl + movzx bx, bl + + shr ax, 8 + shl bx, 5 + + mov di, ax + mov si, ax + + ; Mask and shift + and di, 0b0000_0000_0000_0100 ; PF + and si, 0b0000_0000_0001_0000 ; AF + shr di, 1 + shr si, 2 + + ; OR all of them together + or bx, di + or bx, si + + ; Reclaim DI for getting ZF/SF and shift into place + mov di, ax + and di, 0b0000_0000_1100_0000 ; ZF and SF + shr di, 3 + + ; Finally mask and OR all of the bits together + and ax, 0b0000_0000_0000_0001 ; CF + or bx, ax + or bx, di + + ; Store result to .flags memory + mov [rel .flags + %1], bl +%endmacro + +; Performs the string comparison and moves the result from RCX to +; a region of memory in the .indices section specified by a byte +; offset. +; +; The first parameter is the byte offset to store the RCX result to. +; The second parameter is the control values to pass to pcmpestri +; +%macro CompareAndStore 2 + pcmpestri xmm2, xmm3, %2 + mov [rel .indices + %1], cl + + mov r15, rax + ArrangeAndStoreFLAGS %1 + mov rax, r15 +%endmacro + +movaps xmm2, [rel .data] +movaps xmm3, [rel .data + 32] + +; Unsigned byte string check (lsb, positive polarity) +mov rax, 2 +mov rdx, 16 +CompareAndStore 0, 0b00001100 + +; Unsigned byte string check (msb, positive polarity) +CompareAndStore 1, 0b01001100 + +; Unsigned byte string check (lsb, negative polarity) +CompareAndStore 2, 0b00011100 + +; Unsigned byte string check (msb, negative polarity) +CompareAndStore 3, 0b01011100 + +; Unsigned byte string check (lsb, negative masked) +CompareAndStore 4, 0b00111100 + +; Unsigned byte string check (msb, negative masked) +CompareAndStore 5, 0b01111100 + +; --- 16-bit unsigned word tests --- +; Intentionally don't reset RDX to 8 here to test upper bounds clamping. +movaps xmm2, [rel .data16] +movaps xmm3, [rel .data16 + 32] + +CompareAndStore 6, 0b00001101 + +; Unsigned word string check (msb, positive polarity) +CompareAndStore 7, 0b01001101 + +; Unsigned word string check (lsb, negative polarity) +CompareAndStore 8, 0b00011101 + +; Unsigned word string check (msb, negative polarity) +CompareAndStore 9, 0b01011101 + +; Unsigned word string check (lsb, negative masked) +CompareAndStore 10, 0b00111101 + +; Unsigned word string check (msb, negative masked) +CompareAndStore 11, 0b01111101 + +; Load all our stored indices and flags for result comparing +movaps xmm0, [rel .indices] +movaps xmm1, [rel .flags] + +hlt + +align 32 +.data: +dq 0x6550206F6FFF6C6C ; "ll" with junk following it +dq 0x21212121656C706F +dq 0xFFFFFFFFFFFFFFFF +dq 0xEEEEEEEEEEEEEEEE + +dq 0x2759206F6C6C6548 ; "Hello Y'" +dq 0x21212121216C6C61 ; "all!!!!!" +dq 0xDDDDDDDDDDDDDDDD +dq 0xCCCCCCCCCCCCCCCC + +.data16: +dq 0x306F8A9E30443057 ; "しい" followed by junk +dq 0x000030443057697D +dq 0xAAAAAAAAAAAAAAAA +dq 0xBBBBBBBBBBBBBBBB + +dq 0x306F8A9E672C65E5 ; "日本語は" +dq 0x00003044305796E3 ; "難しい\0" (Japanese is hard) +dq 0x8888888888888888 +dq 0x9999999999999999 + +.indices: +dq 0x0000000000000000 +dq 0x0000000000000000 +dq 0x0000000000000000 +dq 0x0000000000000000 + +.flags: +dq 0x0000000000000000 +dq 0x0000000000000000 +dq 0x0000000000000000 +dq 0x0000000000000000 diff --git a/unittests/ASM/H0F3A/pcmpestri_ranges.asm b/unittests/ASM/H0F3A/pcmpestri_ranges.asm new file mode 100644 index 000000000..50220e0ce --- /dev/null +++ b/unittests/ASM/H0F3A/pcmpestri_ranges.asm @@ -0,0 +1,154 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["4"], + "RDX": ["16"], + "XMM0": ["0x00060F000F000D01", "0x0000000000070007"], + "XMM1": ["0x3111313131311111", "0x0000000000313131"], + "XMM2": ["0x005A0041007A0061", "0x55AACCBBFF223344"], + "XMM3": ["0x006500200027003F", "0x00210065004F0065"] + } +} +%endif + +; Adjusts the result from LAHF and SETO so that we have a set of flags organized +; like [OF, SF, ZF, AF, PF, CF] for storing into the .flags region +; of memory. +; +; The first parameter is the byte offset to store the flag result +; at in the .flags region of memory. +; +%macro ArrangeAndStoreFLAGS 1 + lahf + seto bl + movzx bx, bl + + shr ax, 8 + shl bx, 5 + + mov di, ax + mov si, ax + + ; Mask and shift + and di, 0b0000_0000_0000_0100 ; PF + and si, 0b0000_0000_0001_0000 ; AF + shr di, 1 + shr si, 2 + + ; OR all of them together + or bx, di + or bx, si + + ; Reclaim DI for getting ZF/SF and shift into place + mov di, ax + and di, 0b0000_0000_1100_0000 ; ZF and SF + shr di, 3 + + ; Finally mask and OR all of the bits together + and ax, 0b0000_0000_0000_0001 ; CF + or bx, ax + or bx, di + + ; Store result to .flags memory + mov [rel .flags + %1], bl +%endmacro + +; Performs the string comparison and moves the result from RCX to +; a region of memory in the .indices section specified by a byte +; offset. +; +; The first parameter is the byte offset to store the RCX result to. +; The second parameter is the control values to pass to pcmpestri +; +%macro CompareAndStore 2 + pcmpestri xmm2, xmm3, %2 + mov [rel .indices + %1], cl + + mov r15, rax + ArrangeAndStoreFLAGS %1 + mov rax, r15 +%endmacro + +movaps xmm2, [rel .data] +movaps xmm3, [rel .data + 32] + +; Range unsigned byte check (lsb, positive polarity) +mov rax, 4 +mov rdx, 16 +CompareAndStore 0, 0b00000100 + +; Range unsigned byte check (msb, positive polarity) +CompareAndStore 1, 0b01000100 + +; Range unsigned byte check (lsb, negative polarity) +CompareAndStore 2, 0b00010100 + +; Range unsigned byte check (msb, negative polarity) +CompareAndStore 3, 0b01010100 + +; Range unsigned byte check (lsb, negative masked) +CompareAndStore 4, 0b00110100 + +; Range unsigned byte check (msb, negative masked) +CompareAndStore 5, 0b01110100 + +; --- 16-bit unsigned word tests --- +; Intentionally don't reset RDX to 8 here to test upper bounds clamping. +movaps xmm2, [rel .data16] +movaps xmm3, [rel .data16 + 32] + +; Range unsigned word check (msb, positive polarity) +CompareAndStore 6, 0b01000101 + +; Range unsigned word check (lsb, negative polarity) +CompareAndStore 7, 0b00010101 + +; Range unsigned word check (msb, negative polarity) +CompareAndStore 8, 0b01010101 + +; Range unsigned word check (lsb, negative masked) +CompareAndStore 9, 0b00110101 + +; Range unsigned word check (msb, negative masked) +CompareAndStore 10, 0b01110101 + +; Load all our stored indices and flags for result comparing +movaps xmm0, [rel .indices] +movaps xmm1, [rel .flags] + +hlt + +align 32 +.data: +dq 0x998877665A417A61 ; "azAZ" (followed by junk) +dq 0x55AACCBBFF223344 +dq 0xFFFFFFFFFFFFFFFF +dq 0xEEEEEEEEEEEEEEEE + +dq 0x726548206D27493F ; "?I'm Her" +dq 0x21216E65704F2065 ; "e Open!!" +dq 0xFFFFFFFFFFFFFFFF +dq 0xEEEEEEEEEEEEEEEE + +.data16: +dq 0x005A0041007A0061 ; "azAZ" +dq 0x55AACCBBFF223344 +dq 0xAAAAAAAAAAAAAAAA +dq 0xBBBBBBBBBBBBBBBB + +dq 0x006500200027003F ; "?' e" +dq 0x00210065004F0065 ; "eOen!" +dq 0x8888888888888888 +dq 0x9999999999999999 + +.indices: +dq 0x0000000000000000 +dq 0x0000000000000000 +dq 0x0000000000000000 +dq 0x0000000000000000 + +.flags: +dq 0x0000000000000000 +dq 0x0000000000000000 +dq 0x0000000000000000 +dq 0x0000000000000000 diff --git a/unittests/ASM/VEX/vpcmpestri_equal_any.asm b/unittests/ASM/VEX/vpcmpestri_equal_any.asm new file mode 100644 index 000000000..33d756cad --- /dev/null +++ b/unittests/ASM/VEX/vpcmpestri_equal_any.asm @@ -0,0 +1,154 @@ +%ifdef CONFIG +{ + "HostFeatures": ["AVX"], + "RegData": { + "RAX": ["15"], + "RDX": ["16"], + "XMM0": ["0x04070F000F000E05", "0x0000000000040404", "0x0000000000000000", "0x0000000000000000"], + "XMM1": ["0x0121313131311111", "0x0000000000010101", "0x0000000000000000", "0x0000000000000000"], + "XMM2": ["0x306F8A9E672C65E5", "0x000030443057697D", "0xAAAAAAAAAAAAAAAA", "0xBBBBBBBBBBBBBBBB"], + "XMM3": ["0x306F8A9E672C65E5", "0x00003044305796E3", "0x8888888888888888", "0x9999999999999999"] + } +} +%endif + +; Adjusts the result from LAHF and SETO so that we have a set of flags organized +; like [OF, SF, ZF, AF, PF, CF] for storing into the .flags region +; of memory. +; +; The first parameter is the byte offset to store the flag result +; at in the .flags region of memory. +; +%macro ArrangeAndStoreFLAGS 1 + lahf + seto bl + movzx bx, bl + + shr ax, 8 + shl bx, 5 + + mov di, ax + mov si, ax + + ; Mask and shift + and di, 0b0000_0000_0000_0100 ; PF + and si, 0b0000_0000_0001_0000 ; AF + shr di, 1 + shr si, 2 + + ; OR all of them together + or bx, di + or bx, si + + ; Reclaim DI for getting ZF/SF and shift into place + mov di, ax + and di, 0b0000_0000_1100_0000 ; ZF and SF + shr di, 3 + + ; Finally mask and OR all of the bits together + and ax, 0b0000_0000_0000_0001 ; CF + or bx, ax + or bx, di + + ; Store result to .flags memory + mov [rel .flags + %1], bl +%endmacro + +; Performs the string comparison and moves the result from RCX to +; a region of memory in the .indices section specified by a byte +; offset. +; +; The first parameter is the byte offset to store the RCX result to. +; The second parameter is the control values to pass to vpcmpestri +; +%macro CompareAndStore 2 + vpcmpestri xmm2, xmm3, %2 + mov [rel .indices + %1], cl + + mov r15, rax + ArrangeAndStoreFLAGS %1 + mov rax, r15 +%endmacro + +vmovaps ymm2, [rel .data] +vmovaps ymm3, [rel .data + 32] + +; Unsigned byte character check (lsb, positive polarity) +mov rax, 15 ; Exclude 'l' +mov rdx, 16 +CompareAndStore 0, 0b00000000 + +; Unsigned byte character check (msb, positive polarity) +CompareAndStore 1, 0b01000000 + +; Unsigned byte character check (lsb, negative polarity) +CompareAndStore 2, 0b00010000 + +; Unsigned byte character check (msb, negative polarity) +CompareAndStore 3, 0b01010000 + +; Unsigned byte character check (lsb, negative masked) +CompareAndStore 4, 0b00110000 + +; Unsigned byte character check (msb, negative masked) +CompareAndStore 5, 0b01110000 + +; --- 16-bit unsigned word tests --- +vmovaps ymm2, [rel .data16] +vmovaps ymm3, [rel .data16 + 32] + +; Unsigned word character check (msb, positive polarity) +CompareAndStore 6, 0b01000001 + +; Unsigned word character check (lsb, negative polarity) +CompareAndStore 7, 0b00010001 + +; Unsigned word character check (msb, negative polarity) +CompareAndStore 8, 0b01010001 + +; Unsigned word character check (lsb, negative masked) +CompareAndStore 9, 0b00110001 + +; Unsigned word character check (msb, negative masked) +CompareAndStore 10, 0b01110001 + +; Load all our stored indices and flags for result comparing +vmovaps ymm0, [rel .indices] +vmovaps ymm1, [rel .flags] + +hlt + +align 32 +.data: +dq 0x6463626144434241 ; "ABCDabcd" +dq 0x6C6B6A694C4B4A49 ; "IJKLijkl" +dq 0xFFFFFFFFFFFFFFFF +dq 0xEEEEEEEEEEEEEEEE + +dq 0x4120492065726548 ; "Here I A" +dq 0x6C4C612759202C6D ; "m, Y'aLl" +dq 0xDDDDDDDDDDDDDDDD +dq 0xCCCCCCCCCCCCCCCC + +.data16: +dq 0x306F8A9E672C65E5 ; "日本語は" +dq 0x000030443057697D ; "楽しい\0" (Japanese is fun) +dq 0xAAAAAAAAAAAAAAAA +dq 0xBBBBBBBBBBBBBBBB + +dq 0x306F8A9E672C65E5 ; "日本語は" +dq 0x00003044305796E3 ; "難しい\0" (Japanese is hard) +dq 0x8888888888888888 +dq 0x9999999999999999 + +.indices: +dq 0x0000000000000000 +dq 0x0000000000000000 +dq 0x0000000000000000 +dq 0x0000000000000000 + +.flags: +dq 0x0000000000000000 +dq 0x0000000000000000 +dq 0x0000000000000000 +dq 0x0000000000000000 diff --git a/unittests/ASM/VEX/vpcmpestri_equal_each.asm b/unittests/ASM/VEX/vpcmpestri_equal_each.asm new file mode 100644 index 000000000..acb8de892 --- /dev/null +++ b/unittests/ASM/VEX/vpcmpestri_equal_each.asm @@ -0,0 +1,200 @@ +%ifdef CONFIG +{ + "HostFeatures": ["AVX"], + "RegData": { + "RAX": ["4"], + "RDX": ["3"], + "XMM0": ["0x0F000B060B060F00", "0x040407000F060706", "0x0704030307000404", "0x0000000000000000"], + "XMM1": ["0x3939010101012121", "0x0101212119191919", "0x1919191939390101", "0x0000000000000000"], + "XMM2": ["0x306F8A9E672C65E5", "0x000030443057697D", "0xAAAAAAAAAAAAAAAA", "0xBBBBBBBBBBBBBBBB"], + "XMM3": ["0x306F8A9E672C65E5", "0x00003044305796E3", "0x8888888888888888", "0x9999999999999999"] + } +} +%endif + +; Adjusts the result from LAHF and SETO so that we have a set of flags organized +; like [OF, SF, ZF, AF, PF, CF] for storing into the .flags region +; of memory. +; +; The first parameter is the byte offset to store the flag result +; at in the .flags region of memory. +; +%macro ArrangeAndStoreFLAGS 1 + lahf + seto bl + movzx bx, bl + + shr ax, 8 + shl bx, 5 + + mov di, ax + mov si, ax + + ; Mask and shift + and di, 0b0000_0000_0000_0100 ; PF + and si, 0b0000_0000_0001_0000 ; AF + shr di, 1 + shr si, 2 + + ; OR all of them together + or bx, di + or bx, si + + ; Reclaim DI for getting ZF/SF and shift into place + mov di, ax + and di, 0b0000_0000_1100_0000 ; ZF and SF + shr di, 3 + + ; Finally mask and OR all of the bits together + and ax, 0b0000_0000_0000_0001 ; CF + or bx, ax + or bx, di + + ; Store result to .flags memory + mov [rel .flags + %1], bl +%endmacro + +; Performs the string comparison and moves the result from RCX to +; a region of memory in the .indices section specified by a byte +; offset. +; +; The first parameter is the byte offset to store the RCX result to. +; The second parameter is the control values to pass to vpcmpestri +; +%macro CompareAndStore 2 + vpcmpestri xmm2, xmm3, %2 + mov [rel .indices + %1], cl + + mov r15, rax + ArrangeAndStoreFLAGS %1 + mov rax, r15 +%endmacro + +vmovaps ymm2, [rel .data] +vmovaps ymm3, [rel .data + 32] + +; Full length unsigned byte string check (lsb, positive polarity) +mov rax, 16 +mov rdx, 16 +CompareAndStore 0, 0b00001000 + +; Full length unsigned byte string check (msb, positive polarity) +CompareAndStore 1, 0b01001000 + +; Full length unsigned byte string check (lsb, negative polarity) +CompareAndStore 2, 0b00011000 + +; Full length unsigned byte string check (msb, negative polarity) +CompareAndStore 3, 0b01011000 + +; Full length unsigned byte string check (lsb, negative masked) +CompareAndStore 4, 0b00111000 + +; Full length unsigned byte string check (msb, negative masked) +CompareAndStore 5, 0b01111000 + +; Non-full length unsigned byte string check (lsb, positive polarity) +mov rax, 8 +mov rdx, 7 +CompareAndStore 6, 0b00001000 + +; Non-full length unsigned byte string check (msb, positive polarity) +CompareAndStore 7, 0b01001000 + +; Non-full length unsigned byte string check (lsb, negative polarity) +CompareAndStore 8, 0b00011000 + +; Non-full length unsigned byte string check (msb, negative polarity) +CompareAndStore 9, 0b01011000 + +; Non-full length unsigned byte string check (lsb, negative masked) +CompareAndStore 10, 0b00111000 + +; Non-full length unsigned byte string check (msb, negative masked) +CompareAndStore 11, 0b01111000 + +; --- 16-bit unsigned word tests --- + +vmovaps ymm2, [rel .data16] +vmovaps ymm3, [rel .data16 + 32] + +; Full length unsigned word string check (lsb, positive polarity) +mov rax, 8 +mov rdx, 8 +CompareAndStore 12, 0b00001001 + +; Full length unsigned word string check (msb, positive polarity) +CompareAndStore 13, 0b01001001 + +; Full length unsigned word string check (lsb, negative polarity) +CompareAndStore 14, 0b00011001 + +; Full length unsigned word string check (msb, negative polarity) +CompareAndStore 15, 0b01011001 + +; Full length unsigned word string check (lsb, negative masked) +CompareAndStore 16, 0b00111001 + +; Full length unsigned word string check (msb, negative masked) +CompareAndStore 17, 0b01111001 + +; Non-full length unsigned word string check (lsb, positive polarity) +mov rax, 4 +mov rdx, 3 +CompareAndStore 18, 0b00001001 + +; Non-full length unsigned word string check (msb, positive polarity) +CompareAndStore 19, 0b01001001 + +; Non-full length unsigned word string check (lsb, negative polarity) +CompareAndStore 20, 0b00011001 + +; Non-full length unsigned word string check (msb, negative polarity) +CompareAndStore 21, 0b01011001 + +; Non-full length unsigned word string check (lsb, negative masked) +CompareAndStore 22, 0b00111001 + +; Non-full length unsigned word string check (msb, negative masked) +CompareAndStore 23, 0b01111001 + +; Load all our stored indices and flags for result comparing +vmovaps ymm0, [rel .indices] +vmovaps ymm1, [rel .flags] + +hlt + +align 32 +.data: +dq 0x6550206F6C6C6548 ; "Hello Pe" +dq 0x21212121656C706F ; "ople!!!!" +dq 0xFFFFFFFFFFFFFFFF +dq 0xEEEEEEEEEEEEEEEE + +dq 0x2759206F6C6C6548 ; "Hello Y'" +dq 0x21212121216C6C61 ; "all!!!!!" +dq 0xDDDDDDDDDDDDDDDD +dq 0xCCCCCCCCCCCCCCCC + +.data16: +dq 0x306F8A9E672C65E5 ; "日本語は" +dq 0x000030443057697D ; "楽しい\0" (Japanese is fun) +dq 0xAAAAAAAAAAAAAAAA +dq 0xBBBBBBBBBBBBBBBB + +dq 0x306F8A9E672C65E5 ; "日本語は" +dq 0x00003044305796E3 ; "難しい\0" (Japanese is hard) +dq 0x8888888888888888 +dq 0x9999999999999999 + +.indices: +dq 0x0000000000000000 +dq 0x0000000000000000 +dq 0x0000000000000000 +dq 0x0000000000000000 + +.flags: +dq 0x0000000000000000 +dq 0x0000000000000000 +dq 0x0000000000000000 +dq 0x0000000000000000 diff --git a/unittests/ASM/VEX/vpcmpestri_equal_ordered.asm b/unittests/ASM/VEX/vpcmpestri_equal_ordered.asm new file mode 100644 index 000000000..9b377b6fa --- /dev/null +++ b/unittests/ASM/VEX/vpcmpestri_equal_ordered.asm @@ -0,0 +1,157 @@ +%ifdef CONFIG +{ + "HostFeatures": ["AVX"], + "RegData": { + "RAX": ["2"], + "RDX": ["16"], + "XMM0": ["0x05050F000F000902", "0x0000000007000700", "0x0000000000000000", "0x0000000000000000"], + "XMM1": ["0x1111313131311111", "0x0000000031313131", "0x0000000000000000", "0x0000000000000000"], + "XMM2": ["0x306F8A9E30443057", "0x000030443057697D", "0xAAAAAAAAAAAAAAAA", "0xBBBBBBBBBBBBBBBB"], + "XMM3": ["0x306F8A9E672C65E5", "0x00003044305796E3", "0x8888888888888888", "0x9999999999999999"] + } +} +%endif + +; Adjusts the result from LAHF and SETO so that we have a set of flags organized +; like [OF, SF, ZF, AF, PF, CF] for storing into the .flags region +; of memory. +; +; The first parameter is the byte offset to store the flag result +; at in the .flags region of memory. +; +%macro ArrangeAndStoreFLAGS 1 + lahf + seto bl + movzx bx, bl + + shr ax, 8 + shl bx, 5 + + mov di, ax + mov si, ax + + ; Mask and shift + and di, 0b0000_0000_0000_0100 ; PF + and si, 0b0000_0000_0001_0000 ; AF + shr di, 1 + shr si, 2 + + ; OR all of them together + or bx, di + or bx, si + + ; Reclaim DI for getting ZF/SF and shift into place + mov di, ax + and di, 0b0000_0000_1100_0000 ; ZF and SF + shr di, 3 + + ; Finally mask and OR all of the bits together + and ax, 0b0000_0000_0000_0001 ; CF + or bx, ax + or bx, di + + ; Store result to .flags memory + mov [rel .flags + %1], bl +%endmacro + +; Performs the string comparison and moves the result from RCX to +; a region of memory in the .indices section specified by a byte +; offset. +; +; The first parameter is the byte offset to store the RCX result to. +; The second parameter is the control values to pass to vpcmpestri +; +%macro CompareAndStore 2 + vpcmpestri xmm2, xmm3, %2 + mov [rel .indices + %1], cl + + mov r15, rax + ArrangeAndStoreFLAGS %1 + mov rax, r15 +%endmacro + +vmovaps ymm2, [rel .data] +vmovaps ymm3, [rel .data + 32] + +; Unsigned byte string check (lsb, positive polarity) +mov rax, 2 +mov rdx, 16 +CompareAndStore 0, 0b00001100 + +; Unsigned byte string check (msb, positive polarity) +CompareAndStore 1, 0b01001100 + +; Unsigned byte string check (lsb, negative polarity) +CompareAndStore 2, 0b00011100 + +; Unsigned byte string check (msb, negative polarity) +CompareAndStore 3, 0b01011100 + +; Unsigned byte string check (lsb, negative masked) +CompareAndStore 4, 0b00111100 + +; Unsigned byte string check (msb, negative masked) +CompareAndStore 5, 0b01111100 + +; --- 16-bit unsigned word tests --- +; Intentionally don't reset RDX to 8 here to test upper bounds clamping. +vmovaps ymm2, [rel .data16] +vmovaps ymm3, [rel .data16 + 32] + +CompareAndStore 6, 0b00001101 + +; Unsigned word string check (msb, positive polarity) +CompareAndStore 7, 0b01001101 + +; Unsigned word string check (lsb, negative polarity) +CompareAndStore 8, 0b00011101 + +; Unsigned word string check (msb, negative polarity) +CompareAndStore 9, 0b01011101 + +; Unsigned word string check (lsb, negative masked) +CompareAndStore 10, 0b00111101 + +; Unsigned word string check (msb, negative masked) +CompareAndStore 11, 0b01111101 + +; Load all our stored indices and flags for result comparing +vmovaps ymm0, [rel .indices] +vmovaps ymm1, [rel .flags] + +hlt + +align 32 +.data: +dq 0x6550206F6FFF6C6C ; "ll" with junk following it +dq 0x21212121656C706F +dq 0xFFFFFFFFFFFFFFFF +dq 0xEEEEEEEEEEEEEEEE + +dq 0x2759206F6C6C6548 ; "Hello Y'" +dq 0x21212121216C6C61 ; "all!!!!!" +dq 0xDDDDDDDDDDDDDDDD +dq 0xCCCCCCCCCCCCCCCC + +.data16: +dq 0x306F8A9E30443057 ; "しい" followed by junk +dq 0x000030443057697D +dq 0xAAAAAAAAAAAAAAAA +dq 0xBBBBBBBBBBBBBBBB + +dq 0x306F8A9E672C65E5 ; "日本語は" +dq 0x00003044305796E3 ; "難しい\0" (Japanese is hard) +dq 0x8888888888888888 +dq 0x9999999999999999 + +.indices: +dq 0x0000000000000000 +dq 0x0000000000000000 +dq 0x0000000000000000 +dq 0x0000000000000000 + +.flags: +dq 0x0000000000000000 +dq 0x0000000000000000 +dq 0x0000000000000000 +dq 0x0000000000000000 diff --git a/unittests/ASM/VEX/vpcmpestri_ranges.asm b/unittests/ASM/VEX/vpcmpestri_ranges.asm new file mode 100644 index 000000000..8bf67507f --- /dev/null +++ b/unittests/ASM/VEX/vpcmpestri_ranges.asm @@ -0,0 +1,155 @@ +%ifdef CONFIG +{ + "HostFeatures": ["AVX"], + "RegData": { + "RAX": ["4"], + "RDX": ["16"], + "XMM0": ["0x00060F000F000D01", "0x0000000000070007", "0x0000000000000000", "0x0000000000000000"], + "XMM1": ["0x3111313131311111", "0x0000000000313131", "0x0000000000000000", "0x0000000000000000"], + "XMM2": ["0x005A0041007A0061", "0x55AACCBBFF223344", "0xAAAAAAAAAAAAAAAA", "0xBBBBBBBBBBBBBBBB"], + "XMM3": ["0x006500200027003F", "0x00210065004F0065", "0x8888888888888888", "0x9999999999999999"] + } +} +%endif + +; Adjusts the result from LAHF and SETO so that we have a set of flags organized +; like [OF, SF, ZF, AF, PF, CF] for storing into the .flags region +; of memory. +; +; The first parameter is the byte offset to store the flag result +; at in the .flags region of memory. +; +%macro ArrangeAndStoreFLAGS 1 + lahf + seto bl + movzx bx, bl + + shr ax, 8 + shl bx, 5 + + mov di, ax + mov si, ax + + ; Mask and shift + and di, 0b0000_0000_0000_0100 ; PF + and si, 0b0000_0000_0001_0000 ; AF + shr di, 1 + shr si, 2 + + ; OR all of them together + or bx, di + or bx, si + + ; Reclaim DI for getting ZF/SF and shift into place + mov di, ax + and di, 0b0000_0000_1100_0000 ; ZF and SF + shr di, 3 + + ; Finally mask and OR all of the bits together + and ax, 0b0000_0000_0000_0001 ; CF + or bx, ax + or bx, di + + ; Store result to .flags memory + mov [rel .flags + %1], bl +%endmacro + +; Performs the string comparison and moves the result from RCX to +; a region of memory in the .indices section specified by a byte +; offset. +; +; The first parameter is the byte offset to store the RCX result to. +; The second parameter is the control values to pass to vpcmpestri +; +%macro CompareAndStore 2 + vpcmpestri xmm2, xmm3, %2 + mov [rel .indices + %1], cl + + mov r15, rax + ArrangeAndStoreFLAGS %1 + mov rax, r15 +%endmacro + +vmovaps ymm2, [rel .data] +vmovaps ymm3, [rel .data + 32] + +; Range unsigned byte check (lsb, positive polarity) +mov rax, 4 +mov rdx, 16 +CompareAndStore 0, 0b00000100 + +; Range unsigned byte check (msb, positive polarity) +CompareAndStore 1, 0b01000100 + +; Range unsigned byte check (lsb, negative polarity) +CompareAndStore 2, 0b00010100 + +; Range unsigned byte check (msb, negative polarity) +CompareAndStore 3, 0b01010100 + +; Range unsigned byte check (lsb, negative masked) +CompareAndStore 4, 0b00110100 + +; Range unsigned byte check (msb, negative masked) +CompareAndStore 5, 0b01110100 + +; --- 16-bit unsigned word tests --- +; Intentionally don't reset RDX to 8 here to test upper bounds clamping. +vmovaps ymm2, [rel .data16] +vmovaps ymm3, [rel .data16 + 32] + +; Range unsigned word check (msb, positive polarity) +CompareAndStore 6, 0b01000101 + +; Range unsigned word check (lsb, negative polarity) +CompareAndStore 7, 0b00010101 + +; Range unsigned word check (msb, negative polarity) +CompareAndStore 8, 0b01010101 + +; Range unsigned word check (lsb, negative masked) +CompareAndStore 9, 0b00110101 + +; Range unsigned word check (msb, negative masked) +CompareAndStore 10, 0b01110101 + +; Load all our stored indices and flags for result comparing +vmovaps ymm0, [rel .indices] +vmovaps ymm1, [rel .flags] + +hlt + +align 32 +.data: +dq 0x998877665A417A61 ; "azAZ" (followed by junk) +dq 0x55AACCBBFF223344 +dq 0xFFFFFFFFFFFFFFFF +dq 0xEEEEEEEEEEEEEEEE + +dq 0x726548206D27493F ; "?I'm Her" +dq 0x21216E65704F2065 ; "e Open!!" +dq 0xFFFFFFFFFFFFFFFF +dq 0xEEEEEEEEEEEEEEEE + +.data16: +dq 0x005A0041007A0061 ; "azAZ" +dq 0x55AACCBBFF223344 +dq 0xAAAAAAAAAAAAAAAA +dq 0xBBBBBBBBBBBBBBBB + +dq 0x006500200027003F ; "?' e" +dq 0x00210065004F0065 ; "eOen!" +dq 0x8888888888888888 +dq 0x9999999999999999 + +.indices: +dq 0x0000000000000000 +dq 0x0000000000000000 +dq 0x0000000000000000 +dq 0x0000000000000000 + +.flags: +dq 0x0000000000000000 +dq 0x0000000000000000 +dq 0x0000000000000000 +dq 0x0000000000000000