Count leading zeroes using builtin if available.
Make log_2_floor() use raw_clz() and inline log_2_floor() and
log_2_ceil().
Signed-off-by: Jarno Rajahalme <jrajahalme@nicira.com>
Acked-by: Ben Pfaff <blp@nicira.com>
: " and ");
}
-/* Given a 32 bit word 'n', calculates floor(log_2('n')). This is equivalent
- * to finding the bit position of the most significant one bit in 'n'. It is
- * an error to call this function with 'n' == 0. */
-int
-log_2_floor(uint32_t n)
-{
- ovs_assert(n);
-
-#if !defined(UINT_MAX) || !defined(UINT32_MAX)
-#error "Someone screwed up the #includes."
-#elif __GNUC__ >= 4 && UINT_MAX == UINT32_MAX
- return 31 - __builtin_clz(n);
-#else
- {
- int log = 0;
-
-#define BIN_SEARCH_STEP(BITS) \
- if (n >= (1 << BITS)) { \
- log += BITS; \
- n >>= BITS; \
- }
- BIN_SEARCH_STEP(16);
- BIN_SEARCH_STEP(8);
- BIN_SEARCH_STEP(4);
- BIN_SEARCH_STEP(2);
- BIN_SEARCH_STEP(1);
-#undef BIN_SEARCH_STEP
- return log;
- }
-#endif
-}
-
-/* Given a 32 bit word 'n', calculates ceil(log_2('n')). It is an error to
- * call this function with 'n' == 0. */
-int
-log_2_ceil(uint32_t n)
-{
- return log_2_floor(n) + !is_pow2(n);
-}
-
/* Returns the number of trailing 0-bits in 'n'. Undefined if 'n' == 0. */
#if __GNUC__ >= 4
/* Defined inline in util.h. */
#else
+/* Returns the number of trailing 0-bits in 'n'. Undefined if 'n' == 0. */
int
raw_ctz(uint64_t n)
{
return count;
}
+
+/* Returns the number of leading 0-bits in 'n'. Undefined if 'n' == 0. */
+int
+raw_clz64(uint64_t n)
+{
+ uint64_t k;
+ int count = 63;
+
+#define CLZ_STEP(X) \
+ k = n >> (X); \
+ if (k) { \
+ count -= X; \
+ n = k; \
+ }
+ CLZ_STEP(32);
+ CLZ_STEP(16);
+ CLZ_STEP(8);
+ CLZ_STEP(4);
+ CLZ_STEP(2);
+ CLZ_STEP(1);
+#undef CLZ_STEP
+
+ return count;
+}
#endif
/* Returns the number of 1-bits in 'x', between 0 and 32 inclusive. */
\f
/* Bitwise tests. */
-int log_2_floor(uint32_t);
-int log_2_ceil(uint32_t);
-unsigned int count_1bits(uint64_t);
-
/* Returns the number of trailing 0-bits in 'n'. Undefined if 'n' == 0. */
#if __GNUC__ >= 4
static inline int
? __builtin_ctz(n)
: __builtin_ctzll(n));
}
+
+static inline int
+raw_clz64(uint64_t n)
+{
+ return __builtin_clzll(n);
+}
#else
/* Defined in util.c. */
int raw_ctz(uint64_t n);
+int raw_clz64(uint64_t n);
#endif
/* Returns the number of trailing 0-bits in 'n', or 32 if 'n' is 0. */
return n ? raw_ctz(n) : 64;
}
+/* Returns the number of leading 0-bits in 'n', or 32 if 'n' is 0. */
+static inline int
+clz32(uint32_t n)
+{
+ return n ? raw_clz64(n) - 32 : 32;
+}
+
+/* Returns the number of leading 0-bits in 'n', or 64 if 'n' is 0. */
+static inline int
+clz64(uint64_t n)
+{
+ return n ? raw_clz64(n) : 64;
+}
+
+/* Given a word 'n', calculates floor(log_2('n')). This is equivalent
+ * to finding the bit position of the most significant one bit in 'n'. It is
+ * an error to call this function with 'n' == 0. */
+static inline int
+log_2_floor(uint64_t n)
+{
+ return 63 - raw_clz64(n);
+}
+
+/* Given a word 'n', calculates ceil(log_2('n')). It is an error to
+ * call this function with 'n' == 0. */
+static inline int
+log_2_ceil(uint64_t n)
+{
+ return log_2_floor(n) + !is_pow2(n);
+}
+
+unsigned int count_1bits(uint64_t);
+
/* Returns the rightmost 1-bit in 'x' (e.g. 01011000 => 00001000), or 0 if 'x'
* is 0. */
static inline uintmax_t
m4_foreach(
[testname],
[[ctz],
+ [clz],
[round_up_pow2],
[round_down_pow2],
[count_1bits],
check_ctz64(0, 64);
}
+static void
+check_clz32(uint32_t x, int n)
+{
+ if (clz32(x) != n) {
+ fprintf(stderr, "clz32(%"PRIu32") is %d but should be %d\n",
+ x, clz32(x), n);
+ abort();
+ }
+}
+
+static void
+check_clz64(uint64_t x, int n)
+{
+ if (clz64(x) != n) {
+ fprintf(stderr, "clz64(%"PRIu64") is %d but should be %d\n",
+ x, clz64(x), n);
+ abort();
+ }
+}
+
+static void
+test_clz(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
+{
+ int n;
+
+ for (n = 0; n < 32; n++) {
+ /* Check minimum x such that f(x) == n. */
+ check_clz32((1u << 31) >> n, n);
+
+ /* Check maximum x such that f(x) == n. */
+ check_clz32(UINT32_MAX >> n, n);
+
+ /* Check a random value in the middle. */
+ check_clz32((random_uint32() | 1u << 31) >> n, n);
+ }
+
+ for (n = 0; n < 64; n++) {
+ /* Check minimum x such that f(x) == n. */
+ check_clz64((UINT64_C(1) << 63) >> n, n);
+
+ /* Check maximum x such that f(x) == n. */
+ check_clz64(UINT64_MAX >> n, n);
+
+ /* Check a random value in the middle. */
+ check_clz64((random_uint64() | UINT64_C(1) << 63) >> n, n);
+ }
+
+ /* Check clz(0). */
+ check_clz32(0, 32);
+ check_clz64(0, 64);
+}
+
/* Returns a random number in the range 'min'...'max' inclusive. */
static uint32_t
random_in_range(uint32_t min, uint32_t max)
\f
static const struct command commands[] = {
{"ctz", 0, 0, test_ctz},
+ {"clz", 0, 0, test_clz},
{"round_up_pow2", 0, 0, test_round_up_pow2},
{"round_down_pow2", 0, 0, test_round_down_pow2},
{"count_1bits", 0, 0, test_count_1bits},