Skip to content

Commit

Permalink
Move wtf/BitwiseOperations.h into base/bits.h.
Browse files Browse the repository at this point in the history
Part of the plan for WTF, and supports the PartitionAllocator move as well.

BUG=632441
R=dcheng@chromium.org, esprehn@chromium.org

Review URL: https://codereview.chromium.org/2512593002 .

Cr-Commit-Position: refs/heads/master@{#433301}
  • Loading branch information
Chris Palmer committed Nov 18, 2016
1 parent 4337e5d commit 79df709
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 83 deletions.
59 changes: 58 additions & 1 deletion base/bits.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

Expand All @@ -10,8 +10,13 @@
#include <stddef.h>
#include <stdint.h>

#include "base/compiler_specific.h"
#include "base/logging.h"

#if defined(COMPILER_MSVC)
#include <intrin.h>
#endif

namespace base {
namespace bits {

Expand Down Expand Up @@ -49,6 +54,58 @@ inline size_t Align(size_t size, size_t alignment) {
return (size + alignment - 1) & ~(alignment - 1);
}

// These functions count the number of leading zeros in a binary value, starting
// with the most significant bit. C does not have an operator to do this, but
// fortunately the various compilers have built-ins that map to fast underlying
// processor instructions.
#if defined(COMPILER_MSVC)

ALWAYS_INLINE uint32_t CountLeadingZeroBits32(uint32_t x) {
unsigned long index;
return LIKELY(_BitScanReverse(&index, x)) ? (31 - index) : 32;
}

#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) {
unsigned long index;
return LIKELY(_BitScanReverse64(&index, x)) ? (63 - index) : 64;
}

#endif

#elif defined(COMPILER_GCC)

// This is very annoying. __builtin_clz has undefined behaviour for an input of
// 0, even though there's clearly a return value that makes sense, and even
// though some processor clz instructions have defined behaviour for 0. We could
// drop to raw __asm__ to do better, but we'll avoid doing that unless we see
// proof that we need to.
ALWAYS_INLINE uint32_t CountLeadingZeroBits32(uint32_t x) {
return LIKELY(x) ? __builtin_clz(x) : 32;
}

ALWAYS_INLINE uint64_t CountLeadingZeroBits64(uint64_t x) {
return LIKELY(x) ? __builtin_clzll(x) : 64;
}

#endif

#if defined(ARCH_CPU_64_BITS)

ALWAYS_INLINE size_t CountLeadingZeroBitsSizeT(size_t x) {
return CountLeadingZeroBits64(x);
}

#else

ALWAYS_INLINE size_t CountLeadingZeroBitsSizeT(size_t x) {
return CountLeadingZeroBits32(x);
}

#endif

} // namespace bits
} // namespace base

Expand Down
20 changes: 20 additions & 0 deletions base/bits_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,25 @@ TEST(BitsTest, Align) {
EXPECT_EQ(kSizeTMax / 2 + 1, Align(1, kSizeTMax / 2 + 1));
}

TEST(BitsTest, CLZWorks) {
EXPECT_EQ(32u, CountLeadingZeroBits32(0u));
EXPECT_EQ(31u, CountLeadingZeroBits32(1u));
EXPECT_EQ(1u, CountLeadingZeroBits32(1u << 30));
EXPECT_EQ(0u, CountLeadingZeroBits32(1u << 31));

#if defined(ARCH_CPU_64_BITS)
EXPECT_EQ(64u, CountLeadingZeroBitsSizeT(0ull));
EXPECT_EQ(63u, CountLeadingZeroBitsSizeT(1ull));
EXPECT_EQ(32u, CountLeadingZeroBitsSizeT(1ull << 31));
EXPECT_EQ(1u, CountLeadingZeroBitsSizeT(1ull << 62));
EXPECT_EQ(0u, CountLeadingZeroBitsSizeT(1ull << 63));
#else
EXPECT_EQ(32u, CountLeadingZeroBitsSizeT(0u));
EXPECT_EQ(31u, CountLeadingZeroBitsSizeT(1u));
EXPECT_EQ(1u, CountLeadingZeroBitsSizeT(1u << 30));
EXPECT_EQ(0u, CountLeadingZeroBitsSizeT(1u << 31));
#endif
}

} // namespace bits
} // namespace base
65 changes: 8 additions & 57 deletions third_party/WebKit/Source/wtf/BitwiseOperations.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,72 +28,23 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

// TODO(palmer): The only caller of this code in Blink is PartitionAlloc. When
// PA is moved to base, we can remove this file.
// https://bugs.chromium.org/p/chromium/issues/detail?id=632441

#ifndef WTF_BitwiseOperations_h
#define WTF_BitwiseOperations_h

// DESCRIPTION
// countLeadingZeros() is a bitwise operation that counts the number of leading
// zeros in a binary value, starting with the most significant bit. C does not
// have an operator to do this, but fortunately the various compilers have
// built-ins that map to fast underlying processor instructions.

#include "base/bits.h"
#include "wtf/CPU.h"
#include "wtf/Compiler.h"
#include <cstddef>
#include <stdint.h>

#if COMPILER(MSVC)
#include <intrin.h>
#endif

namespace WTF {

#if COMPILER(MSVC)

ALWAYS_INLINE uint32_t countLeadingZeros32(uint32_t x) {
unsigned long index;
return LIKELY(_BitScanReverse(&index, x)) ? (31 - index) : 32;
}
using base::bits::CountLeadingZeroBits32;
using base::bits::CountLeadingZeroBitsSizeT;

#if CPU(64BIT)

// MSVC only supplies _BitScanForward64 when building for a 64-bit target.
ALWAYS_INLINE uint64_t countLeadingZeros64(uint64_t x) {
unsigned long index;
return LIKELY(_BitScanReverse64(&index, x)) ? (63 - index) : 64;
}

#endif

#elif COMPILER(GCC)

// This is very annoying. __builtin_clz has undefined behaviour for an input of
// 0, even though these's clearly a return value that makes sense, and even
// though nascent processor clz instructions have defined behaviour for 0.
// We could drop to raw __asm__ to do better, but we'll avoid doing that unless
// we see proof that we need to.
ALWAYS_INLINE uint32_t countLeadingZeros32(uint32_t x) {
return LIKELY(x) ? __builtin_clz(x) : 32;
}

ALWAYS_INLINE uint64_t countLeadingZeros64(uint64_t x) {
return LIKELY(x) ? __builtin_clzll(x) : 64;
}

#endif

#if CPU(64BIT)

ALWAYS_INLINE size_t countLeadingZerosSizet(size_t x) {
return countLeadingZeros64(x);
}

#else

ALWAYS_INLINE size_t countLeadingZerosSizet(size_t x) {
return countLeadingZeros32(x);
}

using base::bits::CountLeadingZeroBits64;
#endif

} // namespace WTF
Expand Down
1 change: 1 addition & 0 deletions third_party/WebKit/Source/wtf/DEPS
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ include_rules = [
# directories and files instead of writing 'base/'.
"+base/auto_reset.h",
"+base/bind.h",
"+base/bits.h",
"+base/compiler_specific.h",
"+base/debug",
"+base/logging.h",
Expand Down
2 changes: 1 addition & 1 deletion third_party/WebKit/Source/wtf/allocator/PartitionAlloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -799,7 +799,7 @@ ALWAYS_INLINE void partitionFree(void* ptr) {
ALWAYS_INLINE PartitionBucket* partitionGenericSizeToBucket(
PartitionRootGeneric* root,
size_t size) {
size_t order = kBitsPerSizet - countLeadingZerosSizet(size);
size_t order = kBitsPerSizet - CountLeadingZeroBitsSizeT(size);
// The order index is simply the next few bits after the most significant bit.
size_t orderIndex = (size >> root->orderIndexShifts[order]) &
(kGenericNumBucketsPerOrder - 1);
Expand Down
24 changes: 0 additions & 24 deletions third_party/WebKit/Source/wtf/allocator/PartitionAllocTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2113,30 +2113,6 @@ TEST(PartitionAllocTest, PurgeDiscardable) {
TestShutdown();
}

// Tests that the countLeadingZeros() functions work to our satisfaction.
// It doesn't seem worth the overhead of a whole new file for these tests, so
// we'll put them here since partitionAllocGeneric will depend heavily on these
// functions working correctly.
TEST(PartitionAllocTest, CLZWorks) {
EXPECT_EQ(32u, countLeadingZeros32(0u));
EXPECT_EQ(31u, countLeadingZeros32(1u));
EXPECT_EQ(1u, countLeadingZeros32(1u << 30));
EXPECT_EQ(0u, countLeadingZeros32(1u << 31));

#if CPU(64BIT)
EXPECT_EQ(64u, countLeadingZerosSizet(0ull));
EXPECT_EQ(63u, countLeadingZerosSizet(1ull));
EXPECT_EQ(32u, countLeadingZerosSizet(1ull << 31));
EXPECT_EQ(1u, countLeadingZerosSizet(1ull << 62));
EXPECT_EQ(0u, countLeadingZerosSizet(1ull << 63));
#else
EXPECT_EQ(32u, countLeadingZerosSizet(0u));
EXPECT_EQ(31u, countLeadingZerosSizet(1u));
EXPECT_EQ(1u, countLeadingZerosSizet(1u << 30));
EXPECT_EQ(0u, countLeadingZerosSizet(1u << 31));
#endif
}

} // namespace WTF

#endif // !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)

0 comments on commit 79df709

Please sign in to comment.