timeout-bitops.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. #include <stdint.h>
  2. #ifdef _MSC_VER
  3. #include <intrin.h> /* _BitScanForward, _BitScanReverse */
  4. #endif
  5. /* First define ctz and clz functions; these are compiler-dependent if
  6. * you want them to be fast. */
  7. #if defined(__GNUC__) && !defined(TIMEOUT_DISABLE_GNUC_BITOPS)
  8. /* On GCC and clang and some others, we can use __builtin functions. They
  9. * are not defined for n==0, but timeout.s never calls them with n==0. */
  10. #define ctz64(n) __builtin_ctzll(n)
  11. #define clz64(n) __builtin_clzll(n)
  12. #if LONG_BITS == 32
  13. #define ctz32(n) __builtin_ctzl(n)
  14. #define clz32(n) __builtin_clzl(n)
  15. #else
  16. #define ctz32(n) __builtin_ctz(n)
  17. #define clz32(n) __builtin_clz(n)
  18. #endif
  19. #elif defined(_MSC_VER) && !defined(TIMEOUT_DISABLE_MSVC_BITOPS)
  20. /* On MSVC, we have these handy functions. We can ignore their return
  21. * values, since we will never supply val == 0. */
  22. static __inline int ctz32(unsigned long val)
  23. {
  24. DWORD zeros = 0;
  25. _BitScanForward(&zeros, val);
  26. return zeros;
  27. }
  28. static __inline int clz32(unsigned long val)
  29. {
  30. DWORD zeros = 0;
  31. _BitScanReverse(&zeros, val);
  32. return zeros;
  33. }
  34. #ifdef _WIN64
  35. /* According to the documentation, these only exist on Win64. */
  36. static __inline int ctz64(uint64_t val)
  37. {
  38. DWORD zeros = 0;
  39. _BitScanForward64(&zeros, val);
  40. return zeros;
  41. }
  42. static __inline int clz64(uint64_t val)
  43. {
  44. DWORD zeros = 0;
  45. _BitScanReverse64(&zeros, val);
  46. return zeros;
  47. }
  48. #else
  49. static __inline int ctz64(uint64_t val)
  50. {
  51. uint32_t lo = (uint32_t) val;
  52. uint32_t hi = (uint32_t) (val >> 32);
  53. return lo ? ctz32(lo) : 32 + ctz32(hi);
  54. }
  55. static __inline int clz64(uint64_t val)
  56. {
  57. uint32_t lo = (uint32_t) val;
  58. uint32_t hi = (uint32_t) (val >> 32);
  59. return hi ? clz32(hi) : 32 + clz32(lo);
  60. }
  61. #endif
  62. /* End of MSVC case. */
  63. #else
  64. /* TODO: There are more clever ways to do this in the generic case. */
  65. #define process_(one, cz_bits, bits) \
  66. if (x < ( one << (cz_bits - bits))) { rv += bits; x <<= bits; }
  67. #define process64(bits) process_((UINT64_C(1)), 64, (bits))
  68. static inline int clz64(uint64_t x)
  69. {
  70. int rv = 0;
  71. process64(32);
  72. process64(16);
  73. process64(8);
  74. process64(4);
  75. process64(2);
  76. process64(1);
  77. return rv;
  78. }
  79. #define process32(bits) process_((UINT32_C(1)), 32, (bits))
  80. static inline int clz32(uint32_t x)
  81. {
  82. int rv = 0;
  83. process32(16);
  84. process32(8);
  85. process32(4);
  86. process32(2);
  87. process32(1);
  88. return rv;
  89. }
  90. #undef process_
  91. #undef process32
  92. #undef process64
  93. #define process_(one, bits) \
  94. if ((x & ((one << (bits))-1)) == 0) { rv += bits; x >>= bits; }
  95. #define process64(bits) process_((UINT64_C(1)), bits)
  96. static inline int ctz64(uint64_t x)
  97. {
  98. int rv = 0;
  99. process64(32);
  100. process64(16);
  101. process64(8);
  102. process64(4);
  103. process64(2);
  104. process64(1);
  105. return rv;
  106. }
  107. #define process32(bits) process_((UINT32_C(1)), bits)
  108. static inline int ctz32(uint32_t x)
  109. {
  110. int rv = 0;
  111. process32(16);
  112. process32(8);
  113. process32(4);
  114. process32(2);
  115. process32(1);
  116. return rv;
  117. }
  118. #undef process32
  119. #undef process64
  120. #undef process_
  121. /* End of generic case */
  122. #endif /* End of defining ctz */
  123. #ifdef TEST_BITOPS
  124. #include <stdio.h>
  125. #include <stdlib.h>
  126. static uint64_t testcases[] = {
  127. 13371337 * 10,
  128. 100,
  129. 385789752,
  130. 82574,
  131. (((uint64_t)1)<<63) + (((uint64_t)1)<<31) + 10101
  132. };
  133. static int
  134. naive_clz(int bits, uint64_t v)
  135. {
  136. int r = 0;
  137. uint64_t bit = ((uint64_t)1) << (bits-1);
  138. while (bit && 0 == (v & bit)) {
  139. r++;
  140. bit >>= 1;
  141. }
  142. /* printf("clz(%d,%lx) -> %d\n", bits, v, r); */
  143. return r;
  144. }
  145. static int
  146. naive_ctz(int bits, uint64_t v)
  147. {
  148. int r = 0;
  149. uint64_t bit = 1;
  150. while (bit && 0 == (v & bit)) {
  151. r++;
  152. bit <<= 1;
  153. if (r == bits)
  154. break;
  155. }
  156. /* printf("ctz(%d,%lx) -> %d\n", bits, v, r); */
  157. return r;
  158. }
  159. static int
  160. check(uint64_t vv)
  161. {
  162. uint32_t v32 = (uint32_t) vv;
  163. if (vv == 0)
  164. return 1; /* c[tl]z64(0) is undefined. */
  165. if (ctz64(vv) != naive_ctz(64, vv)) {
  166. printf("mismatch with ctz64: %d\n", ctz64(vv));
  167. exit(1);
  168. return 0;
  169. }
  170. if (clz64(vv) != naive_clz(64, vv)) {
  171. printf("mismatch with clz64: %d\n", clz64(vv));
  172. exit(1);
  173. return 0;
  174. }
  175. if (v32 == 0)
  176. return 1; /* c[lt]z(0) is undefined. */
  177. if (ctz32(v32) != naive_ctz(32, v32)) {
  178. printf("mismatch with ctz32: %d\n", ctz32(v32));
  179. exit(1);
  180. return 0;
  181. }
  182. if (clz32(v32) != naive_clz(32, v32)) {
  183. printf("mismatch with clz32: %d\n", clz32(v32));
  184. exit(1);
  185. return 0;
  186. }
  187. return 1;
  188. }
  189. int
  190. main(int c, char **v)
  191. {
  192. unsigned int i;
  193. const unsigned int n = sizeof(testcases)/sizeof(testcases[0]);
  194. int result = 0;
  195. for (i = 0; i <= 63; ++i) {
  196. uint64_t x = 1 << i;
  197. if (!check(x))
  198. result = 1;
  199. --x;
  200. if (!check(x))
  201. result = 1;
  202. }
  203. for (i = 0; i < n; ++i) {
  204. if (! check(testcases[i]))
  205. result = 1;
  206. }
  207. if (result) {
  208. puts("FAIL");
  209. } else {
  210. puts("OK");
  211. }
  212. return result;
  213. }
  214. #endif