| 2619 | } |
| 2620 | |
| 2621 | void OpDispatchBuilder::IMULOp(OpcodeArgs) { |
| 2622 | const auto Size = OpSizeFromSrc(Op); |
| 2623 | const auto SizeBits = IR::OpSizeAsBits(Size); |
| 2624 | |
| 2625 | Ref Src1 = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = true}); |
| 2626 | Ref Src2 = LoadGPRRegister(X86State::REG_RAX); |
| 2627 | |
| 2628 | if (Size != OpSize::i64Bit) { |
| 2629 | Src1 = _Sbfe(OpSize::i64Bit, SizeBits, 0, Src1); |
| 2630 | Src2 = _Sbfe(OpSize::i64Bit, SizeBits, 0, Src2); |
| 2631 | } |
| 2632 | |
| 2633 | // 64-bit special cased to save a move |
| 2634 | Ref Result = Size < OpSize::i64Bit ? _Mul(OpSize::i64Bit, Src1, Src2) : nullptr; |
| 2635 | Ref ResultHigh {}; |
| 2636 | if (Size == OpSize::i8Bit) { |
| 2637 | // Result is stored in AX |
| 2638 | StoreGPRRegister(X86State::REG_RAX, Result, OpSize::i16Bit); |
| 2639 | ResultHigh = _Sbfe(OpSize::i64Bit, 8, 8, Result); |
| 2640 | } else if (Size == OpSize::i16Bit) { |
| 2641 | // 16bits stored in AX |
| 2642 | // 16bits stored in DX |
| 2643 | StoreGPRRegister(X86State::REG_RAX, Result, Size); |
| 2644 | ResultHigh = _Sbfe(OpSize::i64Bit, 16, 16, Result); |
| 2645 | StoreGPRRegister(X86State::REG_RDX, ResultHigh, Size); |
| 2646 | } else if (Size == OpSize::i32Bit) { |
| 2647 | // 32bits stored in EAX |
| 2648 | // 32bits stored in EDX |
| 2649 | // Make sure they get Zext correctly |
| 2650 | auto LocalResult = _Bfe(OpSize::i64Bit, 32, 0, Result); |
| 2651 | auto LocalResultHigh = _Bfe(OpSize::i64Bit, 32, 32, Result); |
| 2652 | ResultHigh = _Sbfe(OpSize::i64Bit, 32, 32, Result); |
| 2653 | Result = _Sbfe(OpSize::i64Bit, 32, 0, Result); |
| 2654 | StoreGPRRegister(X86State::REG_RAX, LocalResult); |
| 2655 | StoreGPRRegister(X86State::REG_RDX, LocalResultHigh); |
| 2656 | } else if (Size == OpSize::i64Bit) { |
| 2657 | if (!Is64BitMode) { |
| 2658 | LogMan::Msg::EFmt("Doesn't exist in 32bit mode"); |
| 2659 | DecodeFailure = true; |
| 2660 | return; |
| 2661 | } |
| 2662 | // 64bits stored in RAX |
| 2663 | // 64bits stored in RDX |
| 2664 | ResultHigh = _MulH(OpSize::i64Bit, Src1, Src2); |
| 2665 | Result = _Mul(OpSize::i64Bit, Src1, Src2); |
| 2666 | StoreGPRRegister(X86State::REG_RAX, Result); |
| 2667 | StoreGPRRegister(X86State::REG_RDX, ResultHigh); |
| 2668 | } |
| 2669 | |
| 2670 | CalculateFlags_MUL(Size, Result, ResultHigh); |
| 2671 | } |
| 2672 | |
| 2673 | void OpDispatchBuilder::MULOp(OpcodeArgs) { |
| 2674 | const auto Size = OpSizeFromSrc(Op); |
nothing calls this directly
no test coverage detected