From ca51f1a4f67445a69632c3f53d1b62f074cb7414 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Wed, 26 Aug 2015 04:18:08 -0500 Subject: [PATCH] [AArch64] Optimize paired registers being used in double operations. In particular this optimizes the case where a 32bit float is loaded via lfs, and then used in double operations. This happens very often in Gekko based code because the best way to load a 32bit value as a double is lfs since it automatically turns in to a double value. There are a few other implications of this in practice as well. Like if both of the paired registers are loaded via psq_l and then used in double operations it would be improved. Also if we implement a double register we've got to be careful to make sure we understand if it is in "lower" register or the full 128bit register. --- .../JitArm64/JitArm64_FloatingPoint.cpp | 166 ++---------------- .../PowerPC/JitArm64/JitArm64_RegCache.cpp | 15 ++ 2 files changed, 32 insertions(+), 149 deletions(-) diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_FloatingPoint.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_FloatingPoint.cpp index a02948534a..4ee267f55c 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_FloatingPoint.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_FloatingPoint.cpp @@ -27,17 +27,7 @@ void JitArm64::fabsx(UGeckoInstruction inst) ARM64Reg VB = fpr.R(b); ARM64Reg VD = fpr.R(d); - if (fpr.IsLower(d)) - { - m_float_emit.FABS(EncodeRegToDouble(VD), EncodeRegToDouble(VB)); - } - else - { - ARM64Reg V0 = fpr.GetReg(); - m_float_emit.FABS(EncodeRegToDouble(V0), EncodeRegToDouble(VB)); - m_float_emit.INS(64, VD, 0, V0, 0); - fpr.Unlock(V0); - } + m_float_emit.FABS(EncodeRegToDouble(VD), EncodeRegToDouble(VB)); } void JitArm64::faddsx(UGeckoInstruction inst) @@ -70,17 +60,7 @@ void JitArm64::faddx(UGeckoInstruction inst) ARM64Reg VB = fpr.R(b); ARM64Reg VD = fpr.R(d); - if (fpr.IsLower(d)) - { - m_float_emit.FADD(EncodeRegToDouble(VD), EncodeRegToDouble(VA), EncodeRegToDouble(VB)); - } - else - { - ARM64Reg V0 = fpr.GetReg(); - m_float_emit.FADD(EncodeRegToDouble(V0), EncodeRegToDouble(VA), EncodeRegToDouble(VB)); - m_float_emit.INS(64, VD, 0, V0, 0); - fpr.Unlock(V0); - } + m_float_emit.FADD(EncodeRegToDouble(VD), EncodeRegToDouble(VA), EncodeRegToDouble(VB)); } void JitArm64::fmaddsx(UGeckoInstruction inst) @@ -118,17 +98,7 @@ void JitArm64::fmaddx(UGeckoInstruction inst) ARM64Reg VC = fpr.R(c); ARM64Reg VD = fpr.R(d); - if (fpr.IsLower(d)) - { - m_float_emit.FMADD(EncodeRegToDouble(VD), EncodeRegToDouble(VA), EncodeRegToDouble(VC), EncodeRegToDouble(VB)); - } - else - { - ARM64Reg V0 = fpr.GetReg(); - m_float_emit.FMADD(EncodeRegToDouble(V0), EncodeRegToDouble(VA), EncodeRegToDouble(VC), EncodeRegToDouble(VB)); - m_float_emit.INS(64, VD, 0, V0, 0); - fpr.Unlock(V0); - } + m_float_emit.FMADD(EncodeRegToDouble(VD), EncodeRegToDouble(VA), EncodeRegToDouble(VC), EncodeRegToDouble(VB)); } void JitArm64::fmrx(UGeckoInstruction inst) @@ -181,17 +151,7 @@ void JitArm64::fmsubx(UGeckoInstruction inst) ARM64Reg VC = fpr.R(c); ARM64Reg VD = fpr.R(d); - if (fpr.IsLower(d)) - { - m_float_emit.FNMSUB(EncodeRegToDouble(VD), EncodeRegToDouble(VA), EncodeRegToDouble(VC), EncodeRegToDouble(VB)); - } - else - { - ARM64Reg V0 = fpr.GetReg(); - m_float_emit.FNMSUB(EncodeRegToDouble(V0), EncodeRegToDouble(VA), EncodeRegToDouble(VC), EncodeRegToDouble(VB)); - m_float_emit.INS(64, VD, 0, V0, 0); - fpr.Unlock(V0); - } + m_float_emit.FNMSUB(EncodeRegToDouble(VD), EncodeRegToDouble(VA), EncodeRegToDouble(VC), EncodeRegToDouble(VB)); } void JitArm64::fmulsx(UGeckoInstruction inst) @@ -224,17 +184,7 @@ void JitArm64::fmulx(UGeckoInstruction inst) ARM64Reg VC = fpr.R(c); ARM64Reg VD = fpr.R(d); - if (fpr.IsLower(d)) - { - m_float_emit.FMUL(EncodeRegToDouble(VD), EncodeRegToDouble(VA), EncodeRegToDouble(VC)); - } - else - { - ARM64Reg V0 = fpr.GetReg(); - m_float_emit.FMUL(EncodeRegToDouble(V0), EncodeRegToDouble(VA), EncodeRegToDouble(VC)); - m_float_emit.INS(64, VD, 0, V0, 0); - fpr.Unlock(V0); - } + m_float_emit.FMUL(EncodeRegToDouble(VD), EncodeRegToDouble(VA), EncodeRegToDouble(VC)); } void JitArm64::fnabsx(UGeckoInstruction inst) @@ -249,19 +199,8 @@ void JitArm64::fnabsx(UGeckoInstruction inst) ARM64Reg VB = fpr.R(b); ARM64Reg VD = fpr.R(d); - if (fpr.IsLower(d)) - { - m_float_emit.FABS(EncodeRegToDouble(VD), EncodeRegToDouble(VB)); - m_float_emit.FNEG(EncodeRegToDouble(VD), EncodeRegToDouble(VD)); - } - else - { - ARM64Reg V0 = fpr.GetReg(); - m_float_emit.FABS(EncodeRegToDouble(V0), EncodeRegToDouble(VB)); - m_float_emit.FNEG(EncodeRegToDouble(V0), EncodeRegToDouble(V0)); - m_float_emit.INS(64, VD, 0, V0, 0); - fpr.Unlock(V0); - } + m_float_emit.FABS(EncodeRegToDouble(VD), EncodeRegToDouble(VB)); + m_float_emit.FNEG(EncodeRegToDouble(VD), EncodeRegToDouble(VD)); } void JitArm64::fnegx(UGeckoInstruction inst) @@ -276,17 +215,7 @@ void JitArm64::fnegx(UGeckoInstruction inst) ARM64Reg VB = fpr.R(b); ARM64Reg VD = fpr.R(d); - if (fpr.IsLower(d)) - { - m_float_emit.FNEG(EncodeRegToDouble(VD), EncodeRegToDouble(VB)); - } - else - { - ARM64Reg V0 = fpr.GetReg(); - m_float_emit.FNEG(EncodeRegToDouble(V0), EncodeRegToDouble(VB)); - m_float_emit.INS(64, VD, 0, V0, 0); - fpr.Unlock(V0); - } + m_float_emit.FNEG(EncodeRegToDouble(VD), EncodeRegToDouble(VB)); } void JitArm64::fnmaddsx(UGeckoInstruction inst) @@ -325,17 +254,7 @@ void JitArm64::fnmaddx(UGeckoInstruction inst) ARM64Reg VC = fpr.R(c); ARM64Reg VD = fpr.R(d); - if (fpr.IsLower(d)) - { - m_float_emit.FNMADD(EncodeRegToDouble(VD), EncodeRegToDouble(VA), EncodeRegToDouble(VC), EncodeRegToDouble(VB)); - } - else - { - ARM64Reg V0 = fpr.GetReg(); - m_float_emit.FNMADD(EncodeRegToDouble(V0), EncodeRegToDouble(VA), EncodeRegToDouble(VC), EncodeRegToDouble(VB)); - m_float_emit.INS(64, VD, 0, V0, 0); - fpr.Unlock(V0); - } + m_float_emit.FNMADD(EncodeRegToDouble(VD), EncodeRegToDouble(VA), EncodeRegToDouble(VC), EncodeRegToDouble(VB)); } void JitArm64::fnmsubsx(UGeckoInstruction inst) @@ -374,17 +293,7 @@ void JitArm64::fnmsubx(UGeckoInstruction inst) ARM64Reg VC = fpr.R(c); ARM64Reg VD = fpr.R(d); - if (fpr.IsLower(d)) - { - m_float_emit.FMSUB(EncodeRegToDouble(VD), EncodeRegToDouble(VA), EncodeRegToDouble(VC), EncodeRegToDouble(VB)); - } - else - { - ARM64Reg V0 = fpr.GetReg(); - m_float_emit.FMSUB(EncodeRegToDouble(V0), EncodeRegToDouble(VA), EncodeRegToDouble(VC), EncodeRegToDouble(VB)); - m_float_emit.INS(64, VD, 0, V0, 0); - fpr.Unlock(V0); - } + m_float_emit.FMSUB(EncodeRegToDouble(VD), EncodeRegToDouble(VA), EncodeRegToDouble(VC), EncodeRegToDouble(VB)); } void JitArm64::fselx(UGeckoInstruction inst) @@ -402,17 +311,7 @@ void JitArm64::fselx(UGeckoInstruction inst) ARM64Reg VC = fpr.R(c); m_float_emit.FCMPE(EncodeRegToDouble(VA)); - if (fpr.IsLower(d)) - { - m_float_emit.FCSEL(EncodeRegToDouble(VD), EncodeRegToDouble(VC), EncodeRegToDouble(VB), CC_GE); - } - else - { - ARM64Reg V0 = fpr.GetReg(); - m_float_emit.FCSEL(EncodeRegToDouble(V0), EncodeRegToDouble(VC), EncodeRegToDouble(VB), CC_GE); - m_float_emit.INS(64, VD, 0, V0, 0); - fpr.Unlock(V0); - } + m_float_emit.FCSEL(EncodeRegToDouble(VD), EncodeRegToDouble(VC), EncodeRegToDouble(VB), CC_GE); } void JitArm64::fsubsx(UGeckoInstruction inst) @@ -445,17 +344,7 @@ void JitArm64::fsubx(UGeckoInstruction inst) ARM64Reg VB = fpr.R(b); ARM64Reg VD = fpr.R(d); - if (fpr.IsLower(d)) - { - m_float_emit.FSUB(EncodeRegToDouble(VD), EncodeRegToDouble(VA), EncodeRegToDouble(VB)); - } - else - { - ARM64Reg V0 = fpr.GetReg(); - m_float_emit.FSUB(EncodeRegToDouble(V0), EncodeRegToDouble(VA), EncodeRegToDouble(VB)); - m_float_emit.INS(64, VD, 0, V0, 0); - fpr.Unlock(V0); - } + m_float_emit.FSUB(EncodeRegToDouble(VD), EncodeRegToDouble(VA), EncodeRegToDouble(VB)); } void JitArm64::frspx(UGeckoInstruction inst) @@ -576,21 +465,10 @@ void JitArm64::fctiwzx(UGeckoInstruction inst) // Generate 0xFFF8000000000000ULL m_float_emit.MOVI(64, EncodeRegToDouble(V0), 0xFFFF000000000000ULL); m_float_emit.BIC(16, EncodeRegToDouble(V0), 0x7); - if (fpr.IsLower(d)) - { - m_float_emit.FCVTN(32, EncodeRegToDouble(VD), EncodeRegToDouble(VB)); - m_float_emit.FCVTS(EncodeRegToSingle(VD), EncodeRegToSingle(VD), ROUND_Z); - m_float_emit.ORR(EncodeRegToDouble(VD), EncodeRegToDouble(VD), EncodeRegToDouble(V0)); - } - else - { - ARM64Reg V1 = fpr.GetReg(); - m_float_emit.FCVTN(32, EncodeRegToDouble(V1), EncodeRegToDouble(VB)); - m_float_emit.FCVTS(EncodeRegToSingle(V1), EncodeRegToSingle(V1), ROUND_Z); - m_float_emit.ORR(EncodeRegToDouble(V1), EncodeRegToDouble(V1), EncodeRegToDouble(V0)); - m_float_emit.INS(64, VD, 0, V1, 0); - fpr.Unlock(V1); - } + + m_float_emit.FCVTN(32, EncodeRegToDouble(VD), EncodeRegToDouble(VB)); + m_float_emit.FCVTS(EncodeRegToSingle(VD), EncodeRegToSingle(VD), ROUND_Z); + m_float_emit.ORR(EncodeRegToDouble(VD), EncodeRegToDouble(VD), EncodeRegToDouble(V0)); fpr.Unlock(V0); } @@ -607,17 +485,7 @@ void JitArm64::fdivx(UGeckoInstruction inst) ARM64Reg VB = fpr.R(b); ARM64Reg VD = fpr.R(d); - if (fpr.IsLower(d)) - { - m_float_emit.FDIV(EncodeRegToDouble(VD), EncodeRegToDouble(VA), EncodeRegToDouble(VB)); - } - else - { - ARM64Reg V0 = fpr.GetReg(); - m_float_emit.FDIV(EncodeRegToDouble(V0), EncodeRegToDouble(VA), EncodeRegToDouble(VB)); - m_float_emit.INS(64, VD, 0, V0, 0); - fpr.Unlock(V0); - } + m_float_emit.FDIV(EncodeRegToDouble(VD), EncodeRegToDouble(VA), EncodeRegToDouble(VB)); } void JitArm64::fdivsx(UGeckoInstruction inst) diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.cpp index a2e16ef88a..27b021cf8a 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.cpp @@ -330,6 +330,7 @@ void Arm64FPRCache::BindToRegister(u32 preg, bool do_load, bool only_lower) { OpArg& reg = m_guest_registers[preg]; + bool was_dirty = reg.IsDirty(); reg.SetDirty(true); switch (reg.GetType()) { @@ -372,6 +373,20 @@ void Arm64FPRCache::BindToRegister(u32 preg, bool do_load, bool only_lower) } } break; + case REG_REG: + { + if (only_lower) + { + // If we only want the lower bits, let's store away the high bits and drop to a lower only register + // We are doing a full 128bit store because it takes 2 cycles on a Cortex-A57 to do a 128bit store. + // It would take longer to do an insert to a temporary and a 64bit store than to just do this. + ARM64Reg host_reg = reg.GetReg(); + if (was_dirty) + m_float_emit->STR(128, INDEX_UNSIGNED, host_reg, X29, PPCSTATE_OFF(ps[preg][0])); + reg.LoadLowerReg(host_reg); + } + } + break; default: // Do nothing break;