From 79f40fb8d7b5a0d1efb47cd2d4a0661be9772d0e Mon Sep 17 00:00:00 2001 From: Lioncash Date: Fri, 23 Mar 2018 09:50:09 -0400 Subject: [PATCH 1/5] MathUtil: Generify IsPow2 This will allow it to also be used in the AArch64 emitter. --- Source/Core/Common/MathUtil.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Source/Core/Common/MathUtil.h b/Source/Core/Common/MathUtil.h index becaf09792..58aad3522d 100644 --- a/Source/Core/Common/MathUtil.h +++ b/Source/Core/Common/MathUtil.h @@ -49,9 +49,10 @@ constexpr T Clamp(const T val, const T& min, const T& max) return std::max(min, std::min(max, val)); } -constexpr bool IsPow2(u32 imm) +template +constexpr bool IsPow2(T imm) { - return (imm & (imm - 1)) == 0; + return imm > 0 && (imm & (imm - 1)) == 0; } // The most significant bit of the fraction is an is-quiet bit on all architectures we care about. From 03671a55344bb1ee33eb50d86a5f8cfc1c2e4aa1 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Fri, 23 Mar 2018 10:10:15 -0400 Subject: [PATCH 2/5] Arm64Emitter: Remove duplicate IsPowerOf2 function We can just use the generified version in MathUtil. --- Source/Core/Common/Arm64Emitter.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Source/Core/Common/Arm64Emitter.cpp b/Source/Core/Common/Arm64Emitter.cpp index eb5c17c69a..139d90d40e 100644 --- a/Source/Core/Common/Arm64Emitter.cpp +++ b/Source/Core/Common/Arm64Emitter.cpp @@ -12,6 +12,7 @@ #include "Common/Arm64Emitter.h" #include "Common/Assert.h" #include "Common/CommonTypes.h" +#include "Common/MathUtil.h" namespace Arm64Gen { @@ -37,11 +38,6 @@ static uint64_t LargestPowerOf2Divisor(uint64_t value) return value & -(int64_t)value; } -static bool IsPowerOfTwo(uint64_t x) -{ - return (x != 0) && ((x & (x - 1)) == 0); -} - #define V8_UINT64_C(x) ((uint64_t)(x)) bool IsImmArithmetic(uint64_t input, u32* val, bool* shift) @@ -187,7 +183,7 @@ bool IsImmLogical(uint64_t value, unsigned int width, unsigned int* n, unsigned } // If the repeat period d is not a power of two, it can't be encoded. - if (!IsPowerOfTwo(d)) + if (!MathUtil::IsPow2(d)) return false; // If the bit stretch (b - a) does not fit within the mask derived from the From b11c237c43a43be445ad2c20b6b8a32a2d59eceb Mon Sep 17 00:00:00 2001 From: Lioncash Date: Fri, 23 Mar 2018 10:13:50 -0400 Subject: [PATCH 3/5] Arm64Emitter: Remove unnecessary V8_UINT64_C preprocessor macro UINT64_C is provided via , so we can just use that instead. --- Source/Core/Common/Arm64Emitter.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Source/Core/Common/Arm64Emitter.cpp b/Source/Core/Common/Arm64Emitter.cpp index 139d90d40e..2430db8b0a 100644 --- a/Source/Core/Common/Arm64Emitter.cpp +++ b/Source/Core/Common/Arm64Emitter.cpp @@ -38,8 +38,6 @@ static uint64_t LargestPowerOf2Divisor(uint64_t value) return value & -(int64_t)value; } -#define V8_UINT64_C(x) ((uint64_t)(x)) - bool IsImmArithmetic(uint64_t input, u32* val, bool* shift) { if (input < 4096) @@ -151,7 +149,7 @@ bool IsImmLogical(uint64_t value, unsigned int width, unsigned int* n, unsigned clz_a = CountLeadingZeros(a, kXRegSizeInBits); int clz_c = CountLeadingZeros(c, kXRegSizeInBits); d = clz_a - clz_c; - mask = ((V8_UINT64_C(1) << d) - 1); + mask = ((UINT64_C(1) << d) - 1); out_n = 0; } else @@ -177,7 +175,7 @@ bool IsImmLogical(uint64_t value, unsigned int width, unsigned int* n, unsigned // the general case above, and set the N bit in the output. clz_a = CountLeadingZeros(a, kXRegSizeInBits); d = 64; - mask = ~V8_UINT64_C(0); + mask = ~UINT64_C(0); out_n = 1; } } From 91cefe6c8a4e42498573a12fce4c6633ba4ae780 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Fri, 23 Mar 2018 10:17:09 -0400 Subject: [PATCH 4/5] Arm64Emitter: Make IsImmArithmetic, IsImmLogical, FPImm8ToFloat, and FPImm8FromFloat internally linked These aren't used anywhere outside of the emitter. Centralizes them under an anonymous namespace. --- Source/Core/Common/Arm64Emitter.cpp | 73 +++++++++++++++-------------- Source/Core/Common/Arm64Emitter.h | 9 ---- 2 files changed, 39 insertions(+), 43 deletions(-) diff --git a/Source/Core/Common/Arm64Emitter.cpp b/Source/Core/Common/Arm64Emitter.cpp index 2430db8b0a..7a6fbd53e2 100644 --- a/Source/Core/Common/Arm64Emitter.cpp +++ b/Source/Core/Common/Arm64Emitter.cpp @@ -16,11 +16,13 @@ namespace Arm64Gen { +namespace +{ const int kWRegSizeInBits = 32; const int kXRegSizeInBits = 64; // The below few functions are taken from V8. -static int CountLeadingZeros(uint64_t value, int width) +int CountLeadingZeros(uint64_t value, int width) { // TODO(jbramley): Optimize this for ARM64 hosts. int count = 0; @@ -33,11 +35,12 @@ static int CountLeadingZeros(uint64_t value, int width) return count; } -static uint64_t LargestPowerOf2Divisor(uint64_t value) +uint64_t LargestPowerOf2Divisor(uint64_t value) { return value & -(int64_t)value; } +// For ADD/SUB bool IsImmArithmetic(uint64_t input, u32* val, bool* shift) { if (input < 4096) @@ -55,6 +58,7 @@ bool IsImmArithmetic(uint64_t input, u32* val, bool* shift) return false; } +// For AND/TST/ORR/EOR etc bool IsImmLogical(uint64_t value, unsigned int width, unsigned int* n, unsigned int* imm_s, unsigned int* imm_r) { @@ -260,6 +264,39 @@ bool IsImmLogical(uint64_t value, unsigned int width, unsigned int* n, unsigned return true; } +float FPImm8ToFloat(uint8_t bits) +{ + int sign = bits >> 7; + uint32_t f = (sign << 31); + int bit6 = (bits >> 6) & 1; + uint32_t exp = ((!bit6) << 7) | (0x7C * bit6) | ((bits >> 4) & 3); + uint32_t mantissa = (bits & 0xF) << 19; + f |= exp << 23; + f |= mantissa; + float fl; + memcpy(&fl, &f, sizeof(float)); + return fl; +} + +bool FPImm8FromFloat(float value, uint8_t* immOut) +{ + uint32_t f; + memcpy(&f, &value, sizeof(float)); + uint32_t mantissa4 = (f & 0x7FFFFF) >> 19; + uint32_t exponent = (f >> 23) & 0xFF; + uint32_t sign = f >> 31; + if ((exponent >> 7) == ((exponent >> 6) & 1)) + return false; + uint8_t imm8 = (sign << 7) | ((!(exponent >> 7)) << 6) | ((exponent & 3) << 4) | mantissa4; + float newFloat = FPImm8ToFloat(imm8); + if (newFloat == value) + *immOut = imm8; + else + return false; + return true; +} +} // Anonymous namespace + void ARM64XEmitter::SetCodePtrUnsafe(u8* ptr) { m_code = ptr; @@ -4287,38 +4324,6 @@ bool ARM64XEmitter::TryEORI2R(ARM64Reg Rd, ARM64Reg Rn, u32 imm) return true; } -float FPImm8ToFloat(uint8_t bits) -{ - int sign = bits >> 7; - uint32_t f = (sign << 31); - int bit6 = (bits >> 6) & 1; - uint32_t exp = ((!bit6) << 7) | (0x7C * bit6) | ((bits >> 4) & 3); - uint32_t mantissa = (bits & 0xF) << 19; - f |= exp << 23; - f |= mantissa; - float fl; - memcpy(&fl, &f, sizeof(float)); - return fl; -} - -bool FPImm8FromFloat(float value, uint8_t* immOut) -{ - uint32_t f; - memcpy(&f, &value, sizeof(float)); - uint32_t mantissa4 = (f & 0x7FFFFF) >> 19; - uint32_t exponent = (f >> 23) & 0xFF; - uint32_t sign = f >> 31; - if ((exponent >> 7) == ((exponent >> 6) & 1)) - return false; - uint8_t imm8 = (sign << 7) | ((!(exponent >> 7)) << 6) | ((exponent & 3) << 4) | mantissa4; - float newFloat = FPImm8ToFloat(imm8); - if (newFloat == value) - *immOut = imm8; - else - return false; - return true; -} - void ARM64FloatEmitter::MOVI2F(ARM64Reg Rd, float value, ARM64Reg scratch, bool negate) { ASSERT_MSG(DYNA_REC, !IsDouble(Rd), "MOVI2F does not yet support double precision"); diff --git a/Source/Core/Common/Arm64Emitter.h b/Source/Core/Common/Arm64Emitter.h index 8e9ceaa842..22d27284d5 100644 --- a/Source/Core/Common/Arm64Emitter.h +++ b/Source/Core/Common/Arm64Emitter.h @@ -277,15 +277,6 @@ constexpr ARM64Reg EncodeRegToQuad(ARM64Reg reg) return static_cast(reg | 0xC0); } -// For AND/TST/ORR/EOR etc -bool IsImmLogical(uint64_t value, unsigned int width, unsigned int* n, unsigned int* imm_s, - unsigned int* imm_r); -// For ADD/SUB -bool IsImmArithmetic(uint64_t input, u32* val, bool* shift); - -float FPImm8ToFloat(uint8_t bits); -bool FPImm8FromFloat(float value, uint8_t* immOut); - enum OpType { TYPE_IMM = 0, From f889cae8c4f8691573affb2cab29aa6665cd19b5 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Fri, 23 Mar 2018 13:25:17 -0400 Subject: [PATCH 5/5] Arm64Emitter: Satisfy unrelated linter issues that cropped up by modifying the cpp file --- Source/Core/Common/Arm64Emitter.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Source/Core/Common/Arm64Emitter.cpp b/Source/Core/Common/Arm64Emitter.cpp index 7a6fbd53e2..2ff15df5c6 100644 --- a/Source/Core/Common/Arm64Emitter.cpp +++ b/Source/Core/Common/Arm64Emitter.cpp @@ -3771,8 +3771,7 @@ void ARM64FloatEmitter::UXTL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, bool upper) // vector x indexed element void ARM64FloatEmitter::FMUL(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, u8 index) { - ASSERT_MSG(DYNA_REC, size == 32 || size == 64, "%s only supports 32bit or 64bit size!", - __func__); + ASSERT_MSG(DYNA_REC, size == 32 || size == 64, "%s only supports 32bit or 64bit size!", __func__); bool L = false; bool H = false; @@ -3791,8 +3790,7 @@ void ARM64FloatEmitter::FMUL(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, u8 void ARM64FloatEmitter::FMLA(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, u8 index) { - ASSERT_MSG(DYNA_REC, size == 32 || size == 64, "%s only supports 32bit or 64bit size!", - __func__); + ASSERT_MSG(DYNA_REC, size == 32 || size == 64, "%s only supports 32bit or 64bit size!", __func__); bool L = false; bool H = false;