diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp index 14cdacfc2..b29472e51 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp @@ -4265,6 +4265,13 @@ void OpDispatchBuilder::CMPXCHGOp(OpcodeArgs) { // 0x80064000 if (Op->Dest.IsGPR()) { + // If the destination is also the accumulator, we get some algebraic + // simplifications. Not sure if this is actually hit but it's in + // InstCountCI. + bool Trivial = Op->Dest.Data.GPR.GPR == X86State::REG_RAX && + !Op->Dest.IsGPRDirect() && + !Op->Dest.Data.GPR.HighBits; + OrderedNode *Src1{}; OrderedNode *Src1Lower{}; @@ -4288,40 +4295,37 @@ void OpDispatchBuilder::CMPXCHGOp(OpcodeArgs) { Src3Lower = Src3; } - // If our destination is a GPR then this behaves differently - // RAX = RAX == Op1 ? RAX : Op1 - // AKA if they match then don't touch RAX value - // Otherwise set it to the rm operand - OrderedNode *CASResult = _Select(FEXCore::IR::COND_EQ, - Src1Lower, Src3Lower, - Src3Lower, Src1Lower); + // Compare RAX with the destination, setting flags accordingly. + OrderedNode *Result = _Sub(IR::SizeToOpSize(GPRSize), Src3Lower, Src1Lower); + GenerateFlags_SUB(Op, Result, Src3Lower, Src1Lower); + CalculateDeferredFlags(); + + if (!Trivial) { + if (GPRSize == 8 && Size == 4) { + // This allows us to only hit the ZEXT case on failure + OrderedNode *RAXResult = _NZCVSelect(IR::i64Bit, CondClassType{COND_EQ}, + Src3, Src1Lower); + + // When the size is 4 we need to make sure not zext the GPR when the comparison fails + StoreGPRRegister(X86State::REG_RAX, RAXResult); + } + else { + StoreGPRRegister(X86State::REG_RAX, Src1Lower, Size); + } + } // Op1 = RAX == Op1 ? Op2 : Op1 // If they match then set the rm operand to the input // else don't set the rm operand - OrderedNode *DestResult = _Select(FEXCore::IR::COND_EQ, - Src1Lower, Src3Lower, - Src2, Src1); + OrderedNode *DestResult = + Trivial ? Src2 : _NZCVSelect(IR::i64Bit, CondClassType{COND_EQ}, Src2, Src1); // Store in to GPR Dest - // Have to make sure this is after the result store in RAX for when Dest == RAX if (GPRSize == 8 && Size == 4) { - // This allows us to only hit the ZEXT case on failure - OrderedNode *RAXResult = _Select(FEXCore::IR::COND_EQ, - CASResult, Src3Lower, - Src3, Src1Lower); - - // When the size is 4 we need to make sure not zext the GPR when the comparison fails - StoreGPRRegister(X86State::REG_RAX, RAXResult); StoreResult_WithOpSize(GPRClass, Op, Op->Dest, DestResult, GPRSize, -1); - } - else { - StoreGPRRegister(X86State::REG_RAX, CASResult, Size); + } else { StoreResult(GPRClass, Op, DestResult, -1); } - - OrderedNode *Result = _Sub(IR::SizeToOpSize(GPRSize), Src3Lower, CASResult); - GenerateFlags_SUB(Op, Result, Src3Lower, CASResult); } else { HandledLock = Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_LOCK; diff --git a/unittests/InstructionCountCI/FlagM/Secondary.json b/unittests/InstructionCountCI/FlagM/Secondary.json index 812370f15..d0a30a9b1 100644 --- a/unittests/InstructionCountCI/FlagM/Secondary.json +++ b/unittests/InstructionCountCI/FlagM/Secondary.json @@ -1025,27 +1025,100 @@ "ccmn xzr, #0, #nzCV, eq" ] }, + "cmpxchg cl, bl": { + "ExpectedInstructionCount": 14, + "ExpectedArm64ASM": [ + "uxtb w20, w7", + "uxtb w21, w5", + "uxtb x22, w4", + "sub x26, x22, x21", + "eor w27, w22, w21", + "cmn wzr, w26, lsl #24", + "rmif x26, #7, #nzCv", + "eor w23, w22, w21", + "eor w22, w26, w22", + "and w22, w22, w23", + "rmif x22, #7, #nzcV", + "bfxil x4, x21, #0, #8", + "csel x20, x20, x21, eq", + "bfxil x5, x20, #0, #8" + ] + }, + "cmpxchg cx, bx": { + "ExpectedInstructionCount": 14, + "ExpectedArm64ASM": [ + "uxth w20, w7", + "uxth w21, w5", + "uxth x22, w4", + "sub x26, x22, x21", + "eor w27, w22, w21", + "cmn wzr, w26, lsl #16", + "rmif x26, #15, #nzCv", + "eor w23, w22, w21", + "eor w22, w26, w22", + "and w22, w22, w23", + "rmif x22, #15, #nzcV", + "bfxil x4, x21, #0, #16", + "csel x20, x20, x21, eq", + "bfxil x5, x20, #0, #16" + ] + }, + "cmpxchg ecx, ebx": { + "ExpectedInstructionCount": 9, + "ExpectedArm64ASM": [ + "mov w20, w7", + "mov w21, w5", + "mov w22, w4", + "sub x26, x22, x21", + "eor w27, w22, w21", + "cmp w22, w21", + "cfinv", + "csel x4, x4, x21, eq", + "csel x5, x20, x5, eq" + ] + }, + "cmpxchg rcx, rbx": { + "ExpectedInstructionCount": 7, + "ExpectedArm64ASM": [ + "mov x20, x5", + "sub x26, x4, x20", + "eor x27, x4, x20", + "cmp x4, x20", + "cfinv", + "mov x4, x20", + "csel x5, x7, x20, eq" + ] + }, + "cmpxchg [rax], rbx": { + "ExpectedInstructionCount": 8, + "Comment": "0x0f 0xb1", + "ExpectedArm64ASM": [ + "mov x20, x4", + "mov x1, x20", + "casal x1, x7, [x20]", + "mov x4, x1", + "sub x26, x20, x4", + "eor x27, x20, x4", + "cmp x20, x4", + "cfinv" + ] + }, "cmpxchg al, bl": { - "ExpectedInstructionCount": 17, + "ExpectedInstructionCount": 12, "Comment": "0x0f 0xb0", "ExpectedArm64ASM": [ "uxtb w20, w7", "uxtb w21, w4", "uxtb x22, w4", - "cmp x21, x22", - "csel x23, x22, x21, eq", - "cmp x21, x22", - "csel w20, w20, w21, eq", - "bfxil x4, x23, #0, #8", - "bfxil x4, x20, #0, #8", - "sub x26, x22, x23", - "eor w27, w22, w23", + "sub x26, x22, x21", + "eor w27, w22, w21", "cmn wzr, w26, lsl #24", "rmif x26, #7, #nzCv", - "eor w20, w22, w23", - "eor w21, w26, w22", - "and w20, w21, w20", - "rmif x20, #7, #nzcV" + "eor w21, w22, w21", + "eor w22, w26, w22", + "and w21, w22, w21", + "rmif x21, #7, #nzcV", + "bfxil x4, x20, #0, #8" ] }, "cmpxchg [rax], bl": { @@ -1069,26 +1142,21 @@ ] }, "cmpxchg ax, bx": { - "ExpectedInstructionCount": 17, + "ExpectedInstructionCount": 12, "Comment": "0x0f 0xb1", "ExpectedArm64ASM": [ "uxth w20, w7", "uxth w21, w4", "uxth x22, w4", - "cmp x21, x22", - "csel x23, x22, x21, eq", - "cmp x21, x22", - "csel w20, w20, w21, eq", - "bfxil x4, x23, #0, #16", - "bfxil x4, x20, #0, #16", - "sub x26, x22, x23", - "eor w27, w22, w23", + "sub x26, x22, x21", + "eor w27, w22, w21", "cmn wzr, w26, lsl #16", "rmif x26, #15, #nzCv", - "eor w20, w22, w23", - "eor w21, w26, w22", - "and w20, w21, w20", - "rmif x20, #15, #nzcV" + "eor w21, w22, w21", + "eor w22, w26, w22", + "and w21, w22, w21", + "rmif x21, #15, #nzcV", + "bfxil x4, x20, #0, #16" ] }, "cmpxchg [rax], bx": { @@ -1112,24 +1180,17 @@ ] }, "cmpxchg eax, ebx": { - "ExpectedInstructionCount": 15, + "ExpectedInstructionCount": 8, "Comment": "0x0f 0xb1", "ExpectedArm64ASM": [ "mov w20, w7", - "mov x21, x4", - "mov w22, w21", - "mov w23, w21", - "cmp x22, x23", - "csel x24, x23, x22, eq", - "cmp x22, x23", - "csel x20, x20, x21, eq", - "cmp x24, x23", - "csel x4, x21, x22, eq", - "mov x4, x20", - "sub x26, x23, x24", - "eor w27, w23, w24", - "cmp w23, w24", - "cfinv" + "mov w21, w4", + "mov w22, w4", + "sub x26, x22, x21", + "eor w27, w22, w21", + "cmp w22, w21", + "cfinv", + "mov x4, x20" ] }, "cmpxchg [rax], ebx": { @@ -1150,34 +1211,15 @@ ] }, "cmpxchg rax, rbx": { - "ExpectedInstructionCount": 11, + "ExpectedInstructionCount": 6, "Comment": "0x0f 0xb1", "ExpectedArm64ASM": [ - "mov x20, x4", - "cmp x20, x20", - "csel x21, x20, x20, eq", - "cmp x20, x20", - "csel x22, x7, x20, eq", - "mov x4, x21", - "mov x4, x22", - "sub x26, x20, x21", - "eor x27, x20, x21", - "cmp x20, x21", - "cfinv" - ] - }, - "cmpxchg [rax], rbx": { - "ExpectedInstructionCount": 8, - "Comment": "0x0f 0xb1", - "ExpectedArm64ASM": [ - "mov x20, x4", - "mov x1, x20", - "casal x1, x7, [x20]", - "mov x4, x1", - "sub x26, x20, x4", - "eor x27, x20, x4", - "cmp x20, x4", - "cfinv" + "mov x20, x7", + "sub x26, x4, x4", + "mov w27, #0x0", + "cmp x4, x4", + "cfinv", + "mov x4, x20" ] }, "btr ax, bx": { diff --git a/unittests/InstructionCountCI/Secondary.json b/unittests/InstructionCountCI/Secondary.json index 2056e27e5..591b8751b 100644 --- a/unittests/InstructionCountCI/Secondary.json +++ b/unittests/InstructionCountCI/Secondary.json @@ -1895,30 +1895,25 @@ ] }, "cmpxchg al, bl": { - "ExpectedInstructionCount": 21, + "ExpectedInstructionCount": 16, "Comment": "0x0f 0xb0", "ExpectedArm64ASM": [ "uxtb w20, w7", "uxtb w21, w4", "uxtb x22, w4", - "cmp x21, x22", - "csel x23, x22, x21, eq", - "cmp x21, x22", - "csel w20, w20, w21, eq", - "bfxil x4, x23, #0, #8", - "bfxil x4, x20, #0, #8", - "sub x26, x22, x23", - "eor w27, w22, w23", + "sub x26, x22, x21", + "eor w27, w22, w21", "cmn wzr, w26, lsl #24", - "mrs x20, nzcv", - "ubfx x21, x26, #8, #1", - "orr w20, w20, w21, lsl #29", - "eor w21, w22, w23", + "mrs x23, nzcv", + "ubfx x24, x26, #8, #1", + "orr w23, w23, w24, lsl #29", + "eor w21, w22, w21", "eor w22, w26, w22", "and w21, w22, w21", "ubfx x21, x21, #7, #1", - "orr w20, w20, w21, lsl #28", - "msr nzcv, x20" + "orr w21, w23, w21, lsl #28", + "msr nzcv, x21", + "bfxil x4, x20, #0, #8" ] }, "cmpxchg [rax], bl": { @@ -1946,30 +1941,25 @@ ] }, "cmpxchg ax, bx": { - "ExpectedInstructionCount": 21, + "ExpectedInstructionCount": 16, "Comment": "0x0f 0xb1", "ExpectedArm64ASM": [ "uxth w20, w7", "uxth w21, w4", "uxth x22, w4", - "cmp x21, x22", - "csel x23, x22, x21, eq", - "cmp x21, x22", - "csel w20, w20, w21, eq", - "bfxil x4, x23, #0, #16", - "bfxil x4, x20, #0, #16", - "sub x26, x22, x23", - "eor w27, w22, w23", + "sub x26, x22, x21", + "eor w27, w22, w21", "cmn wzr, w26, lsl #16", - "mrs x20, nzcv", - "ubfx x21, x26, #16, #1", - "orr w20, w20, w21, lsl #29", - "eor w21, w22, w23", + "mrs x23, nzcv", + "ubfx x24, x26, #16, #1", + "orr w23, w23, w24, lsl #29", + "eor w21, w22, w21", "eor w22, w26, w22", "and w21, w22, w21", "ubfx x21, x21, #15, #1", - "orr w20, w20, w21, lsl #28", - "msr nzcv, x20" + "orr w21, w23, w21, lsl #28", + "msr nzcv, x21", + "bfxil x4, x20, #0, #16" ] }, "cmpxchg [rax], bx": { @@ -1997,26 +1987,19 @@ ] }, "cmpxchg eax, ebx": { - "ExpectedInstructionCount": 17, + "ExpectedInstructionCount": 10, "Comment": "0x0f 0xb1", "ExpectedArm64ASM": [ "mov w20, w7", - "mov x21, x4", - "mov w22, w21", - "mov w23, w21", - "cmp x22, x23", - "csel x24, x23, x22, eq", - "cmp x22, x23", - "csel x20, x20, x21, eq", - "cmp x24, x23", - "csel x4, x21, x22, eq", - "mov x4, x20", - "sub x26, x23, x24", - "eor w27, w23, w24", - "cmp w23, w24", - "mrs x20, nzcv", - "eor w20, w20, #0x20000000", - "msr nzcv, x20" + "mov w21, w4", + "mov w22, w4", + "sub x26, x22, x21", + "eor w27, w22, w21", + "cmp w22, w21", + "mrs x21, nzcv", + "eor w21, w21, #0x20000000", + "msr nzcv, x21", + "mov x4, x20" ] }, "cmpxchg [rax], ebx": { @@ -2039,22 +2022,17 @@ ] }, "cmpxchg rax, rbx": { - "ExpectedInstructionCount": 13, + "ExpectedInstructionCount": 8, "Comment": "0x0f 0xb1", "ExpectedArm64ASM": [ - "mov x20, x4", - "cmp x20, x20", - "csel x21, x20, x20, eq", - "cmp x20, x20", - "csel x22, x7, x20, eq", - "mov x4, x21", - "mov x4, x22", - "sub x26, x20, x21", - "eor x27, x20, x21", - "cmp x20, x21", - "mrs x20, nzcv", - "eor w20, w20, #0x20000000", - "msr nzcv, x20" + "mov x20, x7", + "sub x26, x4, x4", + "mov w27, #0x0", + "cmp x4, x4", + "mrs x21, nzcv", + "eor w21, w21, #0x20000000", + "msr nzcv, x21", + "mov x4, x20" ] }, "cmpxchg [rax], rbx": {