• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef ABSL_BASE_INTERNAL_BITS_H_
16 #define ABSL_BASE_INTERNAL_BITS_H_
17 
18 // This file contains bitwise ops which are implementation details of various
19 // absl libraries.
20 
21 #include <cstdint>
22 
23 #include "absl/base/config.h"
24 
25 // Clang on Windows has __builtin_clzll; otherwise we need to use the
26 // windows intrinsic functions.
27 #if defined(_MSC_VER)
28 #include <intrin.h>
29 #if defined(_M_X64)
30 #pragma intrinsic(_BitScanReverse64)
31 #pragma intrinsic(_BitScanForward64)
32 #endif
33 #pragma intrinsic(_BitScanReverse)
34 #pragma intrinsic(_BitScanForward)
35 #endif
36 
37 #include "absl/base/attributes.h"
38 
39 #if defined(_MSC_VER)
40 // We can achieve something similar to attribute((always_inline)) with MSVC by
41 // using the __forceinline keyword, however this is not perfect. MSVC is
42 // much less aggressive about inlining, and even with the __forceinline keyword.
43 #define ABSL_BASE_INTERNAL_FORCEINLINE __forceinline
44 #else
45 // Use default attribute inline.
46 #define ABSL_BASE_INTERNAL_FORCEINLINE inline ABSL_ATTRIBUTE_ALWAYS_INLINE
47 #endif
48 
49 
50 namespace absl {
51 ABSL_NAMESPACE_BEGIN
52 namespace base_internal {
53 
CountLeadingZeros64Slow(uint64_t n)54 ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64Slow(uint64_t n) {
55   int zeroes = 60;
56   if (n >> 32) {
57     zeroes -= 32;
58     n >>= 32;
59   }
60   if (n >> 16) {
61     zeroes -= 16;
62     n >>= 16;
63   }
64   if (n >> 8) {
65     zeroes -= 8;
66     n >>= 8;
67   }
68   if (n >> 4) {
69     zeroes -= 4;
70     n >>= 4;
71   }
72   return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[n] + zeroes;
73 }
74 
CountLeadingZeros64(uint64_t n)75 ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64(uint64_t n) {
76 #if defined(_MSC_VER) && defined(_M_X64)
77   // MSVC does not have __buitin_clzll. Use _BitScanReverse64.
78   unsigned long result = 0;  // NOLINT(runtime/int)
79   if (_BitScanReverse64(&result, n)) {
80     return 63 - result;
81   }
82   return 64;
83 #elif defined(_MSC_VER)
84   // MSVC does not have __buitin_clzll. Compose two calls to _BitScanReverse
85   unsigned long result = 0;  // NOLINT(runtime/int)
86   if ((n >> 32) && _BitScanReverse(&result, n >> 32)) {
87     return 31 - result;
88   }
89   if (_BitScanReverse(&result, n)) {
90     return 63 - result;
91   }
92   return 64;
93 #elif defined(__GNUC__)
94   // Use __builtin_clzll, which uses the following instructions:
95   //  x86: bsr
96   //  ARM64: clz
97   //  PPC: cntlzd
98   static_assert(sizeof(unsigned long long) == sizeof(n),  // NOLINT(runtime/int)
99                 "__builtin_clzll does not take 64-bit arg");
100 
101   // Handle 0 as a special case because __builtin_clzll(0) is undefined.
102   if (n == 0) {
103     return 64;
104   }
105   return __builtin_clzll(n);
106 #else
107   return CountLeadingZeros64Slow(n);
108 #endif
109 }
110 
CountLeadingZeros32Slow(uint64_t n)111 ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros32Slow(uint64_t n) {
112   int zeroes = 28;
113   if (n >> 16) {
114     zeroes -= 16;
115     n >>= 16;
116   }
117   if (n >> 8) {
118     zeroes -= 8;
119     n >>= 8;
120   }
121   if (n >> 4) {
122     zeroes -= 4;
123     n >>= 4;
124   }
125   return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[n] + zeroes;
126 }
127 
CountLeadingZeros32(uint32_t n)128 ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros32(uint32_t n) {
129 #if defined(_MSC_VER)
130   unsigned long result = 0;  // NOLINT(runtime/int)
131   if (_BitScanReverse(&result, n)) {
132     return 31 - result;
133   }
134   return 32;
135 #elif defined(__GNUC__)
136   // Use __builtin_clz, which uses the following instructions:
137   //  x86: bsr
138   //  ARM64: clz
139   //  PPC: cntlzd
140   static_assert(sizeof(int) == sizeof(n),
141                 "__builtin_clz does not take 32-bit arg");
142 
143   // Handle 0 as a special case because __builtin_clz(0) is undefined.
144   if (n == 0) {
145     return 32;
146   }
147   return __builtin_clz(n);
148 #else
149   return CountLeadingZeros32Slow(n);
150 #endif
151 }
152 
CountTrailingZerosNonZero64Slow(uint64_t n)153 ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero64Slow(uint64_t n) {
154   int c = 63;
155   n &= ~n + 1;
156   if (n & 0x00000000FFFFFFFF) c -= 32;
157   if (n & 0x0000FFFF0000FFFF) c -= 16;
158   if (n & 0x00FF00FF00FF00FF) c -= 8;
159   if (n & 0x0F0F0F0F0F0F0F0F) c -= 4;
160   if (n & 0x3333333333333333) c -= 2;
161   if (n & 0x5555555555555555) c -= 1;
162   return c;
163 }
164 
CountTrailingZerosNonZero64(uint64_t n)165 ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero64(uint64_t n) {
166 #if defined(_MSC_VER) && defined(_M_X64)
167   unsigned long result = 0;  // NOLINT(runtime/int)
168   _BitScanForward64(&result, n);
169   return result;
170 #elif defined(_MSC_VER)
171   unsigned long result = 0;  // NOLINT(runtime/int)
172   if (static_cast<uint32_t>(n) == 0) {
173     _BitScanForward(&result, n >> 32);
174     return result + 32;
175   }
176   _BitScanForward(&result, n);
177   return result;
178 #elif defined(__GNUC__)
179   static_assert(sizeof(unsigned long long) == sizeof(n),  // NOLINT(runtime/int)
180                 "__builtin_ctzll does not take 64-bit arg");
181   return __builtin_ctzll(n);
182 #else
183   return CountTrailingZerosNonZero64Slow(n);
184 #endif
185 }
186 
CountTrailingZerosNonZero32Slow(uint32_t n)187 ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero32Slow(uint32_t n) {
188   int c = 31;
189   n &= ~n + 1;
190   if (n & 0x0000FFFF) c -= 16;
191   if (n & 0x00FF00FF) c -= 8;
192   if (n & 0x0F0F0F0F) c -= 4;
193   if (n & 0x33333333) c -= 2;
194   if (n & 0x55555555) c -= 1;
195   return c;
196 }
197 
CountTrailingZerosNonZero32(uint32_t n)198 ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero32(uint32_t n) {
199 #if defined(_MSC_VER)
200   unsigned long result = 0;  // NOLINT(runtime/int)
201   _BitScanForward(&result, n);
202   return result;
203 #elif defined(__GNUC__)
204   static_assert(sizeof(int) == sizeof(n),
205                 "__builtin_ctz does not take 32-bit arg");
206   return __builtin_ctz(n);
207 #else
208   return CountTrailingZerosNonZero32Slow(n);
209 #endif
210 }
211 
212 #undef ABSL_BASE_INTERNAL_FORCEINLINE
213 
214 }  // namespace base_internal
215 ABSL_NAMESPACE_END
216 }  // namespace absl
217 
218 #endif  // ABSL_BASE_INTERNAL_BITS_H_
219