| 3856 | } |
| 3857 | |
| 3858 | void OpDispatchBuilder::CMPXCHGPairOp(OpcodeArgs) { |
| 3859 | // Calculate flags early. |
| 3860 | CalculateDeferredFlags(); |
| 3861 | |
| 3862 | // REX.W used to determine if it is 16byte or 8byte |
| 3863 | // Unlike CMPXCHG, the destination can only be a memory location |
| 3864 | const auto Size = Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REX_WIDENING ? OpSize::i64Bit : OpSize::i32Bit; |
| 3865 | |
| 3866 | HandledLock = (Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_LOCK) != 0; |
| 3867 | |
| 3868 | // If this is a memory location then we want the pointer to it |
| 3869 | Ref Src1 = MakeSegmentAddress(Op, Op->Dest); |
| 3870 | |
| 3871 | // Load the full 64-bit registers, all the users ignore the upper 32-bits for |
| 3872 | // 32-bit only cmpxchg. This saves some zero extension. |
| 3873 | Ref Expected_Lower = LoadGPRRegister(X86State::REG_RAX); |
| 3874 | Ref Expected_Upper = LoadGPRRegister(X86State::REG_RDX); |
| 3875 | Ref Desired_Lower = LoadGPRRegister(X86State::REG_RBX); |
| 3876 | Ref Desired_Upper = LoadGPRRegister(X86State::REG_RCX); |
| 3877 | |
| 3878 | // ssa0 = Expected |
| 3879 | // ssa1 = Desired |
| 3880 | // ssa2 = MemoryLocation |
| 3881 | |
| 3882 | // DataSrc = *MemSrc |
| 3883 | // if (DataSrc == Expected) { *MemSrc == Desired; } Expected = DataSrc |
| 3884 | // This will write to memory! Careful! |
| 3885 | // Third operand must be a calculated guest memory address |
| 3886 | |
| 3887 | Ref Result_Lower = _AllocateGPR(true); |
| 3888 | Ref Result_Upper = _AllocateGPRAfter(Result_Lower); |
| 3889 | _CASPair(Size, Expected_Lower, Expected_Upper, Desired_Lower, Desired_Upper, Src1, Result_Lower, Result_Upper); |
| 3890 | |
| 3891 | HandleNZCV_RMW(); |
| 3892 | _CmpPairZ(Size, Result_Lower, Result_Upper, Expected_Lower, Expected_Upper); |
| 3893 | CalculateDeferredFlags(); |
| 3894 | |
| 3895 | auto UpdateIfNotZF = [this](auto Reg, auto Value) { |
| 3896 | // Always use 64-bit csel to preserve existing upper bits. If we have a |
| 3897 | // 32-bit cmpxchg in a 64-bit context, Value will be zeroed in upper bits. |
| 3898 | StoreGPRRegister(Reg, NZCVSelect(OpSize::i64Bit, {COND_NEQ}, Value, LoadGPRRegister(Reg))); |
| 3899 | }; |
| 3900 | |
| 3901 | UpdateIfNotZF(X86State::REG_RAX, Result_Lower); |
| 3902 | UpdateIfNotZF(X86State::REG_RDX, Result_Upper); |
| 3903 | } |
| 3904 | |
| 3905 | void OpDispatchBuilder::CreateJumpBlocks(const fextl::vector<FEXCore::Frontend::Decoder::DecodedBlocks>* Blocks) { |
| 3906 | Ref PrevCodeBlock {}; |
nothing calls this directly
no outgoing calls
no test coverage detected