| 655 | } |
| 656 | |
| 657 | void OpDispatchBuilder::CMOVOp(OpcodeArgs) { |
| 658 | const auto GPRSize = GetGPROpSize(); |
| 659 | const auto OP = Op->OP & 0xF; |
| 660 | const auto ResultSize = std::max(OpSize::i32Bit, OpSizeFromSrc(Op)); |
| 661 | |
| 662 | CalculateDeferredFlags(); |
| 663 | |
| 664 | // Destination is always a GPR. |
| 665 | Ref Dest = LoadSource_WithOpSize(GPRClass, Op, Op->Dest, GPRSize, Op->Flags); |
| 666 | Ref Src {}, SrcCond {}; |
| 667 | if (Op->Src[0].IsGPR()) { |
| 668 | Src = LoadSource_WithOpSize(GPRClass, Op, Op->Src[0], GPRSize, Op->Flags); |
| 669 | } else { |
| 670 | Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); |
| 671 | } |
| 672 | |
| 673 | if (auto Cond = DecodeNZCVCondition(OP); Cond) { |
| 674 | // Use raw select since DecodeNZCVCondition handles the carry invert |
| 675 | SrcCond = _NZCVSelect(ResultSize, *Cond, Src, Dest); |
| 676 | } else { |
| 677 | // Raw value contains inverted PF in bottom bit |
| 678 | Ref Cmp = LoadPFRaw(false, ParityJumpIsJP(OP)); |
| 679 | SaveNZCV(); |
| 680 | |
| 681 | // Because we're only clobbering NZCV internally, we ignore all carry flag |
| 682 | // shenanigans and just use the raw test and raw select. |
| 683 | _TestNZ(OpSize::i32Bit, Cmp, _InlineConstant(1)); |
| 684 | SrcCond = _NZCVSelect(ResultSize, {COND_NEQ}, Src, Dest); |
| 685 | } |
| 686 | |
| 687 | StoreResult(GPRClass, Op, SrcCond, OpSize::iInvalid); |
| 688 | } |
| 689 | |
| 690 | void OpDispatchBuilder::CondJUMPOp(OpcodeArgs) { |
| 691 | // Calculate flags early. |
nothing calls this directly
no test coverage detected