Commit 02548aa0 authored by Ben Maurer's avatar Ben Maurer Committed by Facebook Github Bot

prevPowTwo / faster bit operations

Summary:
Add a prevPowTwo method to bits.h and optimize the current code for
GCCs output.

Reviewed By: ot

Differential Revision: D4072341

fbshipit-source-id: 6e949d0bfcf88ff8500022939d08a2b5aa9e00c9
parent 78753f62
......@@ -143,7 +143,9 @@ typename std::enable_if<
sizeof(T) <= sizeof(unsigned int)),
unsigned int>::type
findLastSet(T x) {
return x ? 8 * sizeof(unsigned int) - __builtin_clz(x) : 0;
// If X is a power of two X - Y = ((X - 1) ^ Y) + 1. Doing this transformation
// allows GCC to remove its own xor that it adds to implement clz using bsr
return x ? ((8 * sizeof(unsigned int) - 1) ^ __builtin_clz(x)) + 1 : 0;
}
template <class T>
......@@ -155,7 +157,7 @@ typename std::enable_if<
sizeof(T) <= sizeof(unsigned long)),
unsigned int>::type
findLastSet(T x) {
return x ? 8 * sizeof(unsigned long) - __builtin_clzl(x) : 0;
return x ? ((8 * sizeof(unsigned long) - 1) ^ __builtin_clzl(x)) + 1 : 0;
}
template <class T>
......@@ -167,7 +169,8 @@ typename std::enable_if<
sizeof(T) <= sizeof(unsigned long long)),
unsigned int>::type
findLastSet(T x) {
return x ? 8 * sizeof(unsigned long long) - __builtin_clzll(x) : 0;
return x ? ((8 * sizeof(unsigned long long) - 1) ^ __builtin_clzll(x)) + 1
: 0;
}
template <class T>
......@@ -190,10 +193,16 @@ nextPowTwo(T v) {
}
template <class T>
inline constexpr
typename std::enable_if<
std::is_integral<T>::value && std::is_unsigned<T>::value,
bool>::type
inline FOLLY_INTRINSIC_CONSTEXPR typename std::
enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value, T>::type
prevPowTwo(T v) {
return v ? (T(1) << (findLastSet(v) - 1)) : 0;
}
template <class T>
inline constexpr typename std::enable_if<
std::is_integral<T>::value && std::is_unsigned<T>::value,
bool>::type
isPowTwo(T v) {
return (v != 0) && !(v & (v - 1));
}
......
......@@ -114,6 +114,29 @@ TEST(Bits, nextPowTwoClz) {
EXPECT_EQ(1ull << 63, nextPowTwo((1ull << 62) + 1));
}
TEST(Bits, prevPowTwoClz) {
EXPECT_EQ(0, prevPowTwo(0u));
EXPECT_EQ(1, prevPowTwo(1u));
EXPECT_EQ(2, prevPowTwo(2u));
EXPECT_EQ(2, prevPowTwo(3u));
EXPECT_EQ(4, prevPowTwo(4u));
EXPECT_EQ(4, prevPowTwo(5u));
EXPECT_EQ(4, prevPowTwo(6u));
EXPECT_EQ(4, prevPowTwo(7u));
EXPECT_EQ(8, prevPowTwo(8u));
EXPECT_EQ(8, prevPowTwo(9u));
EXPECT_EQ(8, prevPowTwo(13u));
EXPECT_EQ(16, prevPowTwo(16u));
EXPECT_EQ(256, prevPowTwo(510u));
EXPECT_EQ(256, prevPowTwo(511u));
EXPECT_EQ(512, prevPowTwo(512u));
EXPECT_EQ(512, prevPowTwo(513u));
EXPECT_EQ(512, prevPowTwo(777u));
EXPECT_EQ(1ul << 30, prevPowTwo((1ul << 31) - 1));
EXPECT_EQ(1ull << 31, prevPowTwo((1ull << 32) - 1));
EXPECT_EQ(1ull << 62, prevPowTwo((1ull << 62) + 1));
}
TEST(Bits, isPowTwo) {
EXPECT_FALSE(isPowTwo(0u));
EXPECT_TRUE(isPowTwo(1ul));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment