Skip to content

Commit 84ea32f

Browse files
committed
Introduce portable clz
1 parent fd87884 commit 84ea32f

File tree

1 file changed

+39
-11
lines changed

1 file changed

+39
-11
lines changed

src/common.h

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
#pragma once
77

8+
#include <stdint.h>
9+
810
#include "feature.h"
911

1012
#if defined(__GNUC__) || defined(__clang__)
@@ -27,20 +29,46 @@
2729

2830
#define MASK(n) (~((~0U << (n))))
2931

32+
#if defined(_MSC_VER)
33+
#include <intrin.h>
34+
static inline int clz(uint32_t v)
35+
{
36+
uint32_t leading_zero = 0;
37+
if (_BitScanReverse(&leading_zero, v))
38+
return 31 - leading_zero;
39+
return 32; /* undefined behavior */
40+
}
41+
#elif defined(__GNUC__) || defined(__clang__)
42+
static inline int clz(uint32_t v)
43+
{
44+
return __builtin_clz(v);
45+
}
46+
#else /* generic implementation */
47+
static inline int clz(uint32_t v)
48+
{
49+
/* http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogDeBruijn */
50+
static const uint8_t mul_debruijn[] = {
51+
0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30,
52+
8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31,
53+
};
54+
55+
v |= v >> 1;
56+
v |= v >> 2;
57+
v |= v >> 4;
58+
v |= v >> 8;
59+
v |= v >> 16;
60+
61+
return mul_debruijn[(uint32_t) (v * 0x07C4ACDDU) >> 27];
62+
}
63+
#endif
64+
3065
/*
3166
* Integer log base 2
32-
*
33-
* The input will be ORed with 1 to prevent x = 0 since
34-
* the result is undefined if x = 0
35-
*
3667
*/
37-
#if defined(__GNUC__) || defined(__clang__)
38-
#define ilog2(x) 31 - __builtin_clz(x | 1)
39-
#elif defined(_MSC_VER)
40-
/* FIXME */
41-
#else /* unsupported compilers */
42-
#define ilog2(x)
43-
#endif
68+
static inline uint8_t ilog2(uint32_t x)
69+
{
70+
return 31 - clz(x);
71+
}
4472

4573
/* Alignment macro */
4674
#if defined(__GNUC__) || defined(__clang__)

0 commit comments

Comments
 (0)