| 3754 | } |
| 3755 | |
| 3756 | void OpDispatchBuilder::CMPXCHGOp(OpcodeArgs) { |
| 3757 | // CMPXCHG ModRM, reg, {RAX} |
| 3758 | // MemData = *ModRM.dest |
| 3759 | // if (RAX == MemData) |
| 3760 | // modRM.dest = reg; |
| 3761 | // ZF = 1 |
| 3762 | // else |
| 3763 | // ZF = 0 |
| 3764 | // RAX = MemData |
| 3765 | // |
| 3766 | // CASL Xs, Xt, Xn |
| 3767 | // MemData = *Xn |
| 3768 | // if (MemData == Xs) |
| 3769 | // *Xn = Xt |
| 3770 | // Xs = MemData |
| 3771 | |
| 3772 | const auto GPRSize = GetGPROpSize(); |
| 3773 | auto Size = OpSizeFromSrc(Op); |
| 3774 | |
| 3775 | if (Op->Dest.IsGPR()) { |
| 3776 | // This is our source register |
| 3777 | Ref Src2 = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.AllowUpperGarbage = true}); |
| 3778 | Ref Src3 = LoadGPRRegister(X86State::REG_RAX); |
| 3779 | |
| 3780 | // If the destination is also the accumulator, we get some algebraic |
| 3781 | // simplifications. Not sure if this is actually hit but it's in |
| 3782 | // InstCountCI. |
| 3783 | bool Trivial = Op->Dest.Data.GPR.GPR == X86State::REG_RAX && !Op->Dest.IsGPRDirect() && !Op->Dest.Data.GPR.HighBits; |
| 3784 | |
| 3785 | Ref Src1 {}; |
| 3786 | Ref Src1Lower {}; |
| 3787 | |
| 3788 | if (GPRSize == OpSize::i64Bit && Size == OpSize::i32Bit) { |
| 3789 | Src1 = LoadSource_WithOpSize(GPRClass, Op, Op->Dest, GPRSize, Op->Flags, {.AllowUpperGarbage = true}); |
| 3790 | Src1Lower = Trivial ? Src1 : _Bfe(GPRSize, IR::OpSizeAsBits(Size), 0, Src1); |
| 3791 | } else { |
| 3792 | Src1 = LoadSource_WithOpSize(GPRClass, Op, Op->Dest, Size, Op->Flags, {.AllowUpperGarbage = true}); |
| 3793 | Src1Lower = Src1; |
| 3794 | } |
| 3795 | |
| 3796 | // Compare RAX with the destination, setting flags accordingly. |
| 3797 | CalculateFlags_SUB(OpSizeFromSrc(Op), Src3, Src1Lower); |
| 3798 | CalculateDeferredFlags(); |
| 3799 | |
| 3800 | if (!Trivial) { |
| 3801 | if (GPRSize == OpSize::i64Bit && Size == OpSize::i32Bit) { |
| 3802 | // This allows us to only hit the ZEXT case on failure |
| 3803 | Ref RAXResult = NZCVSelect(OpSize::i64Bit, {COND_EQ}, Src3, Src1Lower); |
| 3804 | |
| 3805 | // When the size is 4 we need to make sure not zext the GPR when the comparison fails |
| 3806 | StoreGPRRegister(X86State::REG_RAX, RAXResult); |
| 3807 | } else { |
| 3808 | StoreGPRRegister(X86State::REG_RAX, Src1Lower, Size); |
| 3809 | } |
| 3810 | } |
| 3811 | |
| 3812 | // Op1 = RAX == Op1 ? Op2 : Op1 |
| 3813 | // If they match then set the rm operand to the input |
nothing calls this directly
no test coverage detected