mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-24 08:00:43 +02:00
AVX128: Improve VPERMILPS/PD and VPSHUFD
VPSHUFD and VPERMILPS are aliases of each other. Reuses the implementation path from the PSHUFD implementation which has a few swizzles and then a table lookup. VPERMILPD is a very simple swizzle per 128-bit lane. Fixes #3797 Fixes #3784
This commit is contained in:
3 files changed
+29
-30
No files matched your search
@@ -958,6 +958,8 @@ public:
|
||||
void UnimplementedOp(OpcodeArgs);
|
||||
void PermissionRestrictedOp(OpcodeArgs);
|
||||
|
||||
///< Helper for PSHUD and VPERMILPS(imm) since they are the same instruction
|
||||
Ref Single128Bit4ByteVectorShuffle(Ref Src, uint8_t Shuffle);
|
||||
// AVX 128-bit operations
|
||||
Ref AVX128_LoadXMMRegister(uint32_t XMM, bool High);
|
||||
void AVX128_StoreXMMRegister(uint32_t XMM, const Ref Src, bool High);
|
||||
|
||||
@@ -158,7 +158,7 @@ void OpDispatchBuilder::InstallAVX128Handlers() {
|
||||
{OPD(1, 0b01, 0x6F), 1, &OpDispatchBuilder::AVX128_VMOVAPS},
|
||||
{OPD(1, 0b10, 0x6F), 1, &OpDispatchBuilder::AVX128_VMOVAPS},
|
||||
|
||||
{OPD(1, 0b01, 0x70), 1, &OpDispatchBuilder::AVX128_VPSHUF<4, true>},
|
||||
{OPD(1, 0b01, 0x70), 1, &OpDispatchBuilder::AVX128_VPERMILImm<4>},
|
||||
{OPD(1, 0b10, 0x70), 1, &OpDispatchBuilder::AVX128_VPSHUF<2, false>},
|
||||
{OPD(1, 0b11, 0x70), 1, &OpDispatchBuilder::AVX128_VPSHUF<2, true>},
|
||||
|
||||
@@ -1937,26 +1937,28 @@ void OpDispatchBuilder::AVX128_VPERMILImm(OpcodeArgs) {
|
||||
|
||||
RefPair Result = AVX128_Zext(LoadZeroVector(OpSize::i128Bit));
|
||||
|
||||
///< TODO: This could be optimized.
|
||||
if constexpr (ElementSize == OpSize::i64Bit) {
|
||||
Result.Low = _VInsElement(OpSize::i128Bit, ElementSize, 0, Selector & 0b0001, Result.Low, Src.Low);
|
||||
Result.Low = _VInsElement(OpSize::i128Bit, ElementSize, 1, (Selector & 0b0010) >> 1, Result.Low, Src.Low);
|
||||
auto DoSwizzle64 = [this](Ref Src, uint8_t Selector) -> Ref {
|
||||
switch (Selector) {
|
||||
case 0b00:
|
||||
case 0b11: return _VDupElement(OpSize::i128Bit, OpSize::i64Bit, Src, Selector & 1);
|
||||
case 0b01: return _VExtr(OpSize::i128Bit, OpSize::i8Bit, Src, Src, 8);
|
||||
case 0b10:
|
||||
// No swizzle
|
||||
return Src;
|
||||
default: FEX_UNREACHABLE;
|
||||
}
|
||||
};
|
||||
Result.Low = DoSwizzle64(Src.Low, Selector & 0b11);
|
||||
|
||||
if (!Is128Bit) {
|
||||
Result.High = _VInsElement(OpSize::i128Bit, ElementSize, 0, ((Selector & 0b0100) >> 2), Result.High, Src.High);
|
||||
Result.High = _VInsElement(OpSize::i128Bit, ElementSize, 1, ((Selector & 0b1000) >> 3), Result.High, Src.High);
|
||||
Result.High = DoSwizzle64(Src.High, (Selector >> 2) & 0b11);
|
||||
}
|
||||
} else {
|
||||
Result.Low = _VInsElement(OpSize::i128Bit, ElementSize, 0, Selector & 0b00000011, Result.Low, Src.Low);
|
||||
Result.Low = _VInsElement(OpSize::i128Bit, ElementSize, 1, (Selector & 0b00001100) >> 2, Result.Low, Src.Low);
|
||||
Result.Low = _VInsElement(OpSize::i128Bit, ElementSize, 2, (Selector & 0b00110000) >> 4, Result.Low, Src.Low);
|
||||
Result.Low = _VInsElement(OpSize::i128Bit, ElementSize, 3, (Selector & 0b11000000) >> 6, Result.Low, Src.Low);
|
||||
Result.Low = Single128Bit4ByteVectorShuffle(Src.Low, Selector);
|
||||
|
||||
if (!Is128Bit) {
|
||||
Result.High = _VInsElement(OpSize::i128Bit, ElementSize, 0, (Selector & 0b00000011), Result.High, Src.High);
|
||||
Result.High = _VInsElement(OpSize::i128Bit, ElementSize, 1, ((Selector & 0b00001100) >> 2), Result.High, Src.High);
|
||||
Result.High = _VInsElement(OpSize::i128Bit, ElementSize, 2, ((Selector & 0b00110000) >> 4), Result.High, Src.High);
|
||||
Result.High = _VInsElement(OpSize::i128Bit, ElementSize, 3, ((Selector & 0b11000000) >> 6), Result.High, Src.High);
|
||||
Result.High = Single128Bit4ByteVectorShuffle(Src.High, Selector);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1003,20 +1003,14 @@ void OpDispatchBuilder::PSHUFWOp(OpcodeArgs) {
|
||||
template void OpDispatchBuilder::PSHUFWOp<false>(OpcodeArgs);
|
||||
template void OpDispatchBuilder::PSHUFWOp<true>(OpcodeArgs);
|
||||
|
||||
void OpDispatchBuilder::PSHUFDOp(OpcodeArgs) {
|
||||
Ref OpDispatchBuilder::Single128Bit4ByteVectorShuffle(Ref Src, uint8_t Shuffle) {
|
||||
constexpr auto IdentityCopy = 0b11'10'01'00;
|
||||
|
||||
uint16_t Shuffle = Op->Src[1].Data.Literal.Value;
|
||||
const auto Size = GetSrcSize(Op);
|
||||
Ref Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags);
|
||||
Ref Dest {};
|
||||
|
||||
// TODO: There can be more optimized copies here.
|
||||
switch (Shuffle) {
|
||||
case IdentityCopy: {
|
||||
// Special case identity copy.
|
||||
Dest = Src;
|
||||
break;
|
||||
return Src;
|
||||
}
|
||||
case 0b01'01'00'00: {
|
||||
// Zip with self.
|
||||
@@ -1024,27 +1018,28 @@ void OpDispatchBuilder::PSHUFDOp(OpcodeArgs) {
|
||||
// Dest[1] = Src[0]
|
||||
// Dest[2] = Src[1]
|
||||
// Dest[3] = Src[1]
|
||||
Dest = _VZip(Size, 4, Src, Src);
|
||||
break;
|
||||
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.
|
||||
Dest = _VDupElement(Size, 4, Src, Shuffle & 0b11);
|
||||
break;
|
||||
return _VDupElement(OpSize::i128Bit, OpSize::i32Bit, Src, Shuffle & 0b11);
|
||||
}
|
||||
default: {
|
||||
// PSHUFD needs to scale index by 16.
|
||||
auto LookupIndexes =
|
||||
LoadAndCacheIndexedNamedVectorConstant(Size, FEXCore::IR::IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_PSHUFD, Shuffle * 16);
|
||||
Dest = _VTBL1(Size, Src, LookupIndexes);
|
||||
break;
|
||||
LoadAndCacheIndexedNamedVectorConstant(OpSize::i128Bit, FEXCore::IR::IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_PSHUFD, Shuffle * 16);
|
||||
return _VTBL1(OpSize::i128Bit, Src, LookupIndexes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StoreResult(FPRClass, Op, Dest, -1);
|
||||
void OpDispatchBuilder::PSHUFDOp(OpcodeArgs) {
|
||||
uint16_t Shuffle = Op->Src[1].Data.Literal.Value;
|
||||
Ref Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags);
|
||||
StoreResult(FPRClass, Op, Single128Bit4ByteVectorShuffle(Src, Shuffle), -1);
|
||||
}
|
||||
|
||||
template<size_t ElementSize, bool Low>
|
||||
|
||||
Reference in new issue
Block a user