| 1569 | } |
| 1570 | |
| 1571 | Ref OpDispatchBuilder::InsertPSOpImpl(OpcodeArgs, const X86Tables::DecodedOperand& Src1, const X86Tables::DecodedOperand& Src2, |
| 1572 | const X86Tables::DecodedOperand& Imm) { |
| 1573 | const uint8_t ImmValue = Imm.Literal(); |
| 1574 | uint8_t CountS = (ImmValue >> 6); |
| 1575 | uint8_t CountD = (ImmValue >> 4) & 0b11; |
| 1576 | const uint8_t ZMask = ImmValue & 0xF; |
| 1577 | |
| 1578 | const auto DstSize = OpSizeFromDst(Op); |
| 1579 | |
| 1580 | Ref Dest {}; |
| 1581 | if (ZMask != 0xF) { |
| 1582 | // Only need to load destination if it isn't a full zero |
| 1583 | Dest = LoadSource_WithOpSize(FPRClass, Op, Src1, DstSize, Op->Flags); |
| 1584 | } |
| 1585 | |
| 1586 | if ((ZMask & (1 << CountD)) == 0) { |
| 1587 | // In the case that ZMask overwrites the destination element, then don't even insert |
| 1588 | Ref Src {}; |
| 1589 | if (Src2.IsGPR()) { |
| 1590 | Src = LoadSource(FPRClass, Op, Src2, Op->Flags); |
| 1591 | } else { |
| 1592 | // If loading from memory then CountS is forced to zero |
| 1593 | CountS = 0; |
| 1594 | Src = LoadSource_WithOpSize(FPRClass, Op, Src2, OpSize::i32Bit, Op->Flags); |
| 1595 | } |
| 1596 | |
| 1597 | Dest = _VInsElement(DstSize, OpSize::i32Bit, CountD, CountS, Dest, Src); |
| 1598 | } |
| 1599 | |
| 1600 | // ZMask happens after insert |
| 1601 | if (ZMask == 0xF) { |
| 1602 | return LoadZeroVector(DstSize); |
| 1603 | } |
| 1604 | |
| 1605 | if (ZMask) { |
| 1606 | auto Zero = LoadZeroVector(DstSize); |
| 1607 | for (size_t i = 0; i < 4; ++i) { |
| 1608 | if ((ZMask & (1 << i)) != 0) { |
| 1609 | Dest = _VInsElement(DstSize, OpSize::i32Bit, i, 0, Dest, Zero); |
| 1610 | } |
| 1611 | } |
| 1612 | } |
| 1613 | |
| 1614 | return Dest; |
| 1615 | } |
| 1616 | |
| 1617 | void OpDispatchBuilder::InsertPSOp(OpcodeArgs) { |
| 1618 | Ref Result = InsertPSOpImpl(Op, Op->Dest, Op->Src[0], Op->Src[1]); |