count-leading-zeros.h 4.4 KB

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