Merge pull request #6011 from javelina-pkwy/perf/gather-all-ones

Peephole optimization for VPCMPEQD + VGATHERDPS
This commit is contained in:
Ryan Houdek authored and GitHub committed 2026-10-07 09:13:24 -07:00
commit e9373bfaec
115 files changed
+324 -148

No files matched your search

+1 -1
View File
@@ -249,7 +249,7 @@ namespace DiskCache {
// The current version of the diskcache.
// This must be changed any time codegen changes occur!
// Be aware of the impact of changing this frequently!
static constexpr uint16_t FormatVersion = 29;
static constexpr uint16_t FormatVersion = 30;
static constexpr uint32_t LOOKUP_KEY_MAX_BUCKET_DEPTH = 500;
+2 -1
View File
@@ -629,7 +629,8 @@ private:
void Emulate128BitGather(IR::OpSize Size, IR::OpSize ElementSize, ARMEmitter::VRegister Dst, ARMEmitter::VRegister IncomingDst,
std::optional<ARMEmitter::Register> BaseAddr, ARMEmitter::VRegister VectorIndexLow,
std::optional<ARMEmitter::VRegister> VectorIndexHigh, ARMEmitter::VRegister MaskReg, IR::OpSize VectorIndexSize,
size_t DataElementOffsetStart, size_t IndexElementOffsetStart, uint8_t OffsetScale, IR::OpSize AddrSize);
size_t DataElementOffsetStart, size_t IndexElementOffsetStart, uint8_t OffsetScale, IR::OpSize AddrSize,
bool MaskAllOnes);
void EmitTFCheck();
+37 -24
View File
@@ -1058,7 +1058,7 @@ void Arm64JITCore::Emulate128BitGather(IR::OpSize Size, IR::OpSize ElementSize,
ARMEmitter::VRegister IncomingDst, std::optional<ARMEmitter::Register> BaseAddr,
ARMEmitter::VRegister VectorIndexLow, std::optional<ARMEmitter::VRegister> VectorIndexHigh,
ARMEmitter::VRegister MaskReg, IR::OpSize VectorIndexSize, size_t DataElementOffsetStart,
size_t IndexElementOffsetStart, uint8_t OffsetScale, IR::OpSize AddrSize) {
size_t IndexElementOffsetStart, uint8_t OffsetScale, IR::OpSize AddrSize, bool MaskAllOnes) {
LOGMAN_THROW_A_FMT(ElementSize >= IR::OpSize::i8Bit && ElementSize <= IR::OpSize::i64Bit, "Invalid element size");
const auto PerformSMove = [this](IR::OpSize ElementSize, const ARMEmitter::Register Dst, const ARMEmitter::VRegister Vector, int index) {
@@ -1116,11 +1116,13 @@ void Arm64JITCore::Emulate128BitGather(IR::OpSize Size, IR::OpSize ElementSize,
for (size_t i = DataElementOffsetStart, IndexElement = IndexElementOffsetStart; i < NumDataElements; ++i, ++IndexElement) {
ARMEmitter::ForwardLabel Skip {};
// Extract mask element
PerformMove(ElementSize, WorkingReg, MaskReg, i);
if (!MaskAllOnes) {
// Extract mask element
PerformMove(ElementSize, WorkingReg, MaskReg, i);
// Skip if the mask's sign bit isn't set
(void)tbz(WorkingReg, ElementSizeInBits - 1, &Skip);
// Skip if the mask's sign bit isn't set
(void)tbz(WorkingReg, ElementSizeInBits - 1, &Skip);
}
// Extract Index Element
if ((IndexElement * IR::OpSizeToSize(VectorIndexSize)) >= 16) {
@@ -1216,12 +1218,15 @@ DEF_OP(VLoadVectorGatherMasked) {
const auto SubRegSize = ConvertSubRegSize8(IROp);
const auto CMPPredicate = ARMEmitter::PReg::p0;
const auto GoverningPredicate = Is256Bit ? PRED_TMP_32B : PRED_TMP_16B;
// Check if the sign bit is set for the given element size.
cmplt(SubRegSize, CMPPredicate, GoverningPredicate.Zeroing(), MaskReg.Z(), 0);
auto TempDst = VTMP1;
// A mask known to be all-ones loads every element straight into the destination under the governing predicate.
const ARMEmitter::PRegister CMPPredicate = Op->MaskAllOnes ? GoverningPredicate : ARMEmitter::PReg::p0;
auto TempDst = Op->MaskAllOnes ? Dst : VTMP1;
if (!Op->MaskAllOnes) {
// Check if the sign bit is set for the given element size.
cmplt(SubRegSize, CMPPredicate, GoverningPredicate.Zeroing(), MaskReg.Z(), 0);
}
// No need to load a temporary register in the case that we weren't provided a base address and there is no scaling.
ARMEmitter::SVEMemOperand MemDst {ARMEmitter::SVEMemOperand(VectorIndexLow.Z(), 0)};
@@ -1256,12 +1261,14 @@ DEF_OP(VLoadVectorGatherMasked) {
default: break;
}
///< Merge elements based on predicate.
sel(SubRegSize, Dst.Z(), CMPPredicate, TempDst.Z(), IncomingDst.Z());
if (!Op->MaskAllOnes) {
///< Merge elements based on predicate.
sel(SubRegSize, Dst.Z(), CMPPredicate, TempDst.Z(), IncomingDst.Z());
}
} else {
LOGMAN_THROW_A_FMT(!Is256Bit, "Can't emulate this gather load in the backend! Programming error!");
Emulate128BitGather(IROp->Size, IROp->ElementSize, Dst, IncomingDst, BaseAddr, VectorIndexLow, VectorIndexHigh, MaskReg,
VectorIndexSize, DataElementOffsetStart, IndexElementOffsetStart, OffsetScale, Op->AddrSize);
VectorIndexSize, DataElementOffsetStart, IndexElementOffsetStart, OffsetScale, Op->AddrSize, Op->MaskAllOnes);
}
}
@@ -1295,16 +1302,20 @@ DEF_OP(VLoadVectorGatherMaskedQPS) {
}
const auto CMPPredicate = ARMEmitter::PReg::p0;
const auto CMPPredicate2 = ARMEmitter::PReg::p1;
// A mask known to be all-ones loads every element under the governing predicate and narrows straight into the destination.
const ARMEmitter::PRegister CMPPredicate2 = Op->MaskAllOnes ? PRED_TMP_16B : ARMEmitter::PReg::p1;
const auto GoverningPredicate = PRED_TMP_16B;
// Check if the sign bit is set for the given element size.
// This will set the predicate bits for elements [0, 1, 2, 3]
// We then use punpklo to extend the low results to be for 64-bit elements.
cmplt(ARMEmitter::SubRegSize::i32Bit, CMPPredicate, GoverningPredicate.Zeroing(), MaskReg.Z(), 0);
punpklo(CMPPredicate2, CMPPredicate);
if (!Op->MaskAllOnes) {
// Check if the sign bit is set for the given element size.
// This will set the predicate bits for elements [0, 1, 2, 3]
// We then use punpklo to extend the low results to be for 64-bit elements.
cmplt(ARMEmitter::SubRegSize::i32Bit, CMPPredicate, GoverningPredicate.Zeroing(), MaskReg.Z(), 0);
punpklo(CMPPredicate2, CMPPredicate);
}
auto TempDst = VTMP1;
const auto NarrowDst = Op->MaskAllOnes ? Dst : TempDst;
auto GatherExtend = [this](ARMEmitter::VRegister Dst, std::optional<ARMEmitter::Register> BaseAddr, ARMEmitter::VRegister VectorIndex,
ARMEmitter::PRegister CMPPredicate, ARMEmitter::SVEModType ModType, uint8_t OffsetScale) {
@@ -1328,21 +1339,23 @@ DEF_OP(VLoadVectorGatherMaskedQPS) {
GatherExtend(TempDst, BaseAddr, VectorIndexLow, CMPPredicate2, ModType, OffsetScale);
if (VectorIndexHigh.has_value()) {
punpkhi(CMPPredicate2, CMPPredicate);
if (!Op->MaskAllOnes) {
punpkhi(CMPPredicate2, CMPPredicate);
}
GatherExtend(VTMP2, BaseAddr, *VectorIndexHigh, CMPPredicate2, ModType, OffsetScale);
// Move elements to the lower half.
uzp1(ARMEmitter::SubRegSize::i32Bit, TempDst.Q(), TempDst.Q(), VTMP2.Q());
///< Merge elements based on predicate.
sel(ARMEmitter::SubRegSize::i32Bit, Dst.Z(), CMPPredicate, TempDst.Z(), IncomingDst.Z());
uzp1(ARMEmitter::SubRegSize::i32Bit, NarrowDst.Q(), TempDst.Q(), VTMP2.Q());
} else {
// Move elements to the lower half.
xtn(ARMEmitter::SubRegSize::i32Bit, TempDst.Q(), TempDst.Q());
xtn(ARMEmitter::SubRegSize::i32Bit, NarrowDst.Q(), TempDst.Q());
}
if (!Op->MaskAllOnes) {
///< Merge elements based on predicate.
sel(ARMEmitter::SubRegSize::i32Bit, Dst.Z(), CMPPredicate, TempDst.Z(), IncomingDst.Z());
}
} else {
Emulate128BitGather(IR::OpSize::i128Bit, IR::OpSize::i32Bit, Dst, IncomingDst, BaseAddr, VectorIndexLow, VectorIndexHigh, MaskReg,
IR::OpSize::i64Bit, 0, 0, OffsetScale, Op->AddrSize);
IR::OpSize::i64Bit, 0, 0, OffsetScale, Op->AddrSize, Op->MaskAllOnes);
}
}
@@ -1084,8 +1084,9 @@ public:
void AVX128_VFMAScalarImpl(OpcodeArgs, IROps IROp, uint8_t Src1Idx, uint8_t Src2Idx, uint8_t AddendIdx);
void AVX128_VFMAddSubImpl(OpcodeArgs, bool AddSub, uint8_t Src1Idx, uint8_t Src2Idx, uint8_t AddendIdx);
RefPair AVX128_VPGatherQPSImpl(OpcodeArgs, Ref Dest, Ref Mask, RefVSIB VSIB);
RefPair AVX128_VPGatherImpl(OpcodeArgs, OpSize Size, OpSize ElementLoadSize, OpSize AddrElementSize, RefPair Dest, RefPair Mask, RefVSIB VSIB);
RefPair AVX128_VPGatherQPSImpl(OpcodeArgs, Ref Dest, Ref Mask, RefVSIB VSIB, bool MaskAllOnes);
RefPair AVX128_VPGatherImpl(OpcodeArgs, OpSize Size, OpSize ElementLoadSize, OpSize AddrElementSize, RefPair Dest, RefPair Mask,
RefVSIB VSIB, bool MaskAllOnesLow = false, bool MaskAllOnesHigh = false);
void AVX128_VPGATHER(OpcodeArgs, OpSize AddrElementSize);
@@ -1178,6 +1179,11 @@ public:
// At block boundaries, fix up the carry flag.
if (!SRAOnly) {
RectifyCarryInvert(CFInvertedABI);
// Also we can't trust the LastDef accross block boundaries, so clear that as well.
for (auto& Def : RegCache.LastDef) {
Def = nullptr;
}
}
if (!MMXOnly) {
@@ -1963,12 +1969,17 @@ private:
uint64_t Partial;
Ref Value[64];
// Keep track of where each register was last written to within the current block,
// for use in peephole optimizations.
Ref LastDef[64];
} RegCache {};
void InvalidateReg(uint8_t Index) {
uint64_t Bit = (1ull << (uint64_t)Index);
RegCache.Cached &= ~Bit;
RegCache.Written &= ~Bit;
RegCache.LastDef[Index] = nullptr;
}
Ref LoadRegCache(uint64_t Offset, uint8_t Index, RegClass Class, IR::OpSize Size) {
@@ -2084,6 +2095,7 @@ private:
RegCache.Value[Index] = Value;
RegCache.Cached |= Bit;
RegCache.Written |= Bit;
RegCache.LastDef[Index] = Value;
}
void InvalidateHighAVXRegisters() {
@@ -2052,7 +2052,8 @@ void OpDispatchBuilder::AVX128_VFMAddSubImpl(OpcodeArgs, bool AddSub, uint8_t Sr
}
OpDispatchBuilder::RefPair OpDispatchBuilder::AVX128_VPGatherImpl(OpcodeArgs, OpSize Size, OpSize ElementLoadSize, OpSize AddrElementSize,
RefPair Dest, RefPair Mask, RefVSIB VSIB) {
RefPair Dest, RefPair Mask, RefVSIB VSIB, bool MaskAllOnesLow,
bool MaskAllOnesHigh) {
LOGMAN_THROW_A_FMT(AddrElementSize == OpSize::i32Bit || AddrElementSize == OpSize::i64Bit, "Unknown address element size");
const auto Is128Bit = Size == OpSize::i128Bit;
@@ -2102,7 +2103,7 @@ OpDispatchBuilder::RefPair OpDispatchBuilder::AVX128_VPGatherImpl(OpcodeArgs, Op
RefPair Result {};
///< Calculate the low-half.
Result.Low = _VLoadVectorGatherMasked(OpSize::i128Bit, ElementLoadSize, Dest.Low, Mask.Low, BaseAddr, VSIB.Low, VSIB.High,
AddrElementSize, VSIB.Scale, 0, 0, AddrSize);
AddrElementSize, VSIB.Scale, 0, 0, AddrSize, MaskAllOnesLow);
if (Is128Bit) {
Result.High = LoadZeroVector(OpSize::i128Bit);
@@ -2117,6 +2118,7 @@ OpDispatchBuilder::RefPair OpDispatchBuilder::AVX128_VPGatherImpl(OpcodeArgs, Op
Ref DestReg = Dest.High;
Ref MaskReg = Mask.High;
bool MaskAllOnes = MaskAllOnesHigh;
uint8_t IndexElementOffset {};
uint8_t DataElementOffset {};
if (AddrElementSize == ElementLoadSize) {
@@ -2133,13 +2135,15 @@ OpDispatchBuilder::RefPair OpDispatchBuilder::AVX128_VPGatherImpl(OpcodeArgs, Op
AddrAddressing.High = Invalid();
DestReg = Result.Low; ///< Start mixing with the low register.
MaskReg = Mask.Low; ///< Mask starts with the low mask here.
MaskAllOnes = MaskAllOnesLow;
IndexElementOffset = 0;
DataElementOffset = IR::NumElements(OpSize::i128Bit, ElementLoadSize) / 2;
}
///< Calculate the high-half.
auto ResultHigh = _VLoadVectorGatherMasked(OpSize::i128Bit, ElementLoadSize, DestReg, MaskReg, BaseAddr, AddrAddressing.Low,
AddrAddressing.High, AddrElementSize, VSIB.Scale, DataElementOffset, IndexElementOffset, AddrSize);
auto ResultHigh =
_VLoadVectorGatherMasked(OpSize::i128Bit, ElementLoadSize, DestReg, MaskReg, BaseAddr, AddrAddressing.Low, AddrAddressing.High,
AddrElementSize, VSIB.Scale, DataElementOffset, IndexElementOffset, AddrSize, MaskAllOnes);
if (AddrElementSize == OpSize::i64Bit && ElementLoadSize == OpSize::i32Bit) {
// If we only fetched 128-bits worth of data then the upper-result is all zero.
@@ -2152,7 +2156,7 @@ OpDispatchBuilder::RefPair OpDispatchBuilder::AVX128_VPGatherImpl(OpcodeArgs, Op
return Result;
}
OpDispatchBuilder::RefPair OpDispatchBuilder::AVX128_VPGatherQPSImpl(OpcodeArgs, Ref Dest, Ref Mask, RefVSIB VSIB) {
OpDispatchBuilder::RefPair OpDispatchBuilder::AVX128_VPGatherQPSImpl(OpcodeArgs, Ref Dest, Ref Mask, RefVSIB VSIB, bool MaskAllOnes) {
///< BaseAddr doesn't need to exist, calculate that here.
Ref BaseAddr = VSIB.BaseAddr;
@@ -2184,7 +2188,8 @@ OpDispatchBuilder::RefPair OpDispatchBuilder::AVX128_VPGatherQPSImpl(OpcodeArgs,
auto AddrSize = (Op->Flags & X86Tables::DecodeFlags::FLAG_ADDRESS_SIZE) != 0 ? (GPRSize >> 1) : GPRSize;
///< Calculate the low-half.
Result.Low = _VLoadVectorGatherMaskedQPS(OpSize::i128Bit, OpSize::i32Bit, Dest, Mask, BaseAddr, VSIB.Low, VSIB.High, VSIB.Scale, AddrSize);
Result.Low =
_VLoadVectorGatherMaskedQPS(OpSize::i128Bit, OpSize::i32Bit, Dest, Mask, BaseAddr, VSIB.Low, VSIB.High, VSIB.Scale, AddrSize, MaskAllOnes);
Result.High = LoadZeroVector(OpSize::i128Bit);
if (VSIB.High == Invalid()) {
// Special case for only loading two floats.
@@ -2213,6 +2218,21 @@ void OpDispatchBuilder::AVX128_VPGATHER(OpcodeArgs, OpSize AddrElementSize) {
auto VSIB = AVX128_LoadVSIB(Op, Op->Src[0], Op->Flags, NeedsHighAddrBytes);
auto Mask = AVX128_LoadSource_WithOpSize(Op, Op->Src[1], Op->Flags, !Is128Bit);
// Check if the mask was computed from a self comparison, which indicates an all-ones mask.
// This is a compiler idiom for an unmasked gather. In this case, we can apply a peephole and skip
// all mask checks in the codegen, reducing codesize substantially.
bool MaskAllOnesLow = false;
bool MaskAllOnesHigh = false;
if (Op->Src[1].IsGPR()) {
const auto MaskXMM = Op->Src[1].Data.GPR.GPR - X86State::REG_XMM_0;
const Ref LowDef = RegCache.LastDef[FPR0Index + MaskXMM];
const Ref HighDef = RegCache.LastDef[AVXHigh0Index + MaskXMM];
MaskAllOnesLow = LowDef && IsValueVectorAllOnes(WrapNode(LowDef));
MaskAllOnesHigh = !Is128Bit && HighDef && IsValueVectorAllOnes(WrapNode(HighDef));
}
bool NeedsSVEScale = (VSIB.Scale == 2 || VSIB.Scale == 8) || (VSIB.BaseAddr == Invalid() && VSIB.Scale != 1);
const bool NeedsExplicitSVEPath =
@@ -2243,15 +2263,15 @@ void OpDispatchBuilder::AVX128_VPGATHER(OpcodeArgs, OpSize AddrElementSize) {
}
///< AddressElementSize is now OpSize::i64Bit
Result = AVX128_VPGatherQPSImpl(Op, Dest.Low, Mask.Low, VSIBLow);
Result = AVX128_VPGatherQPSImpl(Op, Dest.Low, Mask.Low, VSIBLow, MaskAllOnesLow);
if (NeedsHighAddrBytes) {
auto Res = AVX128_VPGatherQPSImpl(Op, Dest.High, Mask.High, VSIBHigh);
auto Res = AVX128_VPGatherQPSImpl(Op, Dest.High, Mask.High, VSIBHigh, MaskAllOnesHigh);
Result.High = Res.Low;
}
} else if (AddrElementSize == OpSize::i64Bit && ElementLoadSize == OpSize::i32Bit) {
Result = AVX128_VPGatherQPSImpl(Op, Dest.Low, Mask.Low, VSIB);
Result = AVX128_VPGatherQPSImpl(Op, Dest.Low, Mask.Low, VSIB, MaskAllOnesLow);
} else {
Result = AVX128_VPGatherImpl(Op, Size, ElementLoadSize, AddrElementSize, Dest, Mask, VSIB);
Result = AVX128_VPGatherImpl(Op, Size, ElementLoadSize, AddrElementSize, Dest, Mask, VSIB, MaskAllOnesLow, MaskAllOnesHigh);
}
AVX128_StoreResult_WithOpSize(Op, Op->Dest, Result);
+6 -4
View File
@@ -604,11 +604,12 @@
"DestSize": "RegisterSize",
"ElementSize": "ElementSize"
},
"FPR = VLoadVectorGatherMasked OpSize:#RegisterSize, OpSize:#ElementSize, FPR:$Incoming, FPR:$Mask, GPR:$AddrBase, FPR:$VectorIndexLow, FPR:$VectorIndexHigh, OpSize:$VectorIndexElementSize, u8:$OffsetScale, u8:$DataElementOffsetStart, u8:$IndexElementOffsetStart, OpSize:$AddrSize": {
"FPR = VLoadVectorGatherMasked OpSize:#RegisterSize, OpSize:#ElementSize, FPR:$Incoming, FPR:$Mask, GPR:$AddrBase, FPR:$VectorIndexLow, FPR:$VectorIndexHigh, OpSize:$VectorIndexElementSize, u8:$OffsetScale, u8:$DataElementOffsetStart, u8:$IndexElementOffsetStart, OpSize:$AddrSize, i1:$MaskAllOnes{false}": {
"Desc": [
"Does a masked load similar to VPGATHERD* where the upper bit of each element",
"determines whether or not that element will be loaded from memory.",
"Most of VSIB encoding is passed directly through to the IR operation."
"Most of VSIB encoding is passed directly through to the IR operation.",
"MaskAllOnes is set when every mask element is provably all ones."
],
"TiedSource": 0,
"ImplicitFlagClobber": true,
@@ -618,12 +619,13 @@
"$VectorIndexElementSize == OpSize::i32Bit || $VectorIndexElementSize == OpSize::i64Bit"
]
},
"FPR = VLoadVectorGatherMaskedQPS OpSize:#RegisterSize, OpSize:#ElementSize, FPR:$Incoming, FPR:$MaskReg, GPR:$AddrBase, FPR:$VectorIndexLow, FPR:$VectorIndexHigh, u8:$OffsetScale, OpSize:$AddrSize": {
"FPR = VLoadVectorGatherMaskedQPS OpSize:#RegisterSize, OpSize:#ElementSize, FPR:$Incoming, FPR:$MaskReg, GPR:$AddrBase, FPR:$VectorIndexLow, FPR:$VectorIndexHigh, u8:$OffsetScale, OpSize:$AddrSize, i1:$MaskAllOnes{false}": {
"Desc": [
"Does a masked load similar to VPGATHERQPS where the upper bit of each element",
"determines whether or not that element will be loaded from memory.",
"Most of VSIB encoding is passed directly through to the IR operation.",
"Only supports the case of 32-bit data element sizes from 64-bit addresses"
"Only supports the case of 32-bit data element sizes from 64-bit addresses",
"MaskAllOnes is set when every mask element is provably all ones."
],
"TiedSource": 0,
"ImplicitFlagClobber": true,
+9
View File
@@ -341,6 +341,15 @@ public:
return false;
}
// Returns true if every bit of the vector value is set.
// Currently this only recognizes the self compare equal idiom.
// TODO: Should this recognize other patterns?
bool IsValueVectorAllOnes(OrderedNodeWrapper ssa) const {
auto RealNode = ssa.GetNode(DualListData.ListBegin());
const auto* IROp = RealNode->Op(DualListData.DataBegin());
return IROp->Op == OP_VCMPEQ && IROp->Args[0].ID() == IROp->Args[1].ID();
}
FEXCore::IR::IROp_Header* GetOpHeader(OrderedNodeWrapper ssa) {
Ref RealNode = ssa.GetNode(DualListData.ListBegin());
return RealNode->Op(DualListData.DataBegin());
+1 -1
View File
@@ -8,7 +8,7 @@
"SVE128",
"SVE256"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"roundss xmm0, xmm1, 00000000b": {
@@ -7,7 +7,7 @@
"AFP"
],
"DisabledHostFeatures": [],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"cvtpi2ps xmm0, [rax]": {
@@ -9,7 +9,7 @@
"DisabledHostFeatures": [
"RPRES"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"cvtsi2ss xmm0, eax": {
@@ -7,7 +7,7 @@
"AFP"
],
"DisabledHostFeatures": [],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"cvtsi2sd xmm0, eax": {
@@ -8,7 +8,7 @@
"SVE128",
"SVE256"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"cvtpi2ps xmm0, [rax]": {
@@ -9,7 +9,7 @@
"SVE256",
"RPRES"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"cvtsi2ss xmm0, eax": {
@@ -8,7 +8,7 @@
"SVE128",
"SVE256"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"cvtsi2sd xmm0, eax": {
@@ -9,7 +9,7 @@
"DisabledHostFeatures": [
"RPRES"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"vsqrtss xmm0, xmm1, xmm2": {
@@ -7,7 +7,7 @@
"AFP"
],
"DisabledHostFeatures": [],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"vroundss xmm0, xmm1, 00000000b": {
@@ -7,7 +7,7 @@
"SVE256",
"SVE128"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"vfmaddsubps xmm0, xmm1, xmm2, xmm3": {
@@ -13,7 +13,7 @@
"SVE256",
"SVE128"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"vmovups xmm0, xmm0": {
@@ -9,7 +9,7 @@
"SVE256",
"SVE128"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"vaddsubpd xmm0, xmm1, xmm2": {
@@ -10,7 +10,7 @@
"FLAGM2",
"SVE256"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"vmovntps [rax], xmm0": {
@@ -10,7 +10,7 @@
"SVE128",
"SVE256"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"vucomiss xmm0, xmm1": {
@@ -11,7 +11,7 @@
"I8MM",
"DOTPROD"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"vpshufb xmm0, xmm1, xmm2": {
@@ -8,7 +8,7 @@
"SVE256",
"SVE128"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"vfmadd132ss xmm0, xmm1, xmm2": {
@@ -12,7 +12,7 @@
"SVE256",
"I8MM"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"vpdpbusd xmm0, xmm1, xmm2": {
@@ -11,7 +11,7 @@
"SVE128",
"SVE256"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"vpdpbusd xmm0, xmm1, xmm2": {
@@ -10,7 +10,7 @@
"FLAGM2",
"SVE256"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"vmovntdqa xmm0, [rax]": {
@@ -11,7 +11,7 @@
"SVE256",
"SVEBITPERM"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"vtestps xmm0, xmm1": {
@@ -7,7 +7,7 @@
"SVE256",
"SVE128"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"vpermq ymm0, ymm1, 1": {
@@ -8,7 +8,7 @@
"AFP",
"SVE256"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"vblendvps xmm0, xmm1, xmm2, xmm3": {
@@ -9,7 +9,7 @@
"SVE256",
"SVE128"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"vpsrlw xmm0, xmm1, 0": {
+1 -1
View File
@@ -9,7 +9,7 @@
"FLAGM",
"FLAGM2"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"lock add byte [rax], cl": {
@@ -9,7 +9,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"sha1nexte xmm0, xmm1": {
@@ -9,7 +9,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"sha1nexte xmm0, xmm1": {
@@ -9,7 +9,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"pclmulqdq xmm0, xmm1, 00000b": {
+1 -1
View File
@@ -10,7 +10,7 @@
"AFP",
"RPRES"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Comment": [
"These 3DNow! instructions are optimal assuming that FEX doesn't SRA MMX registers",
@@ -8,7 +8,7 @@
"RPRES",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Comment": [
"Instructions that explicitly push against the limits of ARM's loadstore instructions"
@@ -8,7 +8,7 @@
"RPRES",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Comment": [
"Instructions that explicitly push against the limits of ARM's loadstore instructions"
@@ -13,7 +13,7 @@
"RPRES",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Comment": [
"These are instruction combinations that could be more optimal if FEX optimized for them"
@@ -11,7 +11,7 @@
"RPRES",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Comment": [
"These are instruction combinations that could be more optimal if FEX optimized for them"
@@ -9,7 +9,7 @@
"SVE256",
"RPRES"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Comment": [
"These are instruction combinations that could be more optimal if FEX optimized for them"
@@ -14,7 +14,7 @@
"RPRES",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Comment": [
"These are instruction combinations that could be more optimal if FEX optimized for them"
@@ -14,7 +14,7 @@
"RPRES",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Comment": [
"These are instruction combinations that could be more optimal if FEX optimized for them"
@@ -0,0 +1,70 @@
{
"Features": {
"Bitness": 64,
"EnabledHostFeatures": [],
"DisabledHostFeatures": [
"AFP",
"FLAGM",
"FLAGM2",
"SVE128",
"SVE256",
"I8MM",
"DOTPROD"
],
"BinaryCacheVersion": 30
},
"Comment": [
"This file tracks the translations for the 'peephole' optimizations in FEX.",
"Peephole optimizations are small targetted optimizations that recognize",
"specific patterns in x86 code and specialize the translation accordingly."
],
"Instructions": {
"vpcmpeqd + vpgatherdd": {
"x86InstructionCount": 2,
"ExpectedInstructionCount": 32,
"Comment": [
"Setting the mask to all-ones using vpcmpeqd, and then performing the gather operation.",
"This is an idiom emitted by Clang for an unmasked gather.",
"https://godbolt.org/z/4devEvfKf"
],
"x86Insts": [
"vpcmpeqd ymm2, ymm2, ymm2",
"vpgatherdd ymm0, [ymm1*4 + rax], ymm2"
],
"ExpectedArm64ASM": [
"ldr q2, [x28, #224]",
"cmeq v18.4s, v18.4s, v18.4s",
"cmeq v2.4s, v2.4s, v2.4s",
"ldr q3, [x28, #192]",
"ldr q4, [x28, #208]",
"smov x0, v17.s[0]",
"add x1, x4, w0, sxtw #2",
"ld1 {v16.s}[0], [x1]",
"smov x0, v17.s[1]",
"add x1, x4, w0, sxtw #2",
"ld1 {v16.s}[1], [x1]",
"smov x0, v17.s[2]",
"add x1, x4, w0, sxtw #2",
"ld1 {v16.s}[2], [x1]",
"smov x0, v17.s[3]",
"add x1, x4, w0, sxtw #2",
"ld1 {v16.s}[3], [x1]",
"smov x0, v4.s[0]",
"add x1, x4, w0, sxtw #2",
"ld1 {v3.s}[0], [x1]",
"smov x0, v4.s[1]",
"add x1, x4, w0, sxtw #2",
"ld1 {v3.s}[1], [x1]",
"smov x0, v4.s[2]",
"add x1, x4, w0, sxtw #2",
"ld1 {v3.s}[2], [x1]",
"smov x0, v4.s[3]",
"add x1, x4, w0, sxtw #2",
"ld1 {v3.s}[3], [x1]",
"movi v18.2d, #0x0",
"stp xzr, xzr, [x28, #224]",
"str q3, [x28, #192]"
]
}
}
}
@@ -0,0 +1,49 @@
{
"Features": {
"Bitness": 64,
"EnabledHostFeatures": [
"SVE128"
],
"DisabledHostFeatures": [
"AFP",
"FLAGM",
"FLAGM2",
"SVE256"
],
"BinaryCacheVersion": 30
},
"Comment": [
"This file tracks the translations for the 'peephole' optimizations in FEX.",
"Peephole optimizations are small targetted optimizations that recognize",
"specific patterns in x86 code and specialize the translation accordingly."
],
"Instructions": {
"vpcmpeqd + vpgatherdd": {
"x86InstructionCount": 2,
"ExpectedInstructionCount": 12,
"Comment": [
"Setting the mask to all-ones using vpcmpeqd, and then performing the gather operation.",
"This is an idiom emitted by Clang for an unmasked gather.",
"https://godbolt.org/z/4devEvfKf"
],
"x86Insts": [
"vpcmpeqd ymm2, ymm2, ymm2",
"vpgatherdd ymm0, [ymm1*4 + rax], ymm2"
],
"ExpectedArm64ASM": [
"ldr q2, [x28, #224]",
"cmeq v18.4s, v18.4s, v18.4s",
"cmeq v2.4s, v2.4s, v2.4s",
"ldr q3, [x28, #192]",
"ldr q4, [x28, #208]",
"mrs x20, nzcv",
"ld1w {z16.s}, p6/z, [x4, z17.s, sxtw #2]",
"ld1w {z3.s}, p6/z, [x4, z4.s, sxtw #2]",
"movi v18.2d, #0x0",
"msr nzcv, x20",
"stp xzr, xzr, [x28, #224]",
"str q3, [x28, #192]"
]
}
}
}
@@ -12,7 +12,7 @@
"RPRES",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Comment": [],
"Instructions": {
@@ -10,7 +10,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"lock add byte [rax], cl": {
@@ -9,7 +9,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"Chained add": {
@@ -10,7 +10,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"ptest xmm0, xmm1": {
@@ -10,7 +10,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"The Witcher 3": {
@@ -10,7 +10,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"Sonic Mania movie player": {
@@ -10,7 +10,7 @@
"SVE128",
"SVE256"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"FMOD scalar loop": {
@@ -13,7 +13,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"The Sims 1 hot block": {
@@ -10,7 +10,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"add bl, cl": {
@@ -10,7 +10,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"add al, 1": {
@@ -10,7 +10,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"push es": {
@@ -11,7 +11,7 @@
"RPRES",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"ucomiss xmm0, xmm1": {
@@ -11,7 +11,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"sgdt [rax]": {
@@ -11,7 +11,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"xgetbv": {
@@ -11,7 +11,7 @@
"AFP",
"FCMA"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"ucomisd xmm0, xmm1": {
@@ -12,7 +12,7 @@
"AFP",
"CSSC"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"popcnt ax, bx": {
@@ -12,7 +12,7 @@
"RPRES",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"popcnt ax, bx": {
@@ -12,7 +12,7 @@
"RPRES",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"vucomiss xmm0, xmm1": {
@@ -10,7 +10,7 @@
"AFP",
"SVEBITPERM"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"vtestps xmm0, xmm1": {
@@ -9,7 +9,7 @@
"DisabledHostFeatures": [
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"blsr eax, ebx": {
@@ -10,7 +10,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"Block1": {
@@ -10,7 +10,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"Block1": {
@@ -10,7 +10,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"Block1": {
@@ -10,7 +10,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"Block1": {
+1 -1
View File
@@ -11,7 +11,7 @@
"CSSC",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"fadd dword [rax]": {
@@ -13,7 +13,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"Block1": {
@@ -13,7 +13,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"Block1": {
@@ -13,7 +13,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"Block1": {
@@ -13,7 +13,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"Block1": {
@@ -13,7 +13,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"fadd dword [rax]": {
+1 -1
View File
@@ -10,7 +10,7 @@
"FLAGM2",
"CRYPTO"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"pshufb mm0, mm1": {
+1 -1
View File
@@ -8,7 +8,7 @@
"AFP",
"CRYPTO"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Comment": [
"SSE4.2 string instructions are skipped here.",
@@ -8,7 +8,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"dpps xmm0, xmm1, 00000000b": {
@@ -11,7 +11,7 @@
"FLAGM",
"FLAGM2"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"rep movsb": {
+1 -1
View File
@@ -10,7 +10,7 @@
"FLAGM2",
"MOPS"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"add bl, cl": {
@@ -9,7 +9,7 @@
"FLAGM",
"FLAGM2"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Comment": [
"Instructions in this table that are marked optimal don't have their flag calculation part of this assumption",
@@ -9,7 +9,7 @@
"FlagM",
"FlagM2"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"push es": {
+1 -1
View File
@@ -9,7 +9,7 @@
"SVE128",
"SVE256"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"pfrcpv mm0, mm1": {
@@ -9,7 +9,7 @@
"SVE128",
"SVE256"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"rsqrtps xmm0, xmm1": {
@@ -9,7 +9,7 @@
"SVE128",
"SVE256"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"rsqrtss xmm0, xmm1": {
@@ -8,7 +8,7 @@
"AFP"
],
"DisabledHostFeatures": [],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"vrsqrtps xmm0, xmm1": {
+1 -1
View File
@@ -6,7 +6,7 @@
"SVE128",
"SVE256"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {}
}
@@ -33,7 +33,7 @@
" - 1b: ECX = MSB",
"[7] - Reserved"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"pcmpestrm xmm0, xmm1, 0_0_00_00_00b": {
+1 -1
View File
@@ -12,7 +12,7 @@
"FLAGM",
"FLAGM2"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Comment": [
"MMX instructions are defined as optimal without SRA being used for these instructions.",
@@ -11,7 +11,7 @@
"FLAGM",
"FLAGM2"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"sgdt [rax]": {
@@ -11,7 +11,7 @@
"FLAGM",
"FLAGM2"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"xgetbv": {
@@ -7,7 +7,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"push fs": {
@@ -12,7 +12,7 @@
"FLAGM",
"FLAGM2"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"movupd xmm0, xmm0": {
@@ -9,7 +9,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"addsubpd xmm0, xmm1": {
@@ -8,7 +8,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"psrlw xmm0, xmm1": {
@@ -7,7 +7,7 @@
"AFP"
],
"DisabledHostFeatures": [],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"pmulhuw xmm0, xmm1": {
@@ -12,7 +12,7 @@
"FRINTTS",
"CSSC"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"movss xmm0, xmm1": {
@@ -10,7 +10,7 @@
"FCMA",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"movsd xmm0, xmm1": {
@@ -9,7 +9,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"addsubps xmm0, xmm1": {
@@ -10,7 +10,7 @@
"FCMA",
"AFP"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"cvtpd2dq xmm0, xmm1": {
@@ -12,7 +12,7 @@
"FLAGM",
"FLAGM2"
],
"BinaryCacheVersion": 29
"BinaryCacheVersion": 30
},
"Instructions": {
"cvttss2si eax, xmm0": {
Loaded 100 of 115 files, more files were not shown because too many files have changed in this diff. Show more