Chromium Code Reviews| Index: base/bits.h |
| diff --git a/base/bits.h b/base/bits.h |
| index a3a59d1dfad0d4c2992b1a6d0abd9a0c4fc2b1aa..fe583f6a57c88769ae7f97d3e73835b55cd07830 100644 |
| --- a/base/bits.h |
| +++ b/base/bits.h |
| @@ -49,6 +49,85 @@ inline size_t Align(size_t size, size_t alignment) { |
| return (size + alignment - 1) & ~(alignment - 1); |
| } |
| +inline int CountLeadingZerosFallback(uint32_t value) { |
|
vmpstr
2016/03/29 18:38:13
This should probably be a separate CL. Wdyt?
cblume
2016/03/29 18:53:44
I agree 100%.
I'll separate it out.
|
| + if (value == 0) { |
| + return 32; |
| + } |
| + |
| + int zeros = 31; |
| + if (value & 0xFFFF0000) { |
| + zeros -= 16; |
| + value >>= 16; |
| + } |
| + if (value & 0xFF00) { |
| + zeros -= 8; |
| + value >>= 8; |
| + } |
| + if (value & 0xF0) { |
| + zeros -= 4; |
| + value >>= 4; |
| + } |
| + if (value & 0xC) { |
| + zeros -= 2; |
| + value >>= 2; |
| + } |
| + if (value & 0x2) { |
| + zeros -= 1; |
| + } |
| + |
| + return zeros; |
| +} |
| + |
| +// Returns the number of leading zero bits |
| +#if defined(_MSC_VER) |
| + // There is an intrinsic available on x86, ARM, and x64. |
| + #if defined(_M_IX64) || defined(_M_ARM) || defined(_M_6X4) |
| + #include <intrin.h> |
| + |
| + #pragma intrinsic(_BitScanReverse) |
| + inline int CountLeadingZeros(uint32_t value) { |
| + // We want to work with uint32_ts. |
| + // But the intrinsic signature is unsigned long. |
| + static_assert(sizeof(uint32_t) == sizeof(unsigned long), |
| + "Failed assumption that long is 32-bit."); |
| + |
| + // _BitScanReverse returns the index of the first set bit if there is one. |
| + // Otherwise, it returns 0. |
| + unsigned long first_set_bit_index; |
| + if (_BitScanReverse(&first_set_bit_index, value) { |
| + return 31 - first_set_bit_index; |
| + } else { |
| + return 32; |
| + } |
| + } |
| + #else // We cannot use the intrinsic so use the fallback |
| + inline int CountLeadingZeros(uint32_t value) { |
| + return CountLeadingZerosFallback(value); |
| + } |
| + #endif |
| +#elif defined(__clang__) |
| + #if __has_builtin(__builtin_clz) |
| + inline int CountLeadingZeros(uint32_t value) { |
| + // We want to work with uint32_ts. |
| + // But the intrinsic signature is unsigned long. |
| + static_assert(sizeof(uint32_t) == sizeof(unsigned int), |
| + "Failed assumption that int is 32-bit."); |
| + |
| + if (value == 0) { |
| + return 32; |
| + } else { |
| + return __builtin_clz(value); |
| + } |
| + } |
| + #else // We could not use __builtin_clz |
| + inline int CountLeadingZeros(uint32_t value) { |
| + return CountLeadingZerosFallback(value); |
| + } |
| + #endif |
| +#else // unrecognized compiler |
| + #error Unrecognized compiler |
| +#endif |
| + |
| } // namespace bits |
| } // namespace base |