| 2722 | } |
| 2723 | |
| 2724 | void OpDispatchBuilder::NOTOp(OpcodeArgs) { |
| 2725 | const auto Size = OpSizeFromSrc(Op); |
| 2726 | const auto SizeBits = IR::OpSizeAsBits(Size); |
| 2727 | LOGMAN_THROW_A_FMT(Size >= IR::OpSize::i8Bit && Size <= IR::OpSize::i64Bit, "Invalid size"); |
| 2728 | |
| 2729 | Ref MaskConst {}; |
| 2730 | if (Size == OpSize::i64Bit) { |
| 2731 | MaskConst = Constant(~0ULL); |
| 2732 | } else { |
| 2733 | MaskConst = Constant((1ULL << SizeBits) - 1); |
| 2734 | } |
| 2735 | |
| 2736 | if (DestIsLockedMem(Op)) { |
| 2737 | HandledLock = true; |
| 2738 | Ref DestMem = MakeSegmentAddress(Op, Op->Dest); |
| 2739 | _AtomicXor(Size, MaskConst, DestMem); |
| 2740 | } else if (!Op->Dest.IsGPR()) { |
| 2741 | // GPR version plays fast and loose with sizes, be safe for memory tho. |
| 2742 | Ref Src = LoadSource(GPRClass, Op, Op->Dest, Op->Flags); |
| 2743 | Src = _Xor(OpSize::i64Bit, Src, MaskConst); |
| 2744 | StoreResult(GPRClass, Op, Src, OpSize::iInvalid); |
| 2745 | } else { |
| 2746 | // Specially handle high bits so we can invert in place with the correct |
| 2747 | // mask and a larger type. |
| 2748 | auto Dest = Op->Dest; |
| 2749 | if (Dest.Data.GPR.HighBits) { |
| 2750 | LOGMAN_THROW_A_FMT(Size == OpSize::i8Bit, "Only 8-bit GPRs get high bits"); |
| 2751 | MaskConst = Constant(0xFF00); |
| 2752 | Dest.Data.GPR.HighBits = false; |
| 2753 | } |
| 2754 | |
| 2755 | // Always load full size, we explicitly want the upper bits to get the |
| 2756 | // insert behaviour for free/implicitly. |
| 2757 | const auto GPRSize = GetGPROpSize(); |
| 2758 | Ref Src = LoadSource_WithOpSize(GPRClass, Op, Dest, GPRSize, Op->Flags); |
| 2759 | |
| 2760 | // For 8/16-bit, use 64-bit invert so we invert in place, while getting |
| 2761 | // insert behaviour. For 32-bit, use 32-bit invert to zero the upper bits. |
| 2762 | const auto EffectiveSize = Size == OpSize::i32Bit ? OpSize::i32Bit : GPRSize; |
| 2763 | |
| 2764 | // If we're inverting the whole thing, use Not instead of Xor to save a constant. |
| 2765 | if (Size >= OpSize::i32Bit) { |
| 2766 | Src = _Not(EffectiveSize, Src); |
| 2767 | } else { |
| 2768 | Src = _Xor(EffectiveSize, Src, MaskConst); |
| 2769 | } |
| 2770 | |
| 2771 | // Always store 64-bit, the Not/Xor correctly handle the upper bits and this |
| 2772 | // way we can delete the store. |
| 2773 | StoreResult_WithOpSize(GPRClass, Op, Dest, Src, GPRSize, OpSize::iInvalid); |
| 2774 | } |
| 2775 | } |
| 2776 | |
| 2777 | void OpDispatchBuilder::XADDOp(OpcodeArgs) { |
| 2778 | Ref Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.LoadData = false}); |
nothing calls this directly
no test coverage detected