mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-23 11:00:48 +02:00
Vector: Optimize PSHUFD with brute force search
With a brute force search of methods between 1-3 instructions we cover a lot more cases more optimally. There's definitely still more cases (and probably some that can reduce from 3 instruction to 2), but covering 44 cases is a pretty good margin already.
This commit is contained in:
1 file changed
+186
-6
@@ -1012,6 +1012,66 @@ Ref OpDispatchBuilder::Single128Bit4ByteVectorShuffle(Ref Src, uint8_t Shuffle)
|
||||
// Special case identity copy.
|
||||
return Src;
|
||||
}
|
||||
case 0b00'00'00'00:
|
||||
case 0b01'01'01'01:
|
||||
case 0b10'10'10'10:
|
||||
case 0b11'11'11'11: {
|
||||
// Special case element duplicate and broadcast to low or high 64-bits.
|
||||
return _VDupElement(OpSize::i128Bit, OpSize::i32Bit, Src, Shuffle & 0b11);
|
||||
}
|
||||
|
||||
case 0b00'00'10'10: {
|
||||
// Weird reverse low elements and broadcast to each half of the register
|
||||
Ref Tmp = _VUnZip(OpSize::i128Bit, OpSize::i32Bit, Src, Src);
|
||||
Tmp = _VRev64(OpSize::i128Bit, OpSize::i32Bit, Tmp);
|
||||
return _VZip(OpSize::i128Bit, OpSize::i32Bit, Tmp, Tmp);
|
||||
}
|
||||
case 0b00'01'00'01: {
|
||||
///< Weird reversed low elements and broadcast
|
||||
Ref Tmp = _VRev64(OpSize::i128Bit, OpSize::i32Bit, Src);
|
||||
return _VZip(OpSize::i128Bit, OpSize::i64Bit, Tmp, Tmp);
|
||||
}
|
||||
case 0b00'01'01'00: {
|
||||
///< Weird reverse low two elements in to high half
|
||||
Ref Tmp = _VZip(OpSize::i128Bit, OpSize::i32Bit, Src, Src);
|
||||
return _VExtr(OpSize::i128Bit, OpSize::i8Bit, Tmp, Tmp, 4);
|
||||
}
|
||||
case 0b00'10'00'10: {
|
||||
///< Weird reversed even elements and broadcast
|
||||
Ref Tmp = _VUnZip(OpSize::i128Bit, OpSize::i32Bit, Src, Src);
|
||||
return _VExtr(OpSize::i128Bit, OpSize::i8Bit, Tmp, Tmp, 4);
|
||||
}
|
||||
case 0b00'10'10'00: {
|
||||
// Weird reversed low elements in upper half of the register
|
||||
Ref Tmp = _VUnZip(OpSize::i128Bit, OpSize::i32Bit, Src, Src);
|
||||
Tmp = _VZip(OpSize::i128Bit, OpSize::i32Bit, Tmp, Tmp);
|
||||
return _VExtr(OpSize::i128Bit, OpSize::i8Bit, Tmp, Tmp, 4);
|
||||
}
|
||||
case 0b00'11'00'11: {
|
||||
///< Weird Low plus high element reversed and broadcast
|
||||
Ref Tmp = _VExtr(OpSize::i128Bit, OpSize::i8Bit, Src, Src, 4);
|
||||
return _VZip2(OpSize::i128Bit, OpSize::i64Bit, Tmp, Tmp);
|
||||
}
|
||||
case 0b00'11'10'01:
|
||||
///< Vector rotate - One element
|
||||
return _VExtr(OpSize::i128Bit, OpSize::i8Bit, Src, Src, 4);
|
||||
case 0b00'11'11'00: {
|
||||
// Weird reversed low and high elements in upper half of the register
|
||||
Ref Tmp = _VExtr(OpSize::i128Bit, OpSize::i8Bit, Src, Src, 4);
|
||||
Tmp = _VZip2(OpSize::i128Bit, OpSize::i32Bit, Tmp, Tmp);
|
||||
return _VExtr(OpSize::i128Bit, OpSize::i8Bit, Tmp, Tmp, 12);
|
||||
}
|
||||
case 0b01'00'00'01: {
|
||||
///< Weird duplicate bottom two elements, then rotate in the low half
|
||||
Ref Tmp = _VZip(OpSize::i128Bit, OpSize::i32Bit, Src, Src);
|
||||
return _VExtr(OpSize::i128Bit, OpSize::i8Bit, Tmp, Tmp, 12);
|
||||
}
|
||||
case 0b01'00'01'00:
|
||||
///< Duplicate bottom 64-bits
|
||||
return _VDupElement(OpSize::i128Bit, OpSize::i64Bit, Src, 0);
|
||||
case 0b01'00'11'10:
|
||||
///< Vector rotate - Two elements
|
||||
return _VExtr(OpSize::i128Bit, OpSize::i8Bit, Src, Src, 8);
|
||||
case 0b01'01'00'00: {
|
||||
// Zip with self.
|
||||
// Dest[0] = Src[0]
|
||||
@@ -1020,13 +1080,133 @@ Ref OpDispatchBuilder::Single128Bit4ByteVectorShuffle(Ref Src, uint8_t Shuffle)
|
||||
// Dest[3] = Src[1]
|
||||
return _VZip(OpSize::i128Bit, OpSize::i32Bit, Src, Src);
|
||||
}
|
||||
case 0b00'00'00'00:
|
||||
case 0b01'01'01'01:
|
||||
case 0b10'10'10'10:
|
||||
case 0b11'11'11'11: {
|
||||
// Special case element duplicate and broadcast to low or high 64-bits.
|
||||
return _VDupElement(OpSize::i128Bit, OpSize::i32Bit, Src, Shuffle & 0b11);
|
||||
case 0b01'01'10'10: {
|
||||
///< Weird reverse middle elements and broadcast to each half of the register
|
||||
Ref Tmp = _VExtr(OpSize::i128Bit, OpSize::i8Bit, Src, Src, 4);
|
||||
Tmp = _VRev64(OpSize::i128Bit, OpSize::i32Bit, Tmp);
|
||||
return _VZip(OpSize::i128Bit, OpSize::i32Bit, Tmp, Tmp);
|
||||
}
|
||||
case 0b01'01'11'11: {
|
||||
///< Weird reverse odd elements and broadcast to each half of the register
|
||||
Ref Tmp = _VUnZip2(OpSize::i128Bit, OpSize::i32Bit, Src, Src);
|
||||
Tmp = _VRev64(OpSize::i128Bit, OpSize::i32Bit, Tmp);
|
||||
return _VZip(OpSize::i128Bit, OpSize::i32Bit, Tmp, Tmp);
|
||||
}
|
||||
case 0b01'10'01'10: {
|
||||
///< Weird middle elements swizzle plus broadcast
|
||||
Ref Tmp = _VExtr(OpSize::i128Bit, OpSize::i8Bit, Src, Src, 4);
|
||||
Tmp = _VRev64(OpSize::i128Bit, OpSize::i32Bit, Tmp);
|
||||
return _VZip(OpSize::i128Bit, OpSize::i64Bit, Tmp, Tmp);
|
||||
}
|
||||
case 0b01'10'10'01: {
|
||||
///< Weird middle elements swizzle plus broadcast and reverse
|
||||
Ref Tmp = _VExtr(OpSize::i128Bit, OpSize::i8Bit, Src, Src, 4);
|
||||
Tmp = _VZip(OpSize::i128Bit, OpSize::i32Bit, Tmp, Tmp);
|
||||
return _VExtr(OpSize::i128Bit, OpSize::i8Bit, Tmp, Tmp, 4);
|
||||
}
|
||||
case 0b01'11'01'11: {
|
||||
///< Weird reversed odd elements and broadcast
|
||||
Ref Tmp = _VUnZip2(OpSize::i128Bit, OpSize::i32Bit, Src, Src);
|
||||
return _VExtr(OpSize::i128Bit, OpSize::i8Bit, Tmp, Tmp, 4);
|
||||
}
|
||||
case 0b01'11'11'01: {
|
||||
///< Weird odd elements swizzle plus broadcast and reverse
|
||||
Ref Tmp = _VUnZip2(OpSize::i128Bit, OpSize::i32Bit, Src, Src);
|
||||
Tmp = _VZip(OpSize::i128Bit, OpSize::i32Bit, Tmp, Tmp);
|
||||
return _VExtr(OpSize::i128Bit, OpSize::i8Bit, Tmp, Tmp, 4);
|
||||
}
|
||||
case 0b10'00'00'10: {
|
||||
///< Weird even elements swizzle plus broadcast and reverse
|
||||
Ref Tmp = _VUnZip(OpSize::i128Bit, OpSize::i32Bit, Src, Src);
|
||||
Tmp = _VZip(OpSize::i128Bit, OpSize::i32Bit, Tmp, Tmp);
|
||||
return _VExtr(OpSize::i128Bit, OpSize::i8Bit, Tmp, Tmp, 12);
|
||||
}
|
||||
case 0b10'00'10'00:
|
||||
///< Even elements broadcast
|
||||
return _VUnZip(OpSize::i128Bit, OpSize::i32Bit, Src, Src);
|
||||
case 0b10'01'00'11:
|
||||
///< Vector rotate - Three elements
|
||||
return _VExtr(OpSize::i128Bit, OpSize::i8Bit, Src, Src, 12);
|
||||
|
||||
case 0b10'01'01'10: {
|
||||
///< Weird odd elements swizzle plus broadcast and reverse
|
||||
Ref Tmp = _VExtr(OpSize::i128Bit, OpSize::i8Bit, Src, Src, 4);
|
||||
Tmp = _VZip(OpSize::i128Bit, OpSize::i32Bit, Tmp, Tmp);
|
||||
return _VExtr(OpSize::i128Bit, OpSize::i8Bit, Tmp, Tmp, 12);
|
||||
}
|
||||
case 0b10'01'10'01: {
|
||||
///< Middle two elements broadcast
|
||||
Ref Tmp = _VExtr(OpSize::i128Bit, OpSize::i8Bit, Src, Src, 4);
|
||||
return _VZip(OpSize::i128Bit, OpSize::i64Bit, Tmp, Tmp);
|
||||
}
|
||||
case 0b10'10'00'00: {
|
||||
///< Broadcast even elements to each half of the register
|
||||
Ref Tmp = _VUnZip(OpSize::i128Bit, OpSize::i32Bit, Src, Src);
|
||||
return _VZip(OpSize::i128Bit, OpSize::i32Bit, Tmp, Tmp);
|
||||
}
|
||||
case 0b10'10'01'01: {
|
||||
///< Broadcast middle elements to each half of the register
|
||||
Ref Tmp = _VExtr(OpSize::i128Bit, OpSize::i8Bit, Src, Src, 4);
|
||||
return _VZip(OpSize::i128Bit, OpSize::i32Bit, Tmp, Tmp);
|
||||
}
|
||||
case 0b10'10'11'11: {
|
||||
///< Reverse top two elements and broadcast to each half of the register
|
||||
Ref Tmp = _VZip2(OpSize::i128Bit, OpSize::i32Bit, Src, Src);
|
||||
return _VExtr(OpSize::i128Bit, OpSize::i8Bit, Tmp, Tmp, 8);
|
||||
}
|
||||
case 0b10'11'10'11: {
|
||||
///< Weird top two elements reverse and broadcast
|
||||
Ref Tmp = _VZip2(OpSize::i128Bit, OpSize::i64Bit, Src, Src);
|
||||
return _VExtr(OpSize::i128Bit, OpSize::i8Bit, Tmp, Tmp, 4);
|
||||
}
|
||||
case 0b10'11'11'10: {
|
||||
///< Weird move top two elements to bottom and reverse in the top half
|
||||
Ref Tmp = _VZip2(OpSize::i128Bit, OpSize::i32Bit, Src, Src);
|
||||
return _VExtr(OpSize::i128Bit, OpSize::i8Bit, Tmp, Tmp, 4);
|
||||
}
|
||||
case 0b11'00'00'11: {
|
||||
///< Weird low plus high elements swizzle plus broadcast and reverse
|
||||
Ref Tmp = _VExtr(OpSize::i128Bit, OpSize::i8Bit, Src, Src, 4);
|
||||
Tmp = _VZip2(OpSize::i128Bit, OpSize::i32Bit, Tmp, Tmp);
|
||||
return _VExtr(OpSize::i128Bit, OpSize::i8Bit, Tmp, Tmp, 4);
|
||||
}
|
||||
case 0b11'00'11'00: {
|
||||
///< Weird low plus high element broadcast
|
||||
Ref Tmp = _VExtr(OpSize::i128Bit, OpSize::i8Bit, Src, Src, 4);
|
||||
Tmp = _VZip2(OpSize::i128Bit, OpSize::i64Bit, Tmp, Tmp);
|
||||
return _VExtr(OpSize::i128Bit, OpSize::i8Bit, Tmp, Tmp, 4);
|
||||
}
|
||||
case 0b11'01'01'11: {
|
||||
///< Weird odd elements swizzle plus broadcast and reverse
|
||||
Ref Tmp = _VUnZip2(OpSize::i128Bit, OpSize::i32Bit, Src, Src);
|
||||
Tmp = _VZip(OpSize::i128Bit, OpSize::i32Bit, Tmp, Tmp);
|
||||
return _VExtr(OpSize::i128Bit, OpSize::i8Bit, Tmp, Tmp, 12);
|
||||
}
|
||||
case 0b11'01'11'01:
|
||||
///< Odd elements broadcast
|
||||
return _VUnZip2(OpSize::i128Bit, OpSize::i32Bit, Src, Src);
|
||||
case 0b11'10'10'11: {
|
||||
///< Rotate top two elements in to bottom half of the register
|
||||
Ref Tmp = _VZip2(OpSize::i128Bit, OpSize::i32Bit, Src, Src);
|
||||
return _VExtr(OpSize::i128Bit, OpSize::i8Bit, Tmp, Tmp, 12);
|
||||
}
|
||||
case 0b11'10'11'10:
|
||||
///< Duplicate Top 64-bits
|
||||
return _VDupElement(OpSize::i128Bit, OpSize::i64Bit, Src, 1);
|
||||
case 0b11'11'00'00: {
|
||||
///< Weird Broadcast bottom and top element to each half of the register
|
||||
Ref Tmp = _VExtr(OpSize::i128Bit, OpSize::i8Bit, Src, Src, 12);
|
||||
Tmp = _VRev64(OpSize::i128Bit, OpSize::i32Bit, Tmp);
|
||||
return _VZip(OpSize::i128Bit, OpSize::i32Bit, Tmp, Tmp);
|
||||
}
|
||||
case 0b11'11'01'01: {
|
||||
///< Broadcast odd elements to each half of the register
|
||||
Ref Tmp = _VUnZip2(OpSize::i128Bit, OpSize::i32Bit, Src, Src);
|
||||
return _VZip(OpSize::i128Bit, OpSize::i32Bit, Tmp, Tmp);
|
||||
}
|
||||
case 0b11'11'10'10:
|
||||
///< Broadcast top two elements to each half of the register
|
||||
return _VZip2(OpSize::i128Bit, OpSize::i32Bit, Src, Src);
|
||||
default: {
|
||||
// PSHUFD needs to scale index by 16.
|
||||
auto LookupIndexes =
|
||||
|
||||
Reference in new issue
Block a user