| 3630 | } |
| 3631 | |
| 3632 | void OpDispatchBuilder::DIVOp(OpcodeArgs) { |
| 3633 | const auto GPRSize = GetGPROpSize(); |
| 3634 | auto Size = OpSizeFromSrc(Op); |
| 3635 | |
| 3636 | // This loads the divisor. 32-bit/64-bit paths mask inside the JIT, 8/16 do not. |
| 3637 | Ref Divisor = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = Size >= OpSize::i32Bit}); |
| 3638 | |
| 3639 | if (Size == OpSize::i64Bit && !Is64BitMode) { |
| 3640 | LogMan::Msg::EFmt("Doesn't exist in 32bit mode"); |
| 3641 | DecodeFailure = true; |
| 3642 | return; |
| 3643 | } |
| 3644 | |
| 3645 | Ref Quotient = _AllocateGPR(true); |
| 3646 | Ref Remainder = _AllocateGPR(true); |
| 3647 | |
| 3648 | if (Size == OpSize::i8Bit) { |
| 3649 | Ref Src1 = LoadGPRRegister(X86State::REG_RAX, OpSize::i16Bit); |
| 3650 | |
| 3651 | _UDiv(OpSize::i16Bit, Src1, Invalid(), Divisor, Quotient, Remainder); |
| 3652 | |
| 3653 | // AX[15:0] = concat<URem[7:0]:UDiv[7:0]> |
| 3654 | auto ResultAX = _Bfi(GPRSize, 8, 8, Quotient, Remainder); |
| 3655 | StoreGPRRegister(X86State::REG_RAX, ResultAX, OpSize::i16Bit); |
| 3656 | } else { |
| 3657 | Ref Src1 = LoadGPRRegister(X86State::REG_RAX); |
| 3658 | Ref Src2 = LoadGPRRegister(X86State::REG_RDX); |
| 3659 | |
| 3660 | _UDiv(Size, Src1, Src2, Divisor, Quotient, Remainder); |
| 3661 | |
| 3662 | if (Size == OpSize::i32Bit) { |
| 3663 | Quotient = _Bfe(OpSize::i32Bit, IR::OpSizeAsBits(Size), 0, Quotient); |
| 3664 | Remainder = _Bfe(OpSize::i32Bit, IR::OpSizeAsBits(Size), 0, Remainder); |
| 3665 | Size = OpSize::iInvalid; |
| 3666 | } |
| 3667 | |
| 3668 | StoreGPRRegister(X86State::REG_RAX, Quotient, Size); |
| 3669 | StoreGPRRegister(X86State::REG_RDX, Remainder, Size); |
| 3670 | } |
| 3671 | } |
| 3672 | |
| 3673 | void OpDispatchBuilder::IDIVOp(OpcodeArgs) { |
| 3674 | // This loads the divisor |
nothing calls this directly
no test coverage detected