MCPcopy Create free account
hub / github.com/FEX-Emu/FEX / CMPXCHGOp

Method CMPXCHGOp

FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp:3756–3856  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

3754}
3755
3756void 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

Callers

nothing calls this directly

Calls 3

OpSizeAsBitsFunction · 0.85
IsGPRDirectMethod · 0.80
IsGPRMethod · 0.45

Tested by

no test coverage detected