count-leading-zeros: port to MSC; support types wider than 64 bits
[gnulib.git] / lib / count-leading-zeros.h
1 /* count-leading-zeros.h -- counts the number of leading 0 bits in a word.
2    Copyright (C) 2012-2013 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
16
17 /* Written by Eric Blake.  */
18
19 #ifndef COUNT_LEADING_ZEROS_H
20 #define COUNT_LEADING_ZEROS_H 1
21
22 #include <limits.h>
23 #include <stdlib.h>
24
25 #ifndef _GL_INLINE_HEADER_BEGIN
26  #error "Please include config.h first."
27 #endif
28 _GL_INLINE_HEADER_BEGIN
29 #ifndef COUNT_LEADING_ZEROS_INLINE
30 # define COUNT_LEADING_ZEROS_INLINE _GL_INLINE
31 #endif
32
33 /* Assuming the GCC builtin is BUILTIN and the MSC builtin is MSC_BUILTIN,
34    expand to code that computes the number of leading zeros of the local
35    variable 'x' of type TYPE (an unsigned integer type) and return it
36    from the current function.  */
37 #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
38 # define COUNT_LEADING_ZEROS(BUILTIN, MSC_BUILTIN, TYPE)                \
39   return x ? BUILTIN (x) : CHAR_BIT * sizeof x;
40 #elif _MSC_VER
41 # pragma intrinsic _BitReverse
42 # pragma intrinsic _BitReverse64
43 # define COUNT_LEADING_ZEROS(BUILTIN, MSC_BUILTIN, TYPE)                \
44     do                                                                  \
45       {                                                                 \
46         unsigned long result;                                           \
47         return MSC_BUILTIN (&result, x) ? result : CHAR_BIT * sizeof x; \
48       }                                                                 \
49     while (0)
50 #else
51 # define COUNT_LEADING_ZEROS(BUILTIN, MSC_BUILTIN, TYPE)                \
52     do                                                                  \
53       {                                                                 \
54         int count;                                                      \
55         unsigned int leading_32;                                        \
56         if (! x)                                                        \
57           return CHAR_BIT * sizeof x;                                   \
58         for (count = 0;                                                 \
59              (leading_32 = ((x >> (sizeof (TYPE) * CHAR_BIT - 32))      \
60                             & 0xffffffffU),                             \
61               count < CHAR_BIT * sizeof x - 32 && !leading_32);         \
62              count += 32)                                               \
63           x = x << 31 << 1;                                             \
64         return count + count_leading_zeros_32 (leading_32);             \
65       }                                                                 \
66     while (0)
67
68 /* Compute and return the number of leading zeros in X,
69    where 0 < X < 2**32.  */
70 COUNT_LEADING_ZEROS_INLINE int
71 count_leading_zeros_32 (unsigned int x)
72 {
73   /* http://graphics.stanford.edu/~seander/bithacks.html */
74   static const char de_Bruijn_lookup[32] = {
75     31, 22, 30, 21, 18, 10, 29, 2, 20, 17, 15, 13, 9, 6, 28, 1,
76     23, 19, 11, 3, 16, 14, 7, 24, 12, 4, 8, 25, 5, 26, 27, 0
77   };
78
79   x |= x >> 1;
80   x |= x >> 2;
81   x |= x >> 4;
82   x |= x >> 8;
83   x |= x >> 16;
84   return de_Bruijn_lookup[((x * 0x07c4acddU) & 0xffffffffU) >> 27];
85 }
86 #endif
87
88 /* Compute and return the number of leading zeros in X. */
89 COUNT_LEADING_ZEROS_INLINE int
90 count_leading_zeros (unsigned int x)
91 {
92   COUNT_LEADING_ZEROS (__builtin_clz, _BitScanReverse, unsigned int);
93 }
94
95 /* Compute and return the number of leading zeros in X. */
96 COUNT_LEADING_ZEROS_INLINE int
97 count_leading_zeros_l (unsigned long int x)
98 {
99   COUNT_LEADING_ZEROS (__builtin_clzl, _BitScanReverse, unsigned long int);
100 }
101
102 #if HAVE_UNSIGNED_LONG_LONG_INT
103 /* Compute and return the number of leading zeros in X. */
104 COUNT_LEADING_ZEROS_INLINE int
105 count_leading_zeros_ll (unsigned long long int x)
106 {
107   COUNT_LEADING_ZEROS (__builtin_clzll, _BitScanReverse64,
108                        unsigned long long int);
109 }
110 #endif
111
112 _GL_INLINE_HEADER_END
113
114 #endif /* COUNT_LEADING_ZEROS_H */