Index: base/bits.h |
diff --git a/base/bits.h b/base/bits.h |
index a3a59d1dfad0d4c2992b1a6d0abd9a0c4fc2b1aa..d101cb731a7da764150ff567777a1c232c4f522f 100644 |
--- a/base/bits.h |
+++ b/base/bits.h |
@@ -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. |
@@ -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 { |
@@ -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 |