mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-25 00:01:26 +02:00
Merge pull request #2998 from Sonicadvance1/optimize_addsub_fcma
OpcodeDispatcher: Optimize addsubp{s,d} using fcadd
This commit is contained in:
20 files changed
+266
-8
No files matched your search
@@ -74,7 +74,9 @@
|
||||
"ENABLECLZERO": "enableclzero",
|
||||
"DISABLECLZERO": "disableclzero",
|
||||
"ENABLEATOMICS": "enableatomics",
|
||||
"DISABLEATOMICS": "disableatomics"
|
||||
"DISABLEATOMICS": "disableatomics",
|
||||
"ENABLEFCMA": "enablefcma",
|
||||
"DISABLEFCMA": "disablefcma"
|
||||
},
|
||||
"Desc": [
|
||||
"Allows controlling of the CPU features in the JIT.",
|
||||
@@ -88,7 +90,8 @@
|
||||
"\t{enable,disable}pmull128: Will force enable or disable pmull128 even if the host doesn't support it",
|
||||
"\t{enable,disable}rng: Will force enable or disable rng even if the host doesn't support it",
|
||||
"\t{enable,disable}clzero: Will force enable or disable clzero even if the host doesn't support it",
|
||||
"\t{enable,disable}atomics: Will force enable or disable ARMv8.1 LSE atomics even if the host doesn't support it"
|
||||
"\t{enable,disable}atomics: Will force enable or disable ARMv8.1 LSE atomics even if the host doesn't support it",
|
||||
"\t{enable,disable}fcma: Will force enable or disable fcma even if the host doesn't support it"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
@@ -96,6 +96,10 @@ static void OverrideFeatures(HostFeatures *Features) {
|
||||
const bool EnableAtomics = HostFeatures() & FEXCore::Config::HostFeatures::ENABLEATOMICS;
|
||||
LogMan::Throw::AFmt(!(DisableAtomics && EnableAtomics), "Disabling and Enabling CPU features are mutually exclusive");
|
||||
|
||||
const bool DisableFCMA = HostFeatures() & FEXCore::Config::HostFeatures::DISABLEFCMA;
|
||||
const bool EnableFCMA = HostFeatures() & FEXCore::Config::HostFeatures::ENABLEFCMA;
|
||||
LogMan::Throw::AFmt(!(DisableFCMA && EnableFCMA), "Disabling and Enabling CPU features are mutually exclusive");
|
||||
|
||||
if (EnableAVX) {
|
||||
Features->SupportsAVX = true;
|
||||
}
|
||||
@@ -156,6 +160,12 @@ static void OverrideFeatures(HostFeatures *Features) {
|
||||
else if (DisableAtomics) {
|
||||
Features->SupportsAtomics = false;
|
||||
}
|
||||
if (EnableFCMA) {
|
||||
Features->SupportsFCMA = true;
|
||||
}
|
||||
else if (DisableFCMA) {
|
||||
Features->SupportsFCMA = false;
|
||||
}
|
||||
}
|
||||
|
||||
HostFeatures::HostFeatures() {
|
||||
@@ -181,6 +191,7 @@ HostFeatures::HostFeatures() {
|
||||
SupportsTSOImm9 = Features.Has(vixl::CPUFeatures::Feature::kRCpcImm);
|
||||
SupportsPMULL_128Bit = Features.Has(vixl::CPUFeatures::Feature::kPmull1Q);
|
||||
SupportsCSSC = Features.Has(vixl::CPUFeatures::Feature::kCSSC);
|
||||
SupportsFCMA = Features.Has(vixl::CPUFeatures::Feature::kFcma);
|
||||
|
||||
Supports3DNow = true;
|
||||
SupportsSSE4A = true;
|
||||
|
||||
@@ -65,6 +65,17 @@
|
||||
} \
|
||||
break; \
|
||||
}
|
||||
#define DO_VECTOR_FCADD_PAIR_OP(size, type, func) \
|
||||
case size: { \
|
||||
auto *Dst_d = reinterpret_cast<type*>(std::data(Tmp)); \
|
||||
auto *Src1_d = reinterpret_cast<const type*>(Src1); \
|
||||
auto *Src2_d = reinterpret_cast<const type*>(Src2); \
|
||||
for (uint8_t i = 0; i < Elements; i += 2) { \
|
||||
func(&Dst_d[i], &Src1_d[i], &Src2_d[i]); \
|
||||
} \
|
||||
break; \
|
||||
}
|
||||
|
||||
#define DO_VECTOR_SCALAR_OP(size, type, func) \
|
||||
case size: { \
|
||||
auto *Dst_d = reinterpret_cast<type*>(std::data(Tmp)); \
|
||||
|
||||
@@ -286,6 +286,7 @@ constexpr OpHandlerArray InterpreterOpHandlers = [] {
|
||||
REGISTER_OP(VREV64, VRev64);
|
||||
REGISTER_OP(VPCMPESTRX, VPCMPESTRX);
|
||||
REGISTER_OP(VPCMPISTRX, VPCMPISTRX);
|
||||
REGISTER_OP(VFCADD, VFCADD);
|
||||
|
||||
// Encryption ops
|
||||
REGISTER_OP(VAESIMC, AESImc);
|
||||
|
||||
@@ -314,6 +314,7 @@ namespace FEXCore::CPU {
|
||||
DEF_OP(VRev64);
|
||||
DEF_OP(VPCMPESTRX);
|
||||
DEF_OP(VPCMPISTRX);
|
||||
DEF_OP(VFCADD);
|
||||
|
||||
///< Encryption ops
|
||||
DEF_OP(AESImc);
|
||||
|
||||
@@ -2561,6 +2561,44 @@ DEF_OP(VPCMPISTRX) {
|
||||
memcpy(GDP, &Result, sizeof(Result));
|
||||
}
|
||||
|
||||
DEF_OP(VFCADD) {
|
||||
const auto Op = IROp->C<IR::IROp_VFCADD>();
|
||||
const uint8_t OpSize = IROp->Size;
|
||||
|
||||
const auto *Src1 = GetSrc<uint8_t*>(Data->SSAData, Op->Vector1);
|
||||
const auto *Src2 = GetSrc<uint8_t*>(Data->SSAData, Op->Vector2);
|
||||
const auto Rotate = Op->Rotate;
|
||||
LOGMAN_THROW_A_FMT(Rotate == 90 || Rotate == 270, "Invalid rotate!");
|
||||
|
||||
TempVectorDataArray Tmp;
|
||||
|
||||
const uint8_t ElementSize = Op->Header.ElementSize;
|
||||
const uint8_t Elements = OpSize / ElementSize;
|
||||
|
||||
const auto Func = [Rotate](auto dst, auto src1, auto src2) {
|
||||
auto Element1 = src2[1];
|
||||
auto Element3 = src2[0];
|
||||
if (Rotate == 90) {
|
||||
Element1 = -Element1;
|
||||
}
|
||||
else {
|
||||
Element3 = -Element3;
|
||||
}
|
||||
dst[0] = src1[0] + Element1;
|
||||
dst[1] = src1[1] + Element3;
|
||||
};
|
||||
|
||||
switch (ElementSize) {
|
||||
//DO_VECTOR_FCADD_PAIR_OP(2, float16_t, Func)
|
||||
DO_VECTOR_FCADD_PAIR_OP(4, float, Func)
|
||||
DO_VECTOR_FCADD_PAIR_OP(8, double, Func)
|
||||
default:
|
||||
LOGMAN_MSG_A_FMT("Unknown Element Size: {}", ElementSize);
|
||||
break;
|
||||
}
|
||||
memcpy(GDP, Tmp.data(), OpSize);
|
||||
}
|
||||
|
||||
#undef DEF_OP
|
||||
|
||||
} // namespace FEXCore::CPU
|
||||
@@ -1104,6 +1104,7 @@ CPUBackend::CompiledCode Arm64JITCore::CompileCode(uint64_t Entry,
|
||||
REGISTER_OP(VTBL1, VTBL1);
|
||||
REGISTER_OP(VREV32, VRev32);
|
||||
REGISTER_OP(VREV64, VRev64);
|
||||
REGISTER_OP(VFCADD, VFCADD);
|
||||
#undef REGISTER_OP
|
||||
|
||||
default:
|
||||
|
||||
@@ -470,6 +470,7 @@ private:
|
||||
DEF_OP(VTBL1);
|
||||
DEF_OP(VRev32);
|
||||
DEF_OP(VRev64);
|
||||
DEF_OP(VFCADD);
|
||||
|
||||
///< Encryption ops
|
||||
DEF_OP(AESImc);
|
||||
|
||||
@@ -3825,6 +3825,50 @@ DEF_OP(VRev64) {
|
||||
}
|
||||
}
|
||||
|
||||
DEF_OP(VFCADD) {
|
||||
const auto Op = IROp->C<IR::IROp_VFCADD>();
|
||||
const auto OpSize = IROp->Size;
|
||||
|
||||
const auto ElementSize = Op->Header.ElementSize;
|
||||
const auto Is256Bit = OpSize == Core::CPUState::XMM_AVX_REG_SIZE;
|
||||
|
||||
const auto Dst = GetVReg(Node);
|
||||
const auto Vector1 = GetVReg(Op->Vector1.ID());
|
||||
const auto Vector2 = GetVReg(Op->Vector2.ID());
|
||||
|
||||
LOGMAN_THROW_AA_FMT(ElementSize == 2 || ElementSize == 4 || ElementSize == 8, "Invalid size");
|
||||
LOGMAN_THROW_A_FMT(Op->Rotate == 90 || Op->Rotate == 270, "Invalidate Rotate");
|
||||
const auto SubRegSize =
|
||||
ElementSize == 2 ? ARMEmitter::SubRegSize::i16Bit :
|
||||
ElementSize == 4 ? ARMEmitter::SubRegSize::i32Bit : ARMEmitter::SubRegSize::i64Bit;
|
||||
const auto Rotate =
|
||||
Op->Rotate == 90 ? ARMEmitter::Rotation::ROTATE_90 : ARMEmitter::Rotation::ROTATE_270;
|
||||
|
||||
if (HostSupportsSVE256 && Is256Bit) {
|
||||
const auto Mask = PRED_TMP_32B.Merging();
|
||||
|
||||
if (Dst == Vector1) {
|
||||
// Trivial case where we already have first vector in the destination
|
||||
// register. We can just do the operation in place.
|
||||
fcadd(SubRegSize, Dst.Z(), Mask, Vector1.Z(), Vector2.Z(), Rotate);
|
||||
}
|
||||
else {
|
||||
// SVE FCADD is a destructive operation, so we need
|
||||
// a temporary for performing operations.
|
||||
movprfx(VTMP1.Z(), Vector1.Z());
|
||||
fcadd(SubRegSize, VTMP1.Z(), Mask, VTMP1.Z(), Vector2.Z(), Rotate);
|
||||
mov(Dst.Z(), VTMP1.Z());
|
||||
}
|
||||
} else {
|
||||
if (OpSize == 8) {
|
||||
fcadd(SubRegSize, Dst.D(), Vector1.D(), Vector2.D(), Rotate);
|
||||
}
|
||||
else {
|
||||
fcadd(SubRegSize, Dst.Q(), Vector1.Q(), Vector2.Q(), Rotate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef DEF_OP
|
||||
}
|
||||
|
||||
@@ -2962,9 +2962,21 @@ OrderedNode* OpDispatchBuilder::ADDSUBPOpImpl(OpcodeArgs, size_t ElementSize,
|
||||
OrderedNode *Src1, OrderedNode *Src2) {
|
||||
const auto Size = GetSrcSize(Op);
|
||||
|
||||
auto ConstantEOR = LoadAndCacheNamedVectorConstant(Size, ElementSize == 4 ? NAMED_VECTOR_PADDSUBPS_INVERT : NAMED_VECTOR_PADDSUBPD_INVERT);
|
||||
auto InvertedSource = _VXor(Size, ElementSize, Src2, ConstantEOR);
|
||||
return _VFAdd(Size, ElementSize, Src1, InvertedSource);
|
||||
if (CTX->HostFeatures.SupportsFCMA) {
|
||||
if (ElementSize == 4) {
|
||||
auto Swizzle = _VRev64(Size, 4, Src2);
|
||||
return _VFCADD(Size, ElementSize, Src1, Swizzle, 90);
|
||||
}
|
||||
else {
|
||||
auto Swizzle = _VExtr(Size, 1, Src2, Src2, 8);
|
||||
return _VFCADD(Size, ElementSize, Src1, Swizzle, 90);
|
||||
}
|
||||
}
|
||||
else {
|
||||
auto ConstantEOR = LoadAndCacheNamedVectorConstant(Size, ElementSize == 4 ? NAMED_VECTOR_PADDSUBPS_INVERT : NAMED_VECTOR_PADDSUBPD_INVERT);
|
||||
auto InvertedSource = _VXor(Size, ElementSize, Src2, ConstantEOR);
|
||||
return _VFAdd(Size, ElementSize, Src1, InvertedSource);
|
||||
}
|
||||
}
|
||||
|
||||
template<size_t ElementSize>
|
||||
|
||||
@@ -1558,6 +1558,10 @@
|
||||
"course of creating the intermediate result"
|
||||
],
|
||||
"DestSize": "4"
|
||||
},
|
||||
"FPR = VFCADD u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2, u16:$Rotate": {
|
||||
"DestSize": "RegisterSize",
|
||||
"NumElements": "RegisterSize / ElementSize"
|
||||
}
|
||||
},
|
||||
"Conv": {
|
||||
|
||||
@@ -31,6 +31,7 @@ class HostFeatures final {
|
||||
bool SupportsCLWB{};
|
||||
bool SupportsPMULL_128Bit{};
|
||||
bool SupportsCSSC{};
|
||||
bool SupportsFCMA{};
|
||||
|
||||
// Float exception behaviour
|
||||
bool SupportsFlushInputsToZero{};
|
||||
|
||||
@@ -46,12 +46,14 @@ class HostFeatures(Flag) :
|
||||
FEATURE_SVE256 = (1 << 1)
|
||||
FEATURE_CLZERO = (1 << 2)
|
||||
FEATURE_RNG = (1 << 3)
|
||||
FEATURE_FCMA = (1 << 4)
|
||||
|
||||
HostFeaturesLookup = {
|
||||
"SVE128" : HostFeatures.FEATURE_SVE128,
|
||||
"SVE256" : HostFeatures.FEATURE_SVE256,
|
||||
"CLZERO" : HostFeatures.FEATURE_CLZERO,
|
||||
"RNG" : HostFeatures.FEATURE_RNG,
|
||||
"FCMA" : HostFeatures.FEATURE_FCMA,
|
||||
}
|
||||
|
||||
def GetHostFeatures(data):
|
||||
|
||||
@@ -384,6 +384,7 @@ int main(int argc, char **argv, char **const envp) {
|
||||
FEATURE_SVE256 = (1U << 1),
|
||||
FEATURE_CLZERO = (1U << 2),
|
||||
FEATURE_RNG = (1U << 3),
|
||||
FEATURE_FCMA = (1U << 4),
|
||||
};
|
||||
|
||||
uint64_t SVEWidth = 0;
|
||||
@@ -402,6 +403,9 @@ int main(int argc, char **argv, char **const envp) {
|
||||
if (TestHeaderData->EnabledHostFeatures & FEATURE_RNG) {
|
||||
HostFeatureControl |= static_cast<uint64_t>(FEXCore::Config::HostFeatures::ENABLERNG);
|
||||
}
|
||||
if (TestHeaderData->EnabledHostFeatures & FEATURE_FCMA) {
|
||||
HostFeatureControl |= static_cast<uint64_t>(FEXCore::Config::HostFeatures::ENABLEFCMA);
|
||||
}
|
||||
|
||||
// Always enable ARMv8.1 LSE atomics.
|
||||
HostFeatureControl |= static_cast<uint64_t>(FEXCore::Config::HostFeatures::ENABLEATOMICS);
|
||||
@@ -418,6 +422,9 @@ int main(int argc, char **argv, char **const envp) {
|
||||
if (TestHeaderData->DisabledHostFeatures & FEATURE_RNG) {
|
||||
HostFeatureControl |= static_cast<uint64_t>(FEXCore::Config::HostFeatures::DISABLERNG);
|
||||
}
|
||||
if (TestHeaderData->DisabledHostFeatures & FEATURE_FCMA) {
|
||||
HostFeatureControl |= static_cast<uint64_t>(FEXCore::Config::HostFeatures::DISABLEFCMA);
|
||||
}
|
||||
FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_HOSTFEATURES, fextl::fmt::format("{}", HostFeatureControl));
|
||||
FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_FORCESVEWIDTH, fextl::fmt::format("{}", SVEWidth));
|
||||
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
"EnabledHostFeatures": [],
|
||||
"DisabledHostFeatures": [
|
||||
"SVE128",
|
||||
"SVE256"
|
||||
"SVE256",
|
||||
"FCMA"
|
||||
]
|
||||
},
|
||||
"Instructions": {
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"Features": {
|
||||
"Bitness": 64,
|
||||
"EnabledHostFeatures": [
|
||||
"FCMA"
|
||||
],
|
||||
"DisabledHostFeatures": [
|
||||
"SVE128",
|
||||
"SVE256"
|
||||
]
|
||||
},
|
||||
"Instructions": {
|
||||
"addsubpd xmm0, xmm1": {
|
||||
"ExpectedInstructionCount": 2,
|
||||
"Optimal": "Yes",
|
||||
"Comment": "0x66 0x0f 0xd0",
|
||||
"ExpectedArm64ASM": [
|
||||
"ext v4.16b, v17.16b, v17.16b, #8",
|
||||
"fcadd v16.2d, v16.2d, v4.2d, #90"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,8 @@
|
||||
"EnabledHostFeatures": [],
|
||||
"DisabledHostFeatures": [
|
||||
"SVE128",
|
||||
"SVE256"
|
||||
"SVE256",
|
||||
"FCMA"
|
||||
]
|
||||
},
|
||||
"Instructions": {
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"Features": {
|
||||
"Bitness": 64,
|
||||
"EnabledHostFeatures": [
|
||||
"FCMA"
|
||||
],
|
||||
"DisabledHostFeatures": [
|
||||
"SVE128",
|
||||
"SVE256"
|
||||
]
|
||||
},
|
||||
"Instructions": {
|
||||
"addsubps xmm0, xmm1": {
|
||||
"ExpectedInstructionCount": 2,
|
||||
"Optimal": "Yes",
|
||||
"Comment": "0xf2 0x0f 0xd0",
|
||||
"ExpectedArm64ASM": [
|
||||
"rev64 v4.4s, v17.4s",
|
||||
"fcadd v16.4s, v16.4s, v4.4s, #90"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,9 @@
|
||||
"SVE128",
|
||||
"SVE256"
|
||||
],
|
||||
"DisabledHostFeatures": []
|
||||
"DisabledHostFeatures": [
|
||||
"FCMA"
|
||||
]
|
||||
},
|
||||
"Instructions": {
|
||||
"vmovups xmm0, [rax]": {
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
{
|
||||
"Features": {
|
||||
"Bitness": 64,
|
||||
"EnabledHostFeatures": [
|
||||
"SVE128",
|
||||
"SVE256",
|
||||
"FCMA"
|
||||
],
|
||||
"DisabledHostFeatures": []
|
||||
},
|
||||
"Instructions": {
|
||||
"vaddsubpd xmm0, xmm1, xmm2": {
|
||||
"ExpectedInstructionCount": 6,
|
||||
"Optimal": "No",
|
||||
"Comment": [
|
||||
"Map 1 0b01 0xd0 128-bit"
|
||||
],
|
||||
"ExpectedArm64ASM": [
|
||||
"mov z4.d, p7/m, z17.d",
|
||||
"mov z5.d, p7/m, z18.d",
|
||||
"ext v5.16b, v5.16b, v5.16b, #8",
|
||||
"fcadd v4.2d, v4.2d, v5.2d, #90",
|
||||
"mov v4.16b, v4.16b",
|
||||
"mov z16.d, p7/m, z4.d"
|
||||
]
|
||||
},
|
||||
"vaddsubpd ymm0, ymm1, ymm2": {
|
||||
"ExpectedInstructionCount": 5,
|
||||
"Optimal": "No",
|
||||
"Comment": [
|
||||
"Map 1 0b01 0xd0 256-bit"
|
||||
],
|
||||
"ExpectedArm64ASM": [
|
||||
"mov z4.d, p7/m, z17.d",
|
||||
"mov z5.d, p7/m, z18.d",
|
||||
"ext z5.b, z5.b, z5.b, #8",
|
||||
"fcadd z4.d, p7/m, z4.d, z5.d, #90",
|
||||
"mov z16.d, p7/m, z4.d"
|
||||
]
|
||||
},
|
||||
"vaddsubps xmm0, xmm1, xmm2": {
|
||||
"ExpectedInstructionCount": 6,
|
||||
"Optimal": "No",
|
||||
"Comment": [
|
||||
"Map 1 0b11 0xd0 128-bit"
|
||||
],
|
||||
"ExpectedArm64ASM": [
|
||||
"mov z4.d, p7/m, z17.d",
|
||||
"mov z5.d, p7/m, z18.d",
|
||||
"rev64 v5.4s, v5.4s",
|
||||
"fcadd v4.4s, v4.4s, v5.4s, #90",
|
||||
"mov v4.16b, v4.16b",
|
||||
"mov z16.d, p7/m, z4.d"
|
||||
]
|
||||
},
|
||||
"vaddsubps ymm0, ymm1, ymm2": {
|
||||
"ExpectedInstructionCount": 5,
|
||||
"Optimal": "No",
|
||||
"Comment": [
|
||||
"Map 1 0b11 0xd0 256-bit"
|
||||
],
|
||||
"ExpectedArm64ASM": [
|
||||
"mov z4.d, p7/m, z17.d",
|
||||
"mov z5.d, p7/m, z18.d",
|
||||
"revw z5.d, p7/m, z5.d",
|
||||
"fcadd z4.s, p7/m, z4.s, z5.s, #90",
|
||||
"mov z16.d, p7/m, z4.d"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user