Commit 5d2331ff authored by Vlad Tsyrklevich's avatar Vlad Tsyrklevich Committed by Commit Bot

Implement base::bits functions for MSVC 32-bit targets

Currently, base::bits::Count{Leading,Trailing}ZeroBits fail to link
when used with 64-bit inputs on 32-bit MSVC builds because MSVC only
implements the _BitScan{Forward,Reverse}64 intrinsics for 64-bit
builds. Fix this by implementing equivalent support using 32-bit
intrinsics.

Change-Id: I9b9095abd03587c29dd642df65cf9783bd9b202d
Reviewed-on: https://chromium-review.googlesource.com/c/1321253Reviewed-by: default avatarAlbert J. Wong <ajwong@chromium.org>
Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org>
Cr-Commit-Position: refs/heads/master@{#607887}
parent 52bcc12a
...@@ -75,9 +75,22 @@ ALWAYS_INLINE ...@@ -75,9 +75,22 @@ ALWAYS_INLINE
CountLeadingZeroBits(T x) { CountLeadingZeroBits(T x) {
static_assert(bits > 0, "invalid instantiation"); static_assert(bits > 0, "invalid instantiation");
unsigned long index; unsigned long index;
// MSVC only supplies _BitScanReverse64 when building for a 64-bit target.
#if defined(ARCH_CPU_64_BITS)
return LIKELY(_BitScanReverse64(&index, static_cast<uint64_t>(x))) return LIKELY(_BitScanReverse64(&index, static_cast<uint64_t>(x)))
? (63 - index) ? (63 - index)
: 64; : 64;
#else
uint32_t left = static_cast<uint32_t>(x >> 32);
if (LIKELY(_BitScanReverse(&index, left)))
return 31 - index;
uint32_t right = static_cast<uint32_t>(x);
if (LIKELY(_BitScanReverse(&index, right)))
return 63 - index;
return 64;
#endif
} }
template <typename T, unsigned bits = sizeof(T) * 8> template <typename T, unsigned bits = sizeof(T) * 8>
...@@ -98,23 +111,31 @@ ALWAYS_INLINE ...@@ -98,23 +111,31 @@ ALWAYS_INLINE
CountTrailingZeroBits(T x) { CountTrailingZeroBits(T x) {
static_assert(bits > 0, "invalid instantiation"); static_assert(bits > 0, "invalid instantiation");
unsigned long index; unsigned long index;
// MSVC only supplies _BitScanForward64 when building for a 64-bit target.
#if defined(ARCH_CPU_64_BITS)
return LIKELY(_BitScanForward64(&index, static_cast<uint64_t>(x))) ? index return LIKELY(_BitScanForward64(&index, static_cast<uint64_t>(x))) ? index
: 64; : 64;
#else
uint32_t right = static_cast<uint32_t>(x);
if (LIKELY(_BitScanForward(&index, right)))
return index;
uint32_t left = static_cast<uint32_t>(x >> 32);
if (LIKELY(_BitScanForward(&index, left)))
return 32 + index;
return 64;
#endif
} }
ALWAYS_INLINE uint32_t CountLeadingZeroBits32(uint32_t x) { ALWAYS_INLINE uint32_t CountLeadingZeroBits32(uint32_t x) {
return CountLeadingZeroBits(x); return CountLeadingZeroBits(x);
} }
#if defined(ARCH_CPU_64_BITS)
// MSVC only supplies _BitScanForward64 when building for a 64-bit target.
ALWAYS_INLINE uint64_t CountLeadingZeroBits64(uint64_t x) { ALWAYS_INLINE uint64_t CountLeadingZeroBits64(uint64_t x) {
return CountLeadingZeroBits(x); return CountLeadingZeroBits(x);
} }
#endif
#elif defined(COMPILER_GCC) #elif defined(COMPILER_GCC)
// __builtin_clz has undefined behaviour for an input of 0, even though there's // __builtin_clz has undefined behaviour for an input of 0, even though there's
...@@ -149,16 +170,12 @@ ALWAYS_INLINE uint32_t CountLeadingZeroBits32(uint32_t x) { ...@@ -149,16 +170,12 @@ ALWAYS_INLINE uint32_t CountLeadingZeroBits32(uint32_t x) {
return CountLeadingZeroBits(x); return CountLeadingZeroBits(x);
} }
#if defined(ARCH_CPU_64_BITS)
ALWAYS_INLINE uint64_t CountLeadingZeroBits64(uint64_t x) { ALWAYS_INLINE uint64_t CountLeadingZeroBits64(uint64_t x) {
return CountLeadingZeroBits(x); return CountLeadingZeroBits(x);
} }
#endif #endif
#endif
ALWAYS_INLINE size_t CountLeadingZeroBitsSizeT(size_t x) { ALWAYS_INLINE size_t CountLeadingZeroBitsSizeT(size_t x) {
return CountLeadingZeroBits(x); return CountLeadingZeroBits(x);
} }
......
...@@ -118,8 +118,6 @@ TEST(BitsTest, CountTrailingeZeroBits32) { ...@@ -118,8 +118,6 @@ TEST(BitsTest, CountTrailingeZeroBits32) {
EXPECT_EQ(4u, CountTrailingZeroBits(uint32_t{0xf0f0f0f0})); EXPECT_EQ(4u, CountTrailingZeroBits(uint32_t{0xf0f0f0f0}));
} }
#if defined(ARCH_CPU_64_BITS)
TEST(BitsTest, CountLeadingZeroBits64) { TEST(BitsTest, CountLeadingZeroBits64) {
EXPECT_EQ(64u, CountLeadingZeroBits(uint64_t{0})); EXPECT_EQ(64u, CountLeadingZeroBits(uint64_t{0}));
EXPECT_EQ(63u, CountLeadingZeroBits(uint64_t{1})); EXPECT_EQ(63u, CountLeadingZeroBits(uint64_t{1}));
...@@ -138,8 +136,6 @@ TEST(BitsTest, CountTrailingeZeroBits64) { ...@@ -138,8 +136,6 @@ TEST(BitsTest, CountTrailingeZeroBits64) {
EXPECT_EQ(4u, CountTrailingZeroBits(uint64_t{0xf0f0f0f0f0f0f0f0})); EXPECT_EQ(4u, CountTrailingZeroBits(uint64_t{0xf0f0f0f0f0f0f0f0}));
} }
#endif // ARCH_CPU_64_BITS
TEST(BitsTest, CountLeadingZeroBitsSizeT) { TEST(BitsTest, CountLeadingZeroBitsSizeT) {
#if defined(ARCH_CPU_64_BITS) #if defined(ARCH_CPU_64_BITS)
EXPECT_EQ(64u, CountLeadingZeroBitsSizeT(size_t{0})); EXPECT_EQ(64u, CountLeadingZeroBitsSizeT(size_t{0}));
......
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