diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp index 0658150d0..0af91899a 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp @@ -2133,17 +2133,17 @@ void OpDispatchBuilder::BEXTRBMIOp(OpcodeArgs) { // Now handle the length specifier. auto Length = _Bfe(OpSizeFromSrc(Op), 8, 8, Src2); - auto SanitizedLength = _Select(IR::COND_ULE, - Length, MaxSrcBitOp, - Length, MaxSrcBitOp); // Now build up the mask - // (1 << SanitizedLength) - 1 - auto One = _Constant(SrcSize, 1); - auto Mask = _Sub(IR::SizeToOpSize(Size), _Lshl(IR::SizeToOpSize(Size), One, SanitizedLength), One); + // (1 << Length) - 1 = ~(~0 << Length) + auto AllOnes = _Constant(~0ull); + auto InvertedMask = _Lshl(IR::SizeToOpSize(Size), AllOnes, Length); // Now put it all together and make the result. - auto Dest = _And(IR::SizeToOpSize(Size), SanitizedShifted, Mask); + auto Masked = _Andn(IR::SizeToOpSize(Size), SanitizedShifted, InvertedMask); + + // Sanitize the length. If it is above the max, we don't do the masking. + auto Dest = _Select(IR::COND_ULE, Length, MaxSrcBitOp, Masked, SanitizedShifted); // Finally store the result. StoreResult(GPRClass, Op, Dest, -1); @@ -2175,7 +2175,7 @@ void OpDispatchBuilder::BLSMSKBMIOp(OpcodeArgs) { auto Result = _Xor(Size, _Sub(Size, Src, _Constant(1)), Src); StoreResult(GPRClass, Op, Result, -1); - GenerateFlags_BLSMSK(Op, Src); + GenerateFlags_BLSMSK(Op, Result, Src); } void OpDispatchBuilder::BLSRBMIOp(OpcodeArgs) { @@ -5378,7 +5378,7 @@ void OpDispatchBuilder::TZCNT(OpcodeArgs) { Src = _FindTrailingZeroes(OpSizeFromSrc(Op), Src); StoreResult(GPRClass, Op, Src, -1); - GenerateFlags_TZCNT(Op, Src); + GenerateFlags_ZCNT(Op, Src); } void OpDispatchBuilder::LZCNT(OpcodeArgs) { @@ -5387,7 +5387,7 @@ void OpDispatchBuilder::LZCNT(OpcodeArgs) { auto Res = _CountLeadingZeroes(OpSizeFromSrc(Op), Src); StoreResult(GPRClass, Op, Res, -1); - GenerateFlags_LZCNT(Op, Src); + GenerateFlags_ZCNT(Op, Res); } void OpDispatchBuilder::MOVBEOp(OpcodeArgs) { diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher.h b/FEXCore/Source/Interface/Core/OpcodeDispatcher.h index 26f467ab1..42fa5e0e5 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher.h +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher.h @@ -102,8 +102,7 @@ public: TYPE_BLSR, TYPE_POPCOUNT, TYPE_BZHI, - TYPE_TZCNT, - TYPE_LZCNT, + TYPE_ZCNT, TYPE_RDRAND, }; @@ -1604,11 +1603,11 @@ private: OrderedNode *Res{}; union { - // UMUL, BEXTR, BLSI, BLSMSK, POPCOUNT, TZCNT, LZCNT, RDRAND + // UMUL, BEXTR, BLSI, POPCOUNT, ZCNT, RDRAND struct { } NoSource; - // MUL, BLSR, BZHI + // MUL, BLSR, BLSMSKB, BZHI struct { OrderedNode *Src1; } OneSource; @@ -1740,12 +1739,11 @@ private: void CalculateFlags_RotateLeftImmediate(uint8_t SrcSize, OrderedNode *Res, OrderedNode *Src1, uint64_t Shift); void CalculateFlags_BEXTR(OrderedNode *Src); void CalculateFlags_BLSI(uint8_t SrcSize, OrderedNode *Src); - void CalculateFlags_BLSMSK(OrderedNode *Src); + void CalculateFlags_BLSMSK(uint8_t SrcSize, OrderedNode *Res, OrderedNode *Src); void CalculateFlags_BLSR(uint8_t SrcSize, OrderedNode *Res, OrderedNode *Src); void CalculateFlags_POPCOUNT(OrderedNode *Src); void CalculateFlags_BZHI(uint8_t SrcSize, OrderedNode *Result, OrderedNode *Src); - void CalculateFlags_TZCNT(OrderedNode *Src); - void CalculateFlags_LZCNT(uint8_t SrcSize, OrderedNode *Src); + void CalculateFlags_ZCNT(uint8_t SrcSize, OrderedNode *Result); void CalculateFlags_RDRAND(OrderedNode *Src); /** @} */ @@ -2064,11 +2062,16 @@ private: }; } - void GenerateFlags_BLSMSK(FEXCore::X86Tables::DecodedOp Op, OrderedNode *Src) { + void GenerateFlags_BLSMSK(FEXCore::X86Tables::DecodedOp Op, OrderedNode *Res, OrderedNode *Src) { CurrentDeferredFlags = DeferredFlagData { .Type = FlagsGenerationType::TYPE_BLSMSK, .SrcSize = GetSrcSize(Op), - .Res = Src, + .Res = Res, + .Sources = { + .OneSource = { + .Src1 = Src, + }, + }, }; } @@ -2106,17 +2109,9 @@ private: }; } - void GenerateFlags_TZCNT(FEXCore::X86Tables::DecodedOp Op, OrderedNode *Src) { + void GenerateFlags_ZCNT(FEXCore::X86Tables::DecodedOp Op, OrderedNode *Src) { CurrentDeferredFlags = DeferredFlagData { - .Type = FlagsGenerationType::TYPE_TZCNT, - .SrcSize = GetSrcSize(Op), - .Res = Src, - }; - } - - void GenerateFlags_LZCNT(FEXCore::X86Tables::DecodedOp Op, OrderedNode *Src) { - CurrentDeferredFlags = DeferredFlagData { - .Type = FlagsGenerationType::TYPE_LZCNT, + .Type = FlagsGenerationType::TYPE_ZCNT, .SrcSize = GetSrcSize(Op), .Res = Src, }; diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher/Flags.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher/Flags.cpp index d130c53fd..0d612d603 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher/Flags.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher/Flags.cpp @@ -444,7 +444,10 @@ void OpDispatchBuilder::CalculateDeferredFlags(uint32_t FlagsToCalculateMask) { CurrentDeferredFlags.Res); break; case FlagsGenerationType::TYPE_BLSMSK: - CalculateFlags_BLSMSK(CurrentDeferredFlags.Res); + CalculateFlags_BLSMSK( + CurrentDeferredFlags.SrcSize, + CurrentDeferredFlags.Res, + CurrentDeferredFlags.Sources.OneSource.Src1); break; case FlagsGenerationType::TYPE_BLSR: CalculateFlags_BLSR( @@ -461,11 +464,8 @@ void OpDispatchBuilder::CalculateDeferredFlags(uint32_t FlagsToCalculateMask) { CurrentDeferredFlags.Res, CurrentDeferredFlags.Sources.OneSource.Src1); break; - case FlagsGenerationType::TYPE_TZCNT: - CalculateFlags_TZCNT(CurrentDeferredFlags.Res); - break; - case FlagsGenerationType::TYPE_LZCNT: - CalculateFlags_LZCNT( + case FlagsGenerationType::TYPE_ZCNT: + CalculateFlags_ZCNT( CurrentDeferredFlags.SrcSize, CurrentDeferredFlags.Res); break; @@ -976,112 +976,67 @@ void OpDispatchBuilder::CalculateFlags_RotateLeftImmediate(uint8_t SrcSize, Orde } void OpDispatchBuilder::CalculateFlags_BEXTR(OrderedNode *Src) { - auto Zero = _Constant(0); - auto One = _Constant(1); + // ZF is set properly. CF and OF are defined as being set to zero. SF, PF, and + // AF are undefined. + SetNZ_ZeroCV(GetOpSize(Src), Src); - // Handle flag setting. - // - // All that matters primarily for this instruction is - // that we only set the ZF flag properly. - // - // CF and OF are defined as being set to zero - // - // Every other flag is considered undefined after a - // BEXTR instruction, but we opt to reliably clear them. - // - ZeroMultipleFlags(FullNZCVMask); - - // PF/AF undefined _InvalidateFlags((1UL << X86State::RFLAG_PF_RAW_LOC) | (1UL << X86State::RFLAG_AF_RAW_LOC)); - - // ZF - auto ZeroOp = _Select(IR::COND_EQ, - Src, Zero, - One, Zero); - SetRFLAG(ZeroOp); } -void OpDispatchBuilder::CalculateFlags_BLSI(uint8_t SrcSize, OrderedNode *Src) { - // Now for the flags: +void OpDispatchBuilder::CalculateFlags_BLSI(uint8_t SrcSize, OrderedNode *Result) { + // CF is cleared if Src is zero, otherwise it's set. However, Src is zero iff + // Result is zero, so we can test the result instead. So, CF is just the + // inverted ZF. // - // Only CF, SF, ZF and OF are defined as being updated - // CF is cleared if Src is zero, otherwise it's set. - // SF is set to the value of the most significant operand bit of Result. - // OF is always cleared - // ZF is set, as usual, if Result is zero or not. + // ZF/SF/OF set as usual. + SetNZ_ZeroCV(SrcSize, Result); - auto Zero = _Constant(0); - auto One = _Constant(1); - - SetNZ_ZeroCV(SrcSize, Src); + auto CFOp = GetRFLAG(X86State::RFLAG_ZF_RAW_LOC, true /* Invert */); + SetRFLAG(CFOp); // PF/AF undefined _InvalidateFlags((1UL << X86State::RFLAG_PF_RAW_LOC) | (1UL << X86State::RFLAG_AF_RAW_LOC)); - - - // CF - { - auto CFOp = _Select(IR::COND_NEQ, Src, Zero, One, Zero); - SetRFLAG(CFOp); - } } -void OpDispatchBuilder::CalculateFlags_BLSMSK(OrderedNode *Src) { - // Now for the flags. - - auto Zero = _Constant(0); - auto One = _Constant(1); - - uint32_t FlagsMaskToZero = - (1U << X86State::RFLAG_ZF_RAW_LOC) | - (1U << X86State::RFLAG_OF_RAW_LOC); - - ZeroMultipleFlags(FlagsMaskToZero); - +void OpDispatchBuilder::CalculateFlags_BLSMSK(uint8_t SrcSize, OrderedNode *Result, OrderedNode *Src) { // PF/AF undefined _InvalidateFlags((1UL << X86State::RFLAG_PF_RAW_LOC) | (1UL << X86State::RFLAG_AF_RAW_LOC)); - auto CFOp = _Select(IR::COND_NEQ, Src, Zero, One, Zero); + // CF set according to the Src + auto Zero = _Constant(0); + auto One = _Constant(1); + auto CFOp = _Select(IR::COND_EQ, Src, Zero, One, Zero); + + // The output of BLSMSK is always nonzero, so TST will clear Z (along with C + // and O) while setting S. + SetNZ_ZeroCV(SrcSize, Result); SetRFLAG(CFOp); } void OpDispatchBuilder::CalculateFlags_BLSR(uint8_t SrcSize, OrderedNode *Result, OrderedNode *Src) { - // Now for flags. auto Zero = _Constant(0); auto One = _Constant(1); + auto CFOp = _Select(IR::COND_EQ, Src, Zero, One, Zero); SetNZ_ZeroCV(SrcSize, Result); + SetRFLAG(CFOp); // PF/AF undefined _InvalidateFlags((1UL << X86State::RFLAG_PF_RAW_LOC) | (1UL << X86State::RFLAG_AF_RAW_LOC)); - - // CF - { - auto CFOp = _Select(IR::COND_NEQ, Src, Zero, One, Zero); - SetRFLAG(CFOp); - } } -void OpDispatchBuilder::CalculateFlags_POPCOUNT(OrderedNode *Src) { - // Set ZF - auto Zero = _Constant(0); - auto ZFResult = _Select(FEXCore::IR::COND_EQ, - Src, Zero, - _Constant(1), Zero); +void OpDispatchBuilder::CalculateFlags_POPCOUNT(OrderedNode *Result) { + // We need to set ZF while clearing the rest of NZCV. The result of a popcount + // is in the range [0, 63]. In particular, it is always positive. So a + // combined NZ test will correctly zero SF/CF/OF while setting ZF. + SetNZ_ZeroCV(OpSize::i32Bit, Result); - // Set flags - uint32_t FlagsMaskToZero = - FullNZCVMask | - (1U << X86State::RFLAG_AF_RAW_LOC) | - (1U << X86State::RFLAG_PF_RAW_LOC); - - ZeroMultipleFlags(FlagsMaskToZero); - - SetRFLAG(ZFResult); + ZeroMultipleFlags((1U << X86State::RFLAG_AF_RAW_LOC) | + (1U << X86State::RFLAG_PF_RAW_LOC)); } void OpDispatchBuilder::CalculateFlags_BZHI(uint8_t SrcSize, OrderedNode *Result, OrderedNode *Src) { @@ -1093,32 +1048,16 @@ void OpDispatchBuilder::CalculateFlags_BZHI(uint8_t SrcSize, OrderedNode *Result SetRFLAG(Src); } -void OpDispatchBuilder::CalculateFlags_TZCNT(OrderedNode *Src) { +void OpDispatchBuilder::CalculateFlags_ZCNT(uint8_t SrcSize, OrderedNode *Result) { // OF, SF, AF, PF all undefined - ZeroNZCV(); + // Test ZF of result, SF is undefined so this is ok. + SetNZ_ZeroCV(SrcSize, Result); - auto Zero = _Constant(0); - auto ZFResult = _Select(FEXCore::IR::COND_EQ, - Src, Zero, - _Constant(1), Zero); - - // Set flags - SetRFLAG(ZFResult); - SetRFLAG(Src, 0, true); -} - -void OpDispatchBuilder::CalculateFlags_LZCNT(uint8_t SrcSize, OrderedNode *Src) { - // OF, SF, AF, PF all undefined - ZeroNZCV(); - - auto Zero = _Constant(0); - auto ZFResult = _Select(FEXCore::IR::COND_EQ, - Src, Zero, - _Constant(1), Zero); - - // Set flags - SetRFLAG(ZFResult); - SetRFLAG(Src, SrcSize * 8 - 1, true); + // Now set CF if the Result = SrcSize * 8. Since SrcSize is a power-of-two and + // Result is <= SrcSize * 8, we equivalently check if the log2(SrcSize * 8) + // bit is set. No masking is needed because no higher bits could be set. + unsigned CarryBit = FEXCore::ilog2(SrcSize * 8u); + SetRFLAG(Result, CarryBit); } void OpDispatchBuilder::CalculateFlags_RDRAND(OrderedNode *Src) { diff --git a/unittests/ASM/FEX_bugs/BLSI_flags.asm b/unittests/ASM/FEX_bugs/BLSI_flags.asm new file mode 100644 index 000000000..e9698d5d8 --- /dev/null +++ b/unittests/ASM/FEX_bugs/BLSI_flags.asm @@ -0,0 +1,60 @@ +%ifdef CONFIG +{ + "RegData": { + "RDX": "0xcafe" + }, + "HostFeatures": ["BMI1"] +} +%endif + +; Source 0 sets ZF +mov rax, 0 +blsi rax, rax + +js fexi_fexi_im_so_broken +jnz fexi_fexi_im_so_broken +jc fexi_fexi_im_so_broken +jo fexi_fexi_im_so_broken + +; Source 1 sets CF +mov rax, 1 +blsi rax, rax + +js fexi_fexi_im_so_broken +jz fexi_fexi_im_so_broken +jnc fexi_fexi_im_so_broken +jo fexi_fexi_im_so_broken + +; Source all-1's sets CF +mov rax, 0xffffffffffffffff +blsi rax, rax + +js fexi_fexi_im_so_broken +jz fexi_fexi_im_so_broken +jnc fexi_fexi_im_so_broken +jo fexi_fexi_im_so_broken + +; Source 1<<63 sets CF and SF +mov rax, 0x8000000000000000 +blsi rax, rax + +jns fexi_fexi_im_so_broken +jz fexi_fexi_im_so_broken +jnc fexi_fexi_im_so_broken +jo fexi_fexi_im_so_broken + +; Make sure we're correctly clearing the overflow flag +mov rbx, 5 +mov al, 0x7F +inc al +jno fexi_fexi_im_so_broken +blsi rax, rax +jo fexi_fexi_im_so_broken + +; Happy ending +mov rdx, 0xcafe +hlt + +fexi_fexi_im_so_broken: +mov rdx, 0xdead +hlt diff --git a/unittests/ASM/FEX_bugs/BLSMSK_flags.asm b/unittests/ASM/FEX_bugs/BLSMSK_flags.asm new file mode 100644 index 000000000..b9c397a49 --- /dev/null +++ b/unittests/ASM/FEX_bugs/BLSMSK_flags.asm @@ -0,0 +1,63 @@ +%ifdef CONFIG +{ + "RegData": { + "RDX": "0xcafe", + "RBX": "5" + }, + "HostFeatures": ["BMI1"] +} +%endif + +; Result in all-1's due to underflow so SF/CF set +mov rbx, 1 +mov rax, 0 +blsmsk rax, rax + +jns fexi_fexi_im_so_broken +jz fexi_fexi_im_so_broken +jnc fexi_fexi_im_so_broken +jo fexi_fexi_im_so_broken + +; Result in 1, so all flags clear +mov rbx, 2 +mov rax, 11 +blsmsk rax, rax + +js fexi_fexi_im_so_broken +jz fexi_fexi_im_so_broken +jc fexi_fexi_im_so_broken +jo fexi_fexi_im_so_broken + +; Result in all-1's without carry, so SF set +mov rbx, 3 +mov rax, 0x8000000000000000 +blsmsk rax, rax + +jns fexi_fexi_im_so_broken +jz fexi_fexi_im_so_broken +jc fexi_fexi_im_so_broken +jo fexi_fexi_im_so_broken + +; Make sure we're correctly clearing the zero flag +mov rbx, 4 +mov rax, 0 +add rax, rax +jnz fexi_fexi_im_so_broken +blsmsk rax, rax +jz fexi_fexi_im_so_broken + +; Make sure we're correctly clearing the overflow flag +mov rbx, 5 +mov al, 0x7F +inc al +jno fexi_fexi_im_so_broken +blsmsk rax, rax +jo fexi_fexi_im_so_broken + +; Happy ending +mov rdx, 0xcafe +hlt + +fexi_fexi_im_so_broken: +mov rdx, 0xdead +hlt diff --git a/unittests/ASM/FEX_bugs/BLSR_flags.asm b/unittests/ASM/FEX_bugs/BLSR_flags.asm new file mode 100644 index 000000000..b0f200f88 --- /dev/null +++ b/unittests/ASM/FEX_bugs/BLSR_flags.asm @@ -0,0 +1,60 @@ +%ifdef CONFIG +{ + "RegData": { + "RDX": "0xcafe" + }, + "HostFeatures": ["BMI1"] +} +%endif + +; Source 0 sets CF and ZF +mov rax, 0 +blsr rax, rax + +js fexi_fexi_im_so_broken +jnz fexi_fexi_im_so_broken +jnc fexi_fexi_im_so_broken +jo fexi_fexi_im_so_broken + +; Source 1 sets ZF +mov rax, 1 +blsr rax, rax + +js fexi_fexi_im_so_broken +jnz fexi_fexi_im_so_broken +jc fexi_fexi_im_so_broken +jo fexi_fexi_im_so_broken + +; Source 3 sets nothing +mov rax, 3 +blsr rax, rax + +js fexi_fexi_im_so_broken +jz fexi_fexi_im_so_broken +jc fexi_fexi_im_so_broken +jo fexi_fexi_im_so_broken + +; Source all-1's sets SF +mov rax, 0xffffffffffffffff +blsr rax, rax + +jns fexi_fexi_im_so_broken +jz fexi_fexi_im_so_broken +jc fexi_fexi_im_so_broken +jo fexi_fexi_im_so_broken + +; Make sure we're correctly clearing the overflow flag +mov rbx, 5 +mov al, 0x7F +inc al +jno fexi_fexi_im_so_broken +blsr rax, rax +jo fexi_fexi_im_so_broken + +; Happy ending +mov rdx, 0xcafe +hlt + +fexi_fexi_im_so_broken: +mov rdx, 0xdead +hlt diff --git a/unittests/InstructionCountCI/FlagM/Secondary_REP.json b/unittests/InstructionCountCI/FlagM/Secondary_REP.json index 12a75b610..6710e8472 100644 --- a/unittests/InstructionCountCI/FlagM/Secondary_REP.json +++ b/unittests/InstructionCountCI/FlagM/Secondary_REP.json @@ -14,7 +14,7 @@ }, "Instructions": { "popcnt ax, bx": { - "ExpectedInstructionCount": 12, + "ExpectedInstructionCount": 9, "Comment": "0xf3 0x0f 0xb8", "ExpectedArm64ASM": [ "uxth w20, w7", @@ -23,124 +23,97 @@ "addp v0.8b, v0.8b, v0.8b", "umov w20, v0.b[0]", "bfxil x4, x20, #0, #16", + "tst w20, w20", "mov w27, #0x0", - "mov w26, #0x1", - "cmp x20, #0x0 (0)", - "cset x20, eq", - "lsl x20, x20, #30", - "msr nzcv, x20" + "mov w26, #0x1" ] }, "popcnt eax, ebx": { - "ExpectedInstructionCount": 10, + "ExpectedInstructionCount": 7, "Comment": "0xf3 0x0f 0xb8", "ExpectedArm64ASM": [ "fmov s0, w7", "cnt v0.8b, v0.8b", "addv b0, v0.8b", "umov w4, v0.b[0]", + "tst w4, w4", "mov w27, #0x0", - "mov w26, #0x1", - "cmp x4, #0x0 (0)", - "cset x20, eq", - "lsl x20, x20, #30", - "msr nzcv, x20" + "mov w26, #0x1" ] }, "popcnt rax, rbx": { - "ExpectedInstructionCount": 10, + "ExpectedInstructionCount": 7, "Comment": "0xf3 0x0f 0xb8", "ExpectedArm64ASM": [ "fmov d0, x7", "cnt v0.8b, v0.8b", "addv b0, v0.8b", "umov w4, v0.b[0]", + "tst w4, w4", "mov w27, #0x0", - "mov w26, #0x1", - "cmp x4, #0x0 (0)", - "cset x20, eq", - "lsl x20, x20, #30", - "msr nzcv, x20" + "mov w26, #0x1" ] }, "tzcnt ax, bx": { - "ExpectedInstructionCount": 9, + "ExpectedInstructionCount": 6, "Comment": "0xf3 0x0f 0xbc", "ExpectedArm64ASM": [ "rbit w20, w7", "orr w20, w20, #0x8000", "clz w20, w20", "bfxil x4, x20, #0, #16", - "cmp x20, #0x0 (0)", - "cset x21, eq", - "lsl x21, x21, #29", - "msr nzcv, x21", - "rmif x20, #62, #nZcv" + "cmn wzr, w20, lsl #16", + "rmif x20, #3, #nzCv" ] }, "tzcnt eax, ebx": { - "ExpectedInstructionCount": 7, + "ExpectedInstructionCount": 4, "Comment": "0xf3 0x0f 0xbc", "ExpectedArm64ASM": [ "rbit w4, w7", "clz w4, w4", - "cmp x4, #0x0 (0)", - "cset x20, eq", - "lsl x20, x20, #29", - "msr nzcv, x20", - "rmif x4, #62, #nZcv" + "tst w4, w4", + "rmif x4, #4, #nzCv" ] }, "tzcnt rax, rbx": { - "ExpectedInstructionCount": 7, + "ExpectedInstructionCount": 4, "Comment": "0xf3 0x0f 0xbc", "ExpectedArm64ASM": [ "rbit x4, x7", "clz x4, x4", - "cmp x4, #0x0 (0)", - "cset x20, eq", - "lsl x20, x20, #29", - "msr nzcv, x20", - "rmif x4, #62, #nZcv" + "tst x4, x4", + "rmif x4, #5, #nzCv" ] }, "lzcnt ax, bx": { - "ExpectedInstructionCount": 9, + "ExpectedInstructionCount": 6, "Comment": "0xf3 0x0f 0xbd", "ExpectedArm64ASM": [ "lsl w20, w7, #16", "orr w20, w20, #0x8000", "clz w20, w20", "bfxil x4, x20, #0, #16", - "cmp x7, #0x0 (0)", - "cset x20, eq", - "lsl x20, x20, #29", - "msr nzcv, x20", - "rmif x7, #13, #nZcv" + "cmn wzr, w20, lsl #16", + "rmif x20, #3, #nzCv" ] }, "lzcnt eax, ebx": { - "ExpectedInstructionCount": 6, + "ExpectedInstructionCount": 3, "Comment": "0xf3 0x0f 0xbd", "ExpectedArm64ASM": [ "clz w4, w7", - "cmp x7, #0x0 (0)", - "cset x20, eq", - "lsl x20, x20, #29", - "msr nzcv, x20", - "rmif x7, #29, #nZcv" + "tst w4, w4", + "rmif x4, #4, #nzCv" ] }, "lzcnt rax, rbx": { - "ExpectedInstructionCount": 6, + "ExpectedInstructionCount": 3, "Comment": "0xf3 0x0f 0xbd", "ExpectedArm64ASM": [ "clz x4, x7", - "cmp x7, #0x0 (0)", - "cset x20, eq", - "lsl x20, x20, #29", - "msr nzcv, x20", - "rmif x7, #61, #nZcv" + "tst x4, x4", + "rmif x4, #5, #nzCv" ] } } diff --git a/unittests/InstructionCountCI/FlagM/VEX_map2.json b/unittests/InstructionCountCI/FlagM/VEX_map2.json index 28b791206..f83e40ecd 100644 --- a/unittests/InstructionCountCI/FlagM/VEX_map2.json +++ b/unittests/InstructionCountCI/FlagM/VEX_map2.json @@ -442,53 +442,43 @@ ] }, "bextr eax, ebx, ecx": { - "ExpectedInstructionCount": 17, + "ExpectedInstructionCount": 12, "Comment": [ "Map 2 0b00 0xf7 32-bit" ], "ExpectedArm64ASM": [ - "mov w20, #0x1f", - "uxtb w21, w5", - "lsr w22, w7, w21", - "mov w23, #0x0", + "uxtb w20, w5", + "lsr w21, w7, w20", + "mov w22, #0x0", + "cmp w20, #0x1f (31)", + "csel w20, w21, w22, ls", + "ubfx w21, w5, #8, #8", + "mov x22, #0xffffffffffffffff", + "lsl w22, w22, w21", + "bic w22, w20, w22", "cmp w21, #0x1f (31)", - "csel w21, w22, w23, ls", - "ubfx w22, w5, #8, #8", - "cmp w22, #0x1f (31)", - "csel w20, w22, w20, ls", - "mov w22, #0x1", - "lsl w20, w22, w20", - "sub w20, w20, #0x1 (1)", - "and w4, w21, w20", - "cmp x4, #0x0 (0)", - "cset x20, eq", - "lsl x20, x20, #30", - "msr nzcv, x20" + "csel w4, w22, w20, ls", + "tst w4, w4" ] }, "bextr rax, rbx, rcx": { - "ExpectedInstructionCount": 17, + "ExpectedInstructionCount": 12, "Comment": [ "Map 2 0b00 0xf7 64-bit" ], "ExpectedArm64ASM": [ - "mov w20, #0x3f", - "uxtb x21, w5", - "lsr x22, x7, x21", - "mov w23, #0x0", + "uxtb x20, w5", + "lsr x21, x7, x20", + "mov w22, #0x0", + "cmp x20, #0x3f (63)", + "csel x20, x21, x22, ls", + "ubfx x21, x5, #8, #8", + "mov x22, #0xffffffffffffffff", + "lsl x22, x22, x21", + "bic x22, x20, x22", "cmp x21, #0x3f (63)", - "csel x21, x22, x23, ls", - "ubfx x22, x5, #8, #8", - "cmp x22, #0x3f (63)", - "csel x20, x22, x20, ls", - "mov w22, #0x1", - "lsl x20, x22, x20", - "sub x20, x20, #0x1 (1)", - "and x4, x21, x20", - "cmp x4, #0x0 (0)", - "cset x20, eq", - "lsl x20, x20, #30", - "msr nzcv, x20" + "csel x4, x22, x20, ls", + "tst x4, x4" ] } } diff --git a/unittests/InstructionCountCI/FlagM/VEX_map_group.json b/unittests/InstructionCountCI/FlagM/VEX_map_group.json index cb482da17..277bfad73 100644 --- a/unittests/InstructionCountCI/FlagM/VEX_map_group.json +++ b/unittests/InstructionCountCI/FlagM/VEX_map_group.json @@ -10,73 +10,63 @@ }, "Instructions": { "blsr eax, ebx": { - "ExpectedInstructionCount": 8, + "ExpectedInstructionCount": 6, "Comment": [ "Map group 17 0b001 32-bit" ], "ExpectedArm64ASM": [ "sub w20, w7, #0x1 (1)", "and w4, w20, w7", - "tst w4, w4", - "mrs x20, nzcv", "cmp x7, #0x0 (0)", - "cset x21, ne", - "orr w20, w20, w21, lsl #29", - "msr nzcv, x20" + "cset x20, eq", + "tst w4, w4", + "rmif x20, #63, #nzCv" ] }, "blsr rax, rbx": { - "ExpectedInstructionCount": 8, + "ExpectedInstructionCount": 6, "Comment": [ "Map group 17 0b001 64-bit" ], "ExpectedArm64ASM": [ "sub x20, x7, #0x1 (1)", "and x4, x20, x7", - "tst x4, x4", - "mrs x20, nzcv", "cmp x7, #0x0 (0)", - "cset x21, ne", - "orr w20, w20, w21, lsl #29", - "msr nzcv, x20" + "cset x20, eq", + "tst x4, x4", + "rmif x20, #63, #nzCv" ] }, "blsmsk eax, ebx": { - "ExpectedInstructionCount": 9, + "ExpectedInstructionCount": 6, "Comment": [ "Map group 17 0b010 32-bit" ], "ExpectedArm64ASM": [ "sub w20, w7, #0x1 (1)", "eor w4, w20, w7", - "mov w20, #0x50000000", - "mrs x21, nzcv", - "bic x20, x21, x20", "cmp x7, #0x0 (0)", - "cset x21, ne", - "msr nzcv, x20", - "rmif x21, #63, #nzCv" + "cset x20, eq", + "tst w4, w4", + "rmif x20, #63, #nzCv" ] }, "blsmsk rax, rbx": { - "ExpectedInstructionCount": 9, + "ExpectedInstructionCount": 6, "Comment": [ "Map group 17 0b010 64-bit" ], "ExpectedArm64ASM": [ "sub x20, x7, #0x1 (1)", "eor x4, x20, x7", - "mov w20, #0x50000000", - "mrs x21, nzcv", - "bic x20, x21, x20", "cmp x7, #0x0 (0)", - "cset x21, ne", - "msr nzcv, x20", - "rmif x21, #63, #nzCv" + "cset x20, eq", + "tst x4, x4", + "rmif x20, #63, #nzCv" ] }, "blsi eax, ebx": { - "ExpectedInstructionCount": 8, + "ExpectedInstructionCount": 5, "Comment": [ "Map group 17 0b011 32-bit" ], @@ -84,15 +74,12 @@ "neg w20, w7", "and w4, w7, w20", "tst w4, w4", - "mrs x20, nzcv", - "cmp x4, #0x0 (0)", - "cset x21, ne", - "orr w20, w20, w21, lsl #29", - "msr nzcv, x20" + "cset w20, ne", + "rmif x20, #63, #nzCv" ] }, "blsi rax, rbx": { - "ExpectedInstructionCount": 8, + "ExpectedInstructionCount": 5, "Comment": [ "Map group 17 0b011 64-bit" ], @@ -100,11 +87,8 @@ "neg x20, x7", "and x4, x7, x20", "tst x4, x4", - "mrs x20, nzcv", - "cmp x4, #0x0 (0)", - "cset x21, ne", - "orr w20, w20, w21, lsl #29", - "msr nzcv, x20" + "cset w20, ne", + "rmif x20, #63, #nzCv" ] } } diff --git a/unittests/InstructionCountCI/Secondary_REP.json b/unittests/InstructionCountCI/Secondary_REP.json index 4dacfc523..6a223b739 100644 --- a/unittests/InstructionCountCI/Secondary_REP.json +++ b/unittests/InstructionCountCI/Secondary_REP.json @@ -399,7 +399,7 @@ ] }, "popcnt ax, bx": { - "ExpectedInstructionCount": 12, + "ExpectedInstructionCount": 9, "Comment": "0xf3 0x0f 0xb8", "ExpectedArm64ASM": [ "uxth w20, w7", @@ -408,129 +408,114 @@ "addp v0.8b, v0.8b, v0.8b", "umov w20, v0.b[0]", "bfxil x4, x20, #0, #16", + "tst w20, w20", "mov w27, #0x0", - "mov w26, #0x1", - "cmp x20, #0x0 (0)", - "cset x20, eq", - "lsl x20, x20, #30", - "msr nzcv, x20" + "mov w26, #0x1" ] }, "popcnt eax, ebx": { - "ExpectedInstructionCount": 10, + "ExpectedInstructionCount": 7, "Comment": "0xf3 0x0f 0xb8", "ExpectedArm64ASM": [ "fmov s0, w7", "cnt v0.8b, v0.8b", "addv b0, v0.8b", "umov w4, v0.b[0]", + "tst w4, w4", "mov w27, #0x0", - "mov w26, #0x1", - "cmp x4, #0x0 (0)", - "cset x20, eq", - "lsl x20, x20, #30", - "msr nzcv, x20" + "mov w26, #0x1" ] }, "popcnt rax, rbx": { - "ExpectedInstructionCount": 10, + "ExpectedInstructionCount": 7, "Comment": "0xf3 0x0f 0xb8", "ExpectedArm64ASM": [ "fmov d0, x7", "cnt v0.8b, v0.8b", "addv b0, v0.8b", "umov w4, v0.b[0]", + "tst w4, w4", "mov w27, #0x0", - "mov w26, #0x1", - "cmp x4, #0x0 (0)", - "cset x20, eq", - "lsl x20, x20, #30", - "msr nzcv, x20" + "mov w26, #0x1" ] }, "tzcnt ax, bx": { - "ExpectedInstructionCount": 10, + "ExpectedInstructionCount": 9, "Comment": "0xf3 0x0f 0xbc", "ExpectedArm64ASM": [ "rbit w20, w7", "orr w20, w20, #0x8000", "clz w20, w20", "bfxil x4, x20, #0, #16", - "cmp x20, #0x0 (0)", - "cset x21, eq", - "lsl x21, x21, #29", - "ubfx x20, x20, #0, #1", - "orr w20, w21, w20, lsl #30", + "cmn wzr, w20, lsl #16", + "mrs x21, nzcv", + "ubfx x20, x20, #4, #1", + "orr w20, w21, w20, lsl #29", "msr nzcv, x20" ] }, "tzcnt eax, ebx": { - "ExpectedInstructionCount": 8, + "ExpectedInstructionCount": 7, "Comment": "0xf3 0x0f 0xbc", "ExpectedArm64ASM": [ "rbit w4, w7", "clz w4, w4", - "cmp x4, #0x0 (0)", - "cset x20, eq", - "lsl x20, x20, #29", - "ubfx x21, x4, #0, #1", - "orr w20, w20, w21, lsl #30", + "tst w4, w4", + "mrs x20, nzcv", + "ubfx x21, x4, #5, #1", + "orr w20, w20, w21, lsl #29", "msr nzcv, x20" ] }, "tzcnt rax, rbx": { - "ExpectedInstructionCount": 8, + "ExpectedInstructionCount": 7, "Comment": "0xf3 0x0f 0xbc", "ExpectedArm64ASM": [ "rbit x4, x7", "clz x4, x4", - "cmp x4, #0x0 (0)", - "cset x20, eq", - "lsl x20, x20, #29", - "ubfx x21, x4, #0, #1", - "orr w20, w20, w21, lsl #30", + "tst x4, x4", + "mrs x20, nzcv", + "ubfx x21, x4, #6, #1", + "orr w20, w20, w21, lsl #29", "msr nzcv, x20" ] }, "lzcnt ax, bx": { - "ExpectedInstructionCount": 10, + "ExpectedInstructionCount": 9, "Comment": "0xf3 0x0f 0xbd", "ExpectedArm64ASM": [ "lsl w20, w7, #16", "orr w20, w20, #0x8000", "clz w20, w20", "bfxil x4, x20, #0, #16", - "cmp x7, #0x0 (0)", - "cset x20, eq", - "lsl x20, x20, #29", - "ubfx x21, x7, #15, #1", - "orr w20, w20, w21, lsl #30", + "cmn wzr, w20, lsl #16", + "mrs x21, nzcv", + "ubfx x20, x20, #4, #1", + "orr w20, w21, w20, lsl #29", "msr nzcv, x20" ] }, "lzcnt eax, ebx": { - "ExpectedInstructionCount": 7, + "ExpectedInstructionCount": 6, "Comment": "0xf3 0x0f 0xbd", "ExpectedArm64ASM": [ "clz w4, w7", - "cmp x7, #0x0 (0)", - "cset x20, eq", - "lsl x20, x20, #29", - "ubfx x21, x7, #31, #1", - "orr w20, w20, w21, lsl #30", + "tst w4, w4", + "mrs x20, nzcv", + "ubfx x21, x4, #5, #1", + "orr w20, w20, w21, lsl #29", "msr nzcv, x20" ] }, "lzcnt rax, rbx": { - "ExpectedInstructionCount": 7, + "ExpectedInstructionCount": 6, "Comment": "0xf3 0x0f 0xbd", "ExpectedArm64ASM": [ "clz x4, x7", - "cmp x7, #0x0 (0)", - "cset x20, eq", - "lsl x20, x20, #29", - "lsr x21, x7, #63", - "orr w20, w20, w21, lsl #30", + "tst x4, x4", + "mrs x20, nzcv", + "ubfx x21, x4, #6, #1", + "orr w20, w20, w21, lsl #29", "msr nzcv, x20" ] }, diff --git a/unittests/InstructionCountCI/VEX_map2.json b/unittests/InstructionCountCI/VEX_map2.json index bdde71dfd..5bf2590f7 100644 --- a/unittests/InstructionCountCI/VEX_map2.json +++ b/unittests/InstructionCountCI/VEX_map2.json @@ -3381,53 +3381,43 @@ ] }, "bextr eax, ebx, ecx": { - "ExpectedInstructionCount": 17, + "ExpectedInstructionCount": 12, "Comment": [ "Map 2 0b00 0xf7 32-bit" ], "ExpectedArm64ASM": [ - "mov w20, #0x1f", - "uxtb w21, w5", - "lsr w22, w7, w21", - "mov w23, #0x0", + "uxtb w20, w5", + "lsr w21, w7, w20", + "mov w22, #0x0", + "cmp w20, #0x1f (31)", + "csel w20, w21, w22, ls", + "ubfx w21, w5, #8, #8", + "mov x22, #0xffffffffffffffff", + "lsl w22, w22, w21", + "bic w22, w20, w22", "cmp w21, #0x1f (31)", - "csel w21, w22, w23, ls", - "ubfx w22, w5, #8, #8", - "cmp w22, #0x1f (31)", - "csel w20, w22, w20, ls", - "mov w22, #0x1", - "lsl w20, w22, w20", - "sub w20, w20, #0x1 (1)", - "and w4, w21, w20", - "cmp x4, #0x0 (0)", - "cset x20, eq", - "lsl x20, x20, #30", - "msr nzcv, x20" + "csel w4, w22, w20, ls", + "tst w4, w4" ] }, "bextr rax, rbx, rcx": { - "ExpectedInstructionCount": 17, + "ExpectedInstructionCount": 12, "Comment": [ "Map 2 0b00 0xf7 64-bit" ], "ExpectedArm64ASM": [ - "mov w20, #0x3f", - "uxtb x21, w5", - "lsr x22, x7, x21", - "mov w23, #0x0", + "uxtb x20, w5", + "lsr x21, x7, x20", + "mov w22, #0x0", + "cmp x20, #0x3f (63)", + "csel x20, x21, x22, ls", + "ubfx x21, x5, #8, #8", + "mov x22, #0xffffffffffffffff", + "lsl x22, x22, x21", + "bic x22, x20, x22", "cmp x21, #0x3f (63)", - "csel x21, x22, x23, ls", - "ubfx x22, x5, #8, #8", - "cmp x22, #0x3f (63)", - "csel x20, x22, x20, ls", - "mov w22, #0x1", - "lsl x20, x22, x20", - "sub x20, x20, #0x1 (1)", - "and x4, x21, x20", - "cmp x4, #0x0 (0)", - "cset x20, eq", - "lsl x20, x20, #30", - "msr nzcv, x20" + "csel x4, x22, x20, ls", + "tst x4, x4" ] }, "shlx eax, ebx, ecx": { diff --git a/unittests/InstructionCountCI/VEX_map_group.json b/unittests/InstructionCountCI/VEX_map_group.json index 19187a9fe..6ed4366dd 100644 --- a/unittests/InstructionCountCI/VEX_map_group.json +++ b/unittests/InstructionCountCI/VEX_map_group.json @@ -616,11 +616,11 @@ "ExpectedArm64ASM": [ "sub w20, w7, #0x1 (1)", "and w4, w20, w7", - "tst w4, w4", - "mrs x20, nzcv", "cmp x7, #0x0 (0)", - "cset x21, ne", - "orr w20, w20, w21, lsl #29", + "cset x20, eq", + "tst w4, w4", + "mrs x21, nzcv", + "orr w20, w21, w20, lsl #29", "msr nzcv, x20" ] }, @@ -632,50 +632,48 @@ "ExpectedArm64ASM": [ "sub x20, x7, #0x1 (1)", "and x4, x20, x7", - "tst x4, x4", - "mrs x20, nzcv", "cmp x7, #0x0 (0)", - "cset x21, ne", - "orr w20, w20, w21, lsl #29", + "cset x20, eq", + "tst x4, x4", + "mrs x21, nzcv", + "orr w20, w21, w20, lsl #29", "msr nzcv, x20" ] }, "blsmsk eax, ebx": { - "ExpectedInstructionCount": 9, + "ExpectedInstructionCount": 8, "Comment": [ "Map group 17 0b010 32-bit" ], "ExpectedArm64ASM": [ "sub w20, w7, #0x1 (1)", "eor w4, w20, w7", - "mov w20, #0x50000000", - "mrs x21, nzcv", - "bic x20, x21, x20", "cmp x7, #0x0 (0)", - "cset x21, ne", - "bfi w20, w21, #29, #1", + "cset x20, eq", + "tst w4, w4", + "mrs x21, nzcv", + "orr w20, w21, w20, lsl #29", "msr nzcv, x20" ] }, "blsmsk rax, rbx": { - "ExpectedInstructionCount": 9, + "ExpectedInstructionCount": 8, "Comment": [ "Map group 17 0b010 64-bit" ], "ExpectedArm64ASM": [ "sub x20, x7, #0x1 (1)", "eor x4, x20, x7", - "mov w20, #0x50000000", - "mrs x21, nzcv", - "bic x20, x21, x20", "cmp x7, #0x0 (0)", - "cset x21, ne", - "bfi w20, w21, #29, #1", + "cset x20, eq", + "tst x4, x4", + "mrs x21, nzcv", + "orr w20, w21, w20, lsl #29", "msr nzcv, x20" ] }, "blsi eax, ebx": { - "ExpectedInstructionCount": 8, + "ExpectedInstructionCount": 7, "Comment": [ "Map group 17 0b011 32-bit" ], @@ -684,14 +682,13 @@ "and w4, w7, w20", "tst w4, w4", "mrs x20, nzcv", - "cmp x4, #0x0 (0)", - "cset x21, ne", + "cset w21, ne", "orr w20, w20, w21, lsl #29", "msr nzcv, x20" ] }, "blsi rax, rbx": { - "ExpectedInstructionCount": 8, + "ExpectedInstructionCount": 7, "Comment": [ "Map group 17 0b011 64-bit" ], @@ -700,8 +697,7 @@ "and x4, x7, x20", "tst x4, x4", "mrs x20, nzcv", - "cmp x4, #0x0 (0)", - "cset x21, ne", + "cset w21, ne", "orr w20, w20, w21, lsl #29", "msr nzcv, x20" ]