Merge pull request #6571 from lioncash/rotate
CommonFuncs: Generify rotation functions and move them to BitUtils.h
This commit is contained in:
commit
2449be7f0c
|
@ -100,6 +100,50 @@ constexpr Result ExtractBits(const T src) noexcept
|
|||
return ExtractBits<T, Result>(src, begin, end);
|
||||
}
|
||||
|
||||
///
|
||||
/// Rotates a value left (ROL).
|
||||
///
|
||||
/// @param value The value to rotate.
|
||||
/// @param amount The number of bits to rotate the value.
|
||||
/// @tparam T An unsigned type.
|
||||
///
|
||||
/// @return The rotated value.
|
||||
///
|
||||
template <typename T>
|
||||
constexpr T RotateLeft(const T value, size_t amount) noexcept
|
||||
{
|
||||
static_assert(std::is_unsigned<T>(), "Can only rotate unsigned types left.");
|
||||
|
||||
amount %= BitSize<T>();
|
||||
|
||||
if (amount == 0)
|
||||
return value;
|
||||
|
||||
return static_cast<T>((value << amount) | (value >> (BitSize<T>() - amount)));
|
||||
}
|
||||
|
||||
///
|
||||
/// Rotates a value right (ROR).
|
||||
///
|
||||
/// @param value The value to rotate.
|
||||
/// @param amount The number of bits to rotate the value.
|
||||
/// @tparam T An unsigned type.
|
||||
///
|
||||
/// @return The rotated value.
|
||||
///
|
||||
template <typename T>
|
||||
constexpr T RotateRight(const T value, size_t amount) noexcept
|
||||
{
|
||||
static_assert(std::is_unsigned<T>(), "Can only rotate unsigned types right.");
|
||||
|
||||
amount %= BitSize<T>();
|
||||
|
||||
if (amount == 0)
|
||||
return value;
|
||||
|
||||
return static_cast<T>((value >> amount) | (value << (BitSize<T>() - amount)));
|
||||
}
|
||||
|
||||
///
|
||||
/// Verifies whether the supplied value is a valid bit mask of the form 0b00...0011...11.
|
||||
/// Both edge cases of all zeros and all ones are considered valid masks, too.
|
||||
|
|
|
@ -30,38 +30,6 @@ constexpr size_t ArraySize(T (&arr)[N])
|
|||
__builtin_trap(); \
|
||||
}
|
||||
|
||||
// GCC 4.8 defines all the rotate functions now
|
||||
// Small issue with GCC's lrotl/lrotr intrinsics is they are still 32bit while we require 64bit
|
||||
#ifndef _rotl
|
||||
inline u32 _rotl(u32 x, int shift)
|
||||
{
|
||||
shift &= 31;
|
||||
if (!shift)
|
||||
return x;
|
||||
return (x << shift) | (x >> (32 - shift));
|
||||
}
|
||||
|
||||
inline u32 _rotr(u32 x, int shift)
|
||||
{
|
||||
shift &= 31;
|
||||
if (!shift)
|
||||
return x;
|
||||
return (x >> shift) | (x << (32 - shift));
|
||||
}
|
||||
#endif
|
||||
|
||||
inline u64 _rotl64(u64 x, unsigned int shift)
|
||||
{
|
||||
unsigned int n = shift % 64;
|
||||
return (x << n) | (x >> (64 - n));
|
||||
}
|
||||
|
||||
inline u64 _rotr64(u64 x, unsigned int shift)
|
||||
{
|
||||
unsigned int n = shift % 64;
|
||||
return (x >> n) | (x << (64 - n));
|
||||
}
|
||||
|
||||
#else // WIN32
|
||||
// Function Cross-Compatibility
|
||||
#define strcasecmp _stricmp
|
||||
|
|
|
@ -3,8 +3,10 @@
|
|||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Common/Hash.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include "Common/BitUtils.h"
|
||||
#include "Common/CPUDetect.h"
|
||||
#include "Common/CommonFuncs.h"
|
||||
#include "Common/Intrinsics.h"
|
||||
|
@ -117,15 +119,15 @@ static u64 getblock(const u64* p, int i)
|
|||
static void bmix64(u64& h1, u64& h2, u64& k1, u64& k2, u64& c1, u64& c2)
|
||||
{
|
||||
k1 *= c1;
|
||||
k1 = _rotl64(k1, 23);
|
||||
k1 = Common::RotateLeft(k1, 23);
|
||||
k1 *= c2;
|
||||
h1 ^= k1;
|
||||
h1 += h2;
|
||||
|
||||
h2 = _rotl64(h2, 41);
|
||||
h2 = Common::RotateLeft(h2, 41);
|
||||
|
||||
k2 *= c2;
|
||||
k2 = _rotl64(k2, 23);
|
||||
k2 = Common::RotateLeft(k2, 23);
|
||||
k2 *= c1;
|
||||
h2 ^= k2;
|
||||
h2 += h1;
|
||||
|
@ -396,15 +398,15 @@ static u32 fmix32(u32 h)
|
|||
static void bmix32(u32& h1, u32& h2, u32& k1, u32& k2, u32& c1, u32& c2)
|
||||
{
|
||||
k1 *= c1;
|
||||
k1 = _rotl(k1, 11);
|
||||
k1 = Common::RotateLeft(k1, 11);
|
||||
k1 *= c2;
|
||||
h1 ^= k1;
|
||||
h1 += h2;
|
||||
|
||||
h2 = _rotl(h2, 17);
|
||||
h2 = Common::RotateLeft(h2, 17);
|
||||
|
||||
k2 *= c2;
|
||||
k2 = _rotl(k2, 11);
|
||||
k2 = Common::RotateLeft(k2, 11);
|
||||
k2 *= c1;
|
||||
h2 ^= k2;
|
||||
h2 += h1;
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "Common/CommonFuncs.h"
|
||||
#include "Common/BitUtils.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
#include "Common/Swap.h"
|
||||
|
@ -251,26 +251,26 @@ static void unscramble1(u32* addr, u32* val)
|
|||
{
|
||||
u32 tmp;
|
||||
|
||||
*val = _rotl(*val, 4);
|
||||
*val = Common::RotateLeft(*val, 4);
|
||||
|
||||
tmp = ((*addr ^ *val) & 0xF0F0F0F0);
|
||||
*addr ^= tmp;
|
||||
*val = _rotr((*val ^ tmp), 0x14);
|
||||
*val = Common::RotateRight((*val ^ tmp), 0x14);
|
||||
|
||||
tmp = ((*addr ^ *val) & 0xFFFF0000);
|
||||
*addr ^= tmp;
|
||||
*val = _rotr((*val ^ tmp), 0x12);
|
||||
*val = Common::RotateRight((*val ^ tmp), 0x12);
|
||||
|
||||
tmp = ((*addr ^ *val) & 0x33333333);
|
||||
*addr ^= tmp;
|
||||
*val = _rotr((*val ^ tmp), 6);
|
||||
*val = Common::RotateRight((*val ^ tmp), 6);
|
||||
|
||||
tmp = ((*addr ^ *val) & 0x00FF00FF);
|
||||
*addr ^= tmp;
|
||||
*val = _rotl((*val ^ tmp), 9);
|
||||
*val = Common::RotateLeft((*val ^ tmp), 9);
|
||||
|
||||
tmp = ((*addr ^ *val) & 0xAAAAAAAA);
|
||||
*addr = _rotl((*addr ^ tmp), 1);
|
||||
*addr = Common::RotateLeft((*addr ^ tmp), 1);
|
||||
*val ^= tmp;
|
||||
}
|
||||
|
||||
|
@ -278,27 +278,27 @@ static void unscramble2(u32* addr, u32* val)
|
|||
{
|
||||
u32 tmp;
|
||||
|
||||
*val = _rotr(*val, 1);
|
||||
*val = Common::RotateRight(*val, 1);
|
||||
|
||||
tmp = ((*addr ^ *val) & 0xAAAAAAAA);
|
||||
*val ^= tmp;
|
||||
*addr = _rotr((*addr ^ tmp), 9);
|
||||
*addr = Common::RotateRight((*addr ^ tmp), 9);
|
||||
|
||||
tmp = ((*addr ^ *val) & 0x00FF00FF);
|
||||
*val ^= tmp;
|
||||
*addr = _rotl((*addr ^ tmp), 6);
|
||||
*addr = Common::RotateLeft((*addr ^ tmp), 6);
|
||||
|
||||
tmp = ((*addr ^ *val) & 0x33333333);
|
||||
*val ^= tmp;
|
||||
*addr = _rotl((*addr ^ tmp), 0x12);
|
||||
*addr = Common::RotateLeft((*addr ^ tmp), 0x12);
|
||||
|
||||
tmp = ((*addr ^ *val) & 0xFFFF0000);
|
||||
*val ^= tmp;
|
||||
*addr = _rotl((*addr ^ tmp), 0x14);
|
||||
*addr = Common::RotateLeft((*addr ^ tmp), 0x14);
|
||||
|
||||
tmp = ((*addr ^ *val) & 0xF0F0F0F0);
|
||||
*val ^= tmp;
|
||||
*addr = _rotr((*addr ^ tmp), 4);
|
||||
*addr = Common::RotateRight((*addr ^ tmp), 4);
|
||||
}
|
||||
|
||||
static void decryptcode(const u32* seeds, u32* code)
|
||||
|
@ -311,13 +311,13 @@ static void decryptcode(const u32* seeds, u32* code)
|
|||
unscramble1(&addr, &val);
|
||||
while (i < 32)
|
||||
{
|
||||
tmp = (_rotr(val, 4) ^ seeds[i++]);
|
||||
tmp = (Common::RotateRight(val, 4) ^ seeds[i++]);
|
||||
tmp2 = (val ^ seeds[i++]);
|
||||
addr ^= (table6[tmp & 0x3F] ^ table4[(tmp >> 8) & 0x3F] ^ table2[(tmp >> 16) & 0x3F] ^
|
||||
table0[(tmp >> 24) & 0x3F] ^ table7[tmp2 & 0x3F] ^ table5[(tmp2 >> 8) & 0x3F] ^
|
||||
table3[(tmp2 >> 16) & 0x3F] ^ table1[(tmp2 >> 24) & 0x3F]);
|
||||
|
||||
tmp = (_rotr(addr, 4) ^ seeds[i++]);
|
||||
tmp = (Common::RotateRight(addr, 4) ^ seeds[i++]);
|
||||
tmp2 = (addr ^ seeds[i++]);
|
||||
val ^= (table6[tmp & 0x3F] ^ table4[(tmp >> 8) & 0x3F] ^ table2[(tmp >> 16) & 0x3F] ^
|
||||
table0[(tmp >> 24) & 0x3F] ^ table7[tmp2 & 0x3F] ^ table5[(tmp2 >> 8) & 0x3F] ^
|
||||
|
|
|
@ -4,10 +4,9 @@
|
|||
|
||||
#include "Core/PowerPC/Interpreter/Interpreter.h"
|
||||
|
||||
#include "Common/CommonFuncs.h"
|
||||
#include "Common/BitUtils.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
|
||||
void Interpreter::Helper_UpdateCR0(u32 value)
|
||||
|
@ -172,7 +171,7 @@ void Interpreter::xoris(UGeckoInstruction inst)
|
|||
void Interpreter::rlwimix(UGeckoInstruction inst)
|
||||
{
|
||||
u32 mask = Helper_Mask(inst.MB, inst.ME);
|
||||
rGPR[inst.RA] = (rGPR[inst.RA] & ~mask) | (_rotl(rGPR[inst.RS], inst.SH) & mask);
|
||||
rGPR[inst.RA] = (rGPR[inst.RA] & ~mask) | (Common::RotateLeft(rGPR[inst.RS], inst.SH) & mask);
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR0(rGPR[inst.RA]);
|
||||
|
@ -181,7 +180,7 @@ void Interpreter::rlwimix(UGeckoInstruction inst)
|
|||
void Interpreter::rlwinmx(UGeckoInstruction inst)
|
||||
{
|
||||
u32 mask = Helper_Mask(inst.MB, inst.ME);
|
||||
rGPR[inst.RA] = _rotl(rGPR[inst.RS], inst.SH) & mask;
|
||||
rGPR[inst.RA] = Common::RotateLeft(rGPR[inst.RS], inst.SH) & mask;
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR0(rGPR[inst.RA]);
|
||||
|
@ -190,7 +189,7 @@ void Interpreter::rlwinmx(UGeckoInstruction inst)
|
|||
void Interpreter::rlwnmx(UGeckoInstruction inst)
|
||||
{
|
||||
u32 mask = Helper_Mask(inst.MB, inst.ME);
|
||||
rGPR[inst.RA] = _rotl(rGPR[inst.RS], rGPR[inst.RB] & 0x1F) & mask;
|
||||
rGPR[inst.RA] = Common::RotateLeft(rGPR[inst.RS], rGPR[inst.RB] & 0x1F) & mask;
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR0(rGPR[inst.RA]);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include "Common/Assert.h"
|
||||
#include "Common/BitUtils.h"
|
||||
#include "Common/CPUDetect.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/MathUtil.h"
|
||||
|
@ -1435,7 +1436,7 @@ void Jit64::rlwinmx(UGeckoInstruction inst)
|
|||
{
|
||||
u32 result = gpr.R(s).Imm32();
|
||||
if (inst.SH != 0)
|
||||
result = _rotl(result, inst.SH);
|
||||
result = Common::RotateLeft(result, inst.SH);
|
||||
result &= Helper_Mask(inst.MB, inst.ME);
|
||||
gpr.SetImmediate32(a, result);
|
||||
if (inst.Rc)
|
||||
|
@ -1520,7 +1521,8 @@ void Jit64::rlwimix(UGeckoInstruction inst)
|
|||
if (gpr.R(a).IsImm() && gpr.R(s).IsImm())
|
||||
{
|
||||
u32 mask = Helper_Mask(inst.MB, inst.ME);
|
||||
gpr.SetImmediate32(a, (gpr.R(a).Imm32() & ~mask) | (_rotl(gpr.R(s).Imm32(), inst.SH) & mask));
|
||||
gpr.SetImmediate32(a, (gpr.R(a).Imm32() & ~mask) |
|
||||
(Common::RotateLeft(gpr.R(s).Imm32(), inst.SH) & mask));
|
||||
if (inst.Rc)
|
||||
ComputeRC(gpr.R(a));
|
||||
}
|
||||
|
@ -1546,7 +1548,7 @@ void Jit64::rlwimix(UGeckoInstruction inst)
|
|||
{
|
||||
gpr.BindToRegister(a, true, true);
|
||||
AndWithMask(gpr.RX(a), ~mask);
|
||||
OR(32, gpr.R(a), Imm32(_rotl(gpr.R(s).Imm32(), inst.SH) & mask));
|
||||
OR(32, gpr.R(a), Imm32(Common::RotateLeft(gpr.R(s).Imm32(), inst.SH) & mask));
|
||||
}
|
||||
else if (inst.SH)
|
||||
{
|
||||
|
@ -1620,7 +1622,7 @@ void Jit64::rlwnmx(UGeckoInstruction inst)
|
|||
u32 mask = Helper_Mask(inst.MB, inst.ME);
|
||||
if (gpr.R(b).IsImm() && gpr.R(s).IsImm())
|
||||
{
|
||||
gpr.SetImmediate32(a, _rotl(gpr.R(s).Imm32(), gpr.R(b).Imm32() & 0x1F) & mask);
|
||||
gpr.SetImmediate32(a, Common::RotateLeft(gpr.R(s).Imm32(), gpr.R(b).Imm32() & 0x1F) & mask);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "Common/Arm64Emitter.h"
|
||||
#include "Common/Assert.h"
|
||||
#include "Common/BitUtils.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
#include "Core/Core.h"
|
||||
|
@ -534,7 +535,7 @@ void JitArm64::rlwinmx(UGeckoInstruction inst)
|
|||
u32 mask = Helper_Mask(inst.MB, inst.ME);
|
||||
if (gpr.IsImm(inst.RS))
|
||||
{
|
||||
gpr.SetImmediate(a, _rotl(gpr.GetImm(s), inst.SH) & mask);
|
||||
gpr.SetImmediate(a, Common::RotateLeft(gpr.GetImm(s), inst.SH) & mask);
|
||||
if (inst.Rc)
|
||||
ComputeRC0(gpr.GetImm(a));
|
||||
return;
|
||||
|
@ -583,7 +584,7 @@ void JitArm64::rlwnmx(UGeckoInstruction inst)
|
|||
|
||||
if (gpr.IsImm(b) && gpr.IsImm(s))
|
||||
{
|
||||
gpr.SetImmediate(a, _rotl(gpr.GetImm(s), gpr.GetImm(b) & 0x1F) & mask);
|
||||
gpr.SetImmediate(a, Common::RotateLeft(gpr.GetImm(s), gpr.GetImm(b) & 0x1F) & mask);
|
||||
if (inst.Rc)
|
||||
ComputeRC0(gpr.GetImm(a));
|
||||
}
|
||||
|
@ -1437,7 +1438,7 @@ void JitArm64::rlwimix(UGeckoInstruction inst)
|
|||
|
||||
if (gpr.IsImm(a) && gpr.IsImm(s))
|
||||
{
|
||||
u32 res = (gpr.GetImm(a) & ~mask) | (_rotl(gpr.GetImm(s), inst.SH) & mask);
|
||||
u32 res = (gpr.GetImm(a) & ~mask) | (Common::RotateLeft(gpr.GetImm(s), inst.SH) & mask);
|
||||
gpr.SetImmediate(a, res);
|
||||
if (inst.Rc)
|
||||
ComputeRC0(res);
|
||||
|
|
|
@ -58,6 +58,44 @@ TEST(BitUtils, ExtractBits)
|
|||
EXPECT_EQ((Common::ExtractBits<0, 31, s32, s32>(negative_one)), -1);
|
||||
}
|
||||
|
||||
TEST(BitUtils, RotateLeft)
|
||||
{
|
||||
EXPECT_EQ(Common::RotateLeft(0xF0F0F0F0, 0), 0xF0F0F0F0);
|
||||
EXPECT_EQ(Common::RotateLeft(0xF0F0F0F0, 4), 0x0F0F0F0F);
|
||||
EXPECT_EQ(Common::RotateLeft(0xF0F0F0F0, 8), 0xF0F0F0F0);
|
||||
EXPECT_EQ(Common::RotateLeft(0xF0F0F0F0F0F0F0F0, 0), 0xF0F0F0F0F0F0F0F0);
|
||||
EXPECT_EQ(Common::RotateLeft(0xF0F0F0F0F0F0F0F0, 4), 0x0F0F0F0F0F0F0F0F);
|
||||
EXPECT_EQ(Common::RotateLeft(0xF0F0F0F0F0F0F0F0, 8), 0xF0F0F0F0F0F0F0F0);
|
||||
|
||||
EXPECT_EQ(Common::RotateLeft(0xF1F1F1F1, 1), 0xE3E3E3E3);
|
||||
EXPECT_EQ(Common::RotateLeft(0xF1F1F1F1, 2), 0xC7C7C7C7);
|
||||
EXPECT_EQ(Common::RotateLeft(0xF1F1F1F1, 3), 0x8F8F8F8F);
|
||||
EXPECT_EQ(Common::RotateLeft(0xF1F1F1F1, 4), 0x1F1F1F1F);
|
||||
EXPECT_EQ(Common::RotateLeft(0xF1F1F1F1F1F1F1F1, 1), 0xE3E3E3E3E3E3E3E3);
|
||||
EXPECT_EQ(Common::RotateLeft(0xF1F1F1F1F1F1F1F1, 2), 0xC7C7C7C7C7C7C7C7);
|
||||
EXPECT_EQ(Common::RotateLeft(0xF1F1F1F1F1F1F1F1, 3), 0x8F8F8F8F8F8F8F8F);
|
||||
EXPECT_EQ(Common::RotateLeft(0xF1F1F1F1F1F1F1F1, 4), 0x1F1F1F1F1F1F1F1F);
|
||||
}
|
||||
|
||||
TEST(BitUtils, RotateRight)
|
||||
{
|
||||
EXPECT_EQ(Common::RotateRight(0xF0F0F0F0, 0), 0xF0F0F0F0);
|
||||
EXPECT_EQ(Common::RotateRight(0xF0F0F0F0, 4), 0x0F0F0F0F);
|
||||
EXPECT_EQ(Common::RotateRight(0xF0F0F0F0, 8), 0xF0F0F0F0);
|
||||
EXPECT_EQ(Common::RotateRight(0xF0F0F0F0F0F0F0F0, 0), 0xF0F0F0F0F0F0F0F0);
|
||||
EXPECT_EQ(Common::RotateRight(0xF0F0F0F0F0F0F0F0, 4), 0x0F0F0F0F0F0F0F0F);
|
||||
EXPECT_EQ(Common::RotateRight(0xF0F0F0F0F0F0F0F0, 8), 0xF0F0F0F0F0F0F0F0);
|
||||
|
||||
EXPECT_EQ(Common::RotateRight(0xF1F1F1F1, 1), 0xF8F8F8F8);
|
||||
EXPECT_EQ(Common::RotateRight(0xF1F1F1F1, 2), 0x7C7C7C7C);
|
||||
EXPECT_EQ(Common::RotateRight(0xF1F1F1F1, 3), 0x3E3E3E3E);
|
||||
EXPECT_EQ(Common::RotateRight(0xF1F1F1F1, 4), 0x1F1F1F1F);
|
||||
EXPECT_EQ(Common::RotateRight(0xF1F1F1F1F1F1F1F1, 1), 0xF8F8F8F8F8F8F8F8);
|
||||
EXPECT_EQ(Common::RotateRight(0xF1F1F1F1F1F1F1F1, 2), 0x7C7C7C7C7C7C7C7C);
|
||||
EXPECT_EQ(Common::RotateRight(0xF1F1F1F1F1F1F1F1, 3), 0x3E3E3E3E3E3E3E3E);
|
||||
EXPECT_EQ(Common::RotateRight(0xF1F1F1F1F1F1F1F1, 4), 0x1F1F1F1F1F1F1F1F);
|
||||
}
|
||||
|
||||
TEST(BitUtils, IsValidLowMask)
|
||||
{
|
||||
EXPECT_TRUE(Common::IsValidLowMask(0b0u));
|
||||
|
|
Loading…
Reference in New Issue