diff --git a/FEXCore/Source/Interface/Core/JIT/Arm64/ALUOps.cpp b/FEXCore/Source/Interface/Core/JIT/Arm64/ALUOps.cpp index 88be70900..8654db4ba 100644 --- a/FEXCore/Source/Interface/Core/JIT/Arm64/ALUOps.cpp +++ b/FEXCore/Source/Interface/Core/JIT/Arm64/ALUOps.cpp @@ -563,6 +563,23 @@ DEF_OP(And) { } } +DEF_OP(AndWithFlags) { + auto Op = IROp->C(); + const uint8_t OpSize = IROp->Size; + const auto EmitSize = OpSize == 8 ? ARMEmitter::Size::i64Bit : ARMEmitter::Size::i32Bit; + + const auto Dst = GetReg(Node); + const auto Src1 = GetReg(Op->Src1.ID()); + + uint64_t Const; + if (IsInlineConstant(Op->Src2, &Const)) { + ands(EmitSize, Dst, Src1, Const); + } else { + const auto Src2 = GetReg(Op->Src2.ID()); + ands(EmitSize, Dst, Src1, Src2); + } +} + DEF_OP(Andn) { auto Op = IROp->C(); const uint8_t OpSize = IROp->Size; diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp index 536f35598..1add165fa 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp @@ -1280,8 +1280,25 @@ void OpDispatchBuilder::TESTOp(OpcodeArgs) { auto Size = GetDstSize(Op); - auto ALUOp = _And(Size == 8 ? OpSize::i64Bit : OpSize::i32Bit, Dest, Src); - GenerateFlags_Logical(Op, ALUOp, Dest, Src); + InvalidateDeferredFlags(); + + // SF/ZF/CF/OF + OrderedNode *ALUOp; + + if (Size >= 4) { + ALUOp = _AndWithFlags(IR::SizeToOpSize(Size), Dest, Src); + } else { + ALUOp = _And(OpSize::i32Bit, Dest, Src); + _TestNZ(IR::SizeToOpSize(Size), ALUOp, ALUOp); + } + + CachedNZCV = nullptr; + PossiblySetNZCVBits = (1u << 31) | (1u << 30); + NZCVDirty = false; + + // PF/AF + CalculatePF(ALUOp); + _InvalidateFlags(1 << X86State::RFLAG_AF_RAW_LOC); } void OpDispatchBuilder::MOVSXDOp(OpcodeArgs) { diff --git a/FEXCore/Source/Interface/IR/IR.json b/FEXCore/Source/Interface/IR/IR.json index bd74bbb74..e5ae096f6 100644 --- a/FEXCore/Source/Interface/IR/IR.json +++ b/FEXCore/Source/Interface/IR/IR.json @@ -1089,6 +1089,15 @@ "Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit" ] }, + "GPR = AndWithFlags OpSize:#Size, GPR:$Src1, GPR:$Src2": { + "Desc": ["Integer binary and" + ], + "DestSize": "Size", + "HasSideEffects": true, + "EmitValidation": [ + "Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit" + ] + }, "GPR = Andn OpSize:#Size, GPR:$Src1, GPR:$Src2": { "Desc": ["Integer binary AND NOT. Performs the equivalent of Src1 & ~Src2"], "DestSize": "Size", diff --git a/FEXCore/Source/Interface/IR/Passes/ConstProp.cpp b/FEXCore/Source/Interface/IR/Passes/ConstProp.cpp index 3b4aee0b5..12bd140db 100644 --- a/FEXCore/Source/Interface/IR/Passes/ConstProp.cpp +++ b/FEXCore/Source/Interface/IR/Passes/ConstProp.cpp @@ -1139,6 +1139,7 @@ bool ConstProp::ConstantInlining(IREmitter *IREmit, const IRListView& CurrentIR) case OP_OR: case OP_XOR: case OP_AND: + case OP_ANDWITHFLAGS: case OP_ANDN: { auto Op = IROp->CW(); diff --git a/unittests/InstructionCountCI/FlagM/Primary.json b/unittests/InstructionCountCI/FlagM/Primary.json index f47c708e5..8018a7a67 100644 --- a/unittests/InstructionCountCI/FlagM/Primary.json +++ b/unittests/InstructionCountCI/FlagM/Primary.json @@ -1937,19 +1937,17 @@ ] }, "test eax, ebx": { - "ExpectedInstructionCount": 2, + "ExpectedInstructionCount": 1, "Comment": "0x84", "ExpectedArm64ASM": [ - "and w26, w4, w7", - "tst w26, w26" + "ands w26, w4, w7" ] }, "test rax, rbx": { - "ExpectedInstructionCount": 2, + "ExpectedInstructionCount": 1, "Comment": "0x84", "ExpectedArm64ASM": [ - "and x26, x4, x7", - "tst x26, x26" + "ands x26, x4, x7" ] }, "pushf": { @@ -2398,19 +2396,17 @@ ] }, "test eax, 1": { - "ExpectedInstructionCount": 2, + "ExpectedInstructionCount": 1, "Comment": "0xa9", "ExpectedArm64ASM": [ - "and w26, w4, #0x1", - "tst w26, w26" + "ands w26, w4, #0x1" ] }, "test rax, 1": { - "ExpectedInstructionCount": 2, + "ExpectedInstructionCount": 1, "Comment": "0xa9", "ExpectedArm64ASM": [ - "and x26, x4, #0x1", - "tst x26, x26" + "ands x26, x4, #0x1" ] }, "test al, -1": { @@ -2430,21 +2426,19 @@ ] }, "test eax, -1": { - "ExpectedInstructionCount": 3, + "ExpectedInstructionCount": 2, "Comment": "0xa9", "ExpectedArm64ASM": [ "mov w20, #0xffffffff", - "and w26, w4, w20", - "tst w26, w26" + "ands w26, w4, w20" ] }, "test rax, -1": { - "ExpectedInstructionCount": 3, + "ExpectedInstructionCount": 2, "Comment": "0xa9", "ExpectedArm64ASM": [ "mov x20, #0xffffffffffffffff", - "and x26, x4, x20", - "tst x26, x26" + "ands x26, x4, x20" ] }, "scasb": { diff --git a/unittests/InstructionCountCI/FlagM/PrimaryGroup.json b/unittests/InstructionCountCI/FlagM/PrimaryGroup.json index 16becf883..05cfdc6a9 100644 --- a/unittests/InstructionCountCI/FlagM/PrimaryGroup.json +++ b/unittests/InstructionCountCI/FlagM/PrimaryGroup.json @@ -2328,19 +2328,17 @@ ] }, "test ebx, 1": { - "ExpectedInstructionCount": 2, + "ExpectedInstructionCount": 1, "Comment": "GROUP2 0xf7 /0", "ExpectedArm64ASM": [ - "and w26, w7, #0x1", - "tst w26, w26" + "ands w26, w7, #0x1" ] }, "test rbx, 1": { - "ExpectedInstructionCount": 2, + "ExpectedInstructionCount": 1, "Comment": "GROUP2 0xf7 /0", "ExpectedArm64ASM": [ - "and x26, x7, #0x1", - "tst x26, x26" + "ands x26, x7, #0x1" ] }, "test bx, -1": { @@ -2352,21 +2350,19 @@ ] }, "test ebx, -1": { - "ExpectedInstructionCount": 3, + "ExpectedInstructionCount": 2, "Comment": "GROUP2 0xf7 /0", "ExpectedArm64ASM": [ "mov w20, #0xffffffff", - "and w26, w7, w20", - "tst w26, w26" + "ands w26, w7, w20" ] }, "test rbx, -1": { - "ExpectedInstructionCount": 3, + "ExpectedInstructionCount": 2, "Comment": "GROUP2 0xf7 /0", "ExpectedArm64ASM": [ "mov x20, #0xffffffffffffffff", - "and x26, x7, x20", - "tst x26, x26" + "ands x26, x7, x20" ] }, "neg bx": { diff --git a/unittests/InstructionCountCI/Primary.json b/unittests/InstructionCountCI/Primary.json index de3159b06..0f9d2037f 100644 --- a/unittests/InstructionCountCI/Primary.json +++ b/unittests/InstructionCountCI/Primary.json @@ -2191,19 +2191,47 @@ ] }, "test eax, ebx": { - "ExpectedInstructionCount": 2, + "ExpectedInstructionCount": 1, "Comment": "0x84", "ExpectedArm64ASM": [ - "and w26, w4, w7", - "tst w26, w26" + "ands w26, w4, w7" ] }, "test rax, rbx": { + "ExpectedInstructionCount": 1, + "Comment": "0x84", + "ExpectedArm64ASM": [ + "ands x26, x4, x7" + ] + }, + "test al, al": { "ExpectedInstructionCount": 2, "Comment": "0x84", "ExpectedArm64ASM": [ - "and x26, x4, x7", - "tst x26, x26" + "mov x26, x4", + "cmn wzr, w26, lsl #24" + ] + }, + "test ax, ax": { + "ExpectedInstructionCount": 2, + "Comment": "0x84", + "ExpectedArm64ASM": [ + "mov x26, x4", + "cmn wzr, w26, lsl #16" + ] + }, + "test eax, eax": { + "ExpectedInstructionCount": 1, + "Comment": "0x84", + "ExpectedArm64ASM": [ + "ands w26, w4, w4" + ] + }, + "test rax, rax": { + "ExpectedInstructionCount": 1, + "Comment": "0x84", + "ExpectedArm64ASM": [ + "ands x26, x4, x4" ] }, "xchg bl, cl": { @@ -3566,19 +3594,17 @@ ] }, "test eax, 1": { - "ExpectedInstructionCount": 2, + "ExpectedInstructionCount": 1, "Comment": "0xa9", "ExpectedArm64ASM": [ - "and w26, w4, #0x1", - "tst w26, w26" + "ands w26, w4, #0x1" ] }, "test rax, 1": { - "ExpectedInstructionCount": 2, + "ExpectedInstructionCount": 1, "Comment": "0xa9", "ExpectedArm64ASM": [ - "and x26, x4, #0x1", - "tst x26, x26" + "ands x26, x4, #0x1" ] }, "test al, -1": { @@ -3598,21 +3624,19 @@ ] }, "test eax, -1": { - "ExpectedInstructionCount": 3, + "ExpectedInstructionCount": 2, "Comment": "0xa9", "ExpectedArm64ASM": [ "mov w20, #0xffffffff", - "and w26, w4, w20", - "tst w26, w26" + "ands w26, w4, w20" ] }, "test rax, -1": { - "ExpectedInstructionCount": 3, + "ExpectedInstructionCount": 2, "Comment": "0xa9", "ExpectedArm64ASM": [ "mov x20, #0xffffffffffffffff", - "and x26, x4, x20", - "tst x26, x26" + "ands x26, x4, x20" ] }, "stosb": { diff --git a/unittests/InstructionCountCI/PrimaryGroup.json b/unittests/InstructionCountCI/PrimaryGroup.json index e3e66c46e..8500998d6 100644 --- a/unittests/InstructionCountCI/PrimaryGroup.json +++ b/unittests/InstructionCountCI/PrimaryGroup.json @@ -2822,19 +2822,17 @@ ] }, "test ebx, 1": { - "ExpectedInstructionCount": 2, + "ExpectedInstructionCount": 1, "Comment": "GROUP2 0xf7 /0", "ExpectedArm64ASM": [ - "and w26, w7, #0x1", - "tst w26, w26" + "ands w26, w7, #0x1" ] }, "test rbx, 1": { - "ExpectedInstructionCount": 2, + "ExpectedInstructionCount": 1, "Comment": "GROUP2 0xf7 /0", "ExpectedArm64ASM": [ - "and x26, x7, #0x1", - "tst x26, x26" + "ands x26, x7, #0x1" ] }, "test bx, -1": { @@ -2846,21 +2844,19 @@ ] }, "test ebx, -1": { - "ExpectedInstructionCount": 3, + "ExpectedInstructionCount": 2, "Comment": "GROUP2 0xf7 /0", "ExpectedArm64ASM": [ "mov w20, #0xffffffff", - "and w26, w7, w20", - "tst w26, w26" + "ands w26, w7, w20" ] }, "test rbx, -1": { - "ExpectedInstructionCount": 3, + "ExpectedInstructionCount": 2, "Comment": "GROUP2 0xf7 /0", "ExpectedArm64ASM": [ "mov x20, #0xffffffffffffffff", - "and x26, x7, x20", - "tst x26, x26" + "ands x26, x7, x20" ] }, "not bx": {