| 908 | } |
| 909 | |
| 910 | Ref OpDispatchBuilder::PShufWLane(IR::OpSize Size, FEXCore::IR::IndexNamedVectorConstant IndexConstant, bool LowLane, Ref IncomingLane, |
| 911 | uint8_t Shuffle) { |
| 912 | constexpr auto IdentityCopy = 0b11'10'01'00; |
| 913 | |
| 914 | const bool Is128BitLane = Size == OpSize::i128Bit; |
| 915 | const auto NumElements = IR::NumElements(Size, IR::OpSize::i16Bit); |
| 916 | const auto HalfNumElements = NumElements >> 1; |
| 917 | |
| 918 | // TODO: There can be more optimized copies here. |
| 919 | switch (Shuffle) { |
| 920 | case IdentityCopy: { |
| 921 | // Special case identity copy. |
| 922 | return IncomingLane; |
| 923 | } |
| 924 | case 0b00'00'00'00: |
| 925 | case 0b01'01'01'01: |
| 926 | case 0b10'10'10'10: |
| 927 | case 0b11'11'11'11: { |
| 928 | // Special case element duplicate and broadcast to low or high 64-bits. |
| 929 | Ref Dup = _VDupElement(Size, OpSize::i16Bit, IncomingLane, (LowLane ? 0 : HalfNumElements) + (Shuffle & 0b11)); |
| 930 | if (Is128BitLane) { |
| 931 | if (LowLane) { |
| 932 | // DUP goes low. |
| 933 | // Source goes high. |
| 934 | Dup = _VTrn2(Size, OpSize::i64Bit, Dup, IncomingLane); |
| 935 | } else { |
| 936 | // DUP goes high. |
| 937 | // Source goes low. |
| 938 | Dup = _VTrn(Size, OpSize::i64Bit, IncomingLane, Dup); |
| 939 | } |
| 940 | } |
| 941 | |
| 942 | return Dup; |
| 943 | } |
| 944 | default: { |
| 945 | // PSHUFLW needs to scale index by 16. |
| 946 | // PSHUFHW needs to scale index by 16. |
| 947 | // PSHUFW (mmx) also needs to scale by 16 to get correct low element. |
| 948 | auto LookupIndexes = LoadAndCacheIndexedNamedVectorConstant(Size, IndexConstant, Shuffle * 16); |
| 949 | return _VTBL1(Size, IncomingLane, LookupIndexes); |
| 950 | } |
| 951 | } |
| 952 | } |
| 953 | |
| 954 | void OpDispatchBuilder::PSHUFW8ByteOp(OpcodeArgs) { |
| 955 | uint16_t Shuffle = Op->Src[1].Data.Literal.Value; |
no test coverage detected