bit_scan.h 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. /*
  2. * $Id$
  3. *
  4. * Copyright (C) 2007 iptelorg GmbH
  5. *
  6. * Permission to use, copy, modify, and distribute this software for any
  7. * purpose with or without fee is hereby granted, provided that the above
  8. * copyright notice and this permission notice appear in all copies.
  9. *
  10. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  11. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  12. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  13. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  14. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  15. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  16. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  17. */
  18. /*!
  19. * \file
  20. * \brief SIP-router core :: bit scan operations
  21. * \ingroup core
  22. * Module: \ref core
  23. *
  24. * bit scan operations
  25. *
  26. * - int bit_scan_forward(unsigned long v) - returns the index of the first
  27. * set bit (undefined value if v==0)
  28. * - int bit_scan_forward32(unsigned int v) - returns the index of the first
  29. * set bit (undefined value if v==0)
  30. * - int bit_scan_forward64(long long v) - returns the index of the first
  31. * set bit (undefined value if v==0)
  32. * - int bit_scan_reverse(unsigned long v) - returns the index of the last
  33. * set bit (undefined value if v==0)
  34. * - int bit_scan_reverse32(unsigned int v) - returns the index of the last
  35. * set bit (undefined value if v==0)
  36. * - int bit_scan_reverse64(long long v) - returns the index of the last
  37. * set bit (undefined value if v==0)
  38. *
  39. * Config defines: CC_GCC_LIKE_ASM - the compiler support gcc style
  40. * inline asm,
  41. * __CPU_x86, __CPU_x86_64,
  42. * ULONG_MAX (limits.h)
  43. */
  44. /*
  45. * History:
  46. * --------
  47. * 2007-06-23 created by andrei
  48. */
  49. #ifndef _bit_scan_h
  50. #define _bit_scan_h
  51. #include <limits.h>
  52. /*! \brief fix __CPU_i386 -> __CPU_x86 */
  53. #if defined __CPU_i386 && ! defined __CPU_x86
  54. #define __CPU_x86
  55. #endif
  56. #ifdef CC_GCC_LIKE_ASM
  57. #if defined __CPU_x86 || defined __CPU_x86_64
  58. #define BIT_SCAN_ASM
  59. #endif
  60. #endif
  61. /*! \brief set default bitscan versions, depending on the architecture
  62. * In general the order is asm, debruijn, br, slow for bit_scan_forward
  63. * and asm, br, slow, debruijn for bit_scan_reverse. */
  64. #ifdef BIT_SCAN_ASM
  65. /* have asm => use it */
  66. #define bit_scan_forward32(i) bit_scan_forward_asm32(i)
  67. #define bit_scan_forward64(i) bit_scan_forward_asm64(i)
  68. #define bit_scan_reverse32(i) bit_scan_reverse_asm32(i)
  69. #define bit_scan_reverse64(i) bit_scan_reverse_asm64(i)
  70. #elif defined __CPU_x86 || defined __CPU_x86_64
  71. /* no asm (e.g. no CC_GCC_LIKE_ASM) => debruijn for bit_scan_forward and
  72. * br for bit_scan_reverse */
  73. /* make sure debruijn an branch version are enabled */
  74. #ifndef BIT_SCAN_DEBRUIJN
  75. #define BIT_SCAN_DEBRUIJN
  76. #endif
  77. #ifndef BIT_SCAN_BRANCH
  78. #define BIT_SCAN_BRANCH
  79. #endif
  80. #define bit_scan_forward32(i) bit_scan_forward_debruijn32(i)
  81. #define bit_scan_forward64(i) bit_scan_forward_debruijn64(i)
  82. #define bit_scan_reverse32(i) bit_scan_reverse_br32(i)
  83. #define bit_scan_reverse64(i) bit_scan_reverse_br64(i)
  84. #elif defined __CPU_sparc64
  85. /* no asm yet => use branch for everything in 64 bit mode
  86. * and debruijn + branch in 32 bit mode
  87. * (in 64bit mode the branch method is slightly faster then debruijn,
  88. * however note that in 32 bit mode the roles are reversed for _forward)*/
  89. #ifndef BIT_SCAN_BRANCH
  90. #define BIT_SCAN_BRANCH
  91. #endif
  92. #define bit_scan_reverse32(i) bit_scan_reverse_br32(i)
  93. #define bit_scan_reverse64(i) bit_scan_reverse_br64(i)
  94. #ifdef LP64
  95. #define bit_scan_forward32(i) bit_scan_forward_br32(i)
  96. #define bit_scan_forward64(i) bit_scan_forward_br64(i)
  97. #else /* LP64 */
  98. #ifndef BIT_SCAN_DEBRUIJN
  99. #define BIT_SCAN_DEBRUIJN
  100. #endif
  101. #define bit_scan_forward32(i) bit_scan_forward_debruijn32(i)
  102. #define bit_scan_forward64(i) bit_scan_forward_debruijn64(i)
  103. #endif /* LP64 */
  104. #else /* __CPU_XXX */
  105. /* default - like x86 no asm */
  106. /* make sure debruijn an branch version are enabled */
  107. #ifndef BIT_SCAN_DEBRUIJN
  108. #define BIT_SCAN_DEBRUIJN
  109. #endif
  110. #ifndef BIT_SCAN_BRANCH
  111. #define BIT_SCAN_BRANCH
  112. #endif
  113. #define bit_scan_forward32(i) bit_scan_forward_debruijn32(i)
  114. #define bit_scan_forward64(i) bit_scan_forward_debruijn64(i)
  115. #define bit_scan_reverse32(i) bit_scan_reverse_br32(i)
  116. #define bit_scan_reverse64(i) bit_scan_reverse_br64(i)
  117. #endif /* __CPU_XXX */
  118. /*! \brief try to use the right version for bit_scan_forward(unisgned long l)
  119. */
  120. #if (defined (ULONG_MAX) && ULONG_MAX > 4294967295) || defined LP64
  121. /*! \brief long is 64 bits */
  122. #define bit_scan_forward(l) bit_scan_forward64((unsigned long long)(l))
  123. #define bit_scan_reverse(l) bit_scan_reverse64((unsigned long long)(l))
  124. #else
  125. /*! \brief long is 32 bits */
  126. #define bit_scan_forward(l) bit_scan_forward32((l))
  127. #define bit_scan_reverse(l) bit_scan_reverse32((l))
  128. #endif
  129. #ifdef BIT_SCAN_DEBRUIJN
  130. /*! \brief use a de Bruijn sequence to get the index of the set bit for a number
  131. * of the form 2^k (DEBRUIJN_HASH32() and DEBRUIJN_HASH64()).
  132. * bit_scan_forward & bit_scan_reverse would need first to convert
  133. * the argument to 2^k (where k is the first set bit or last set bit index)-
  134. * For bit_scan_forward this can be done very fast using x & (-x).
  135. * For more info about this method see:
  136. * http://citeseer.ist.psu.edu/leiserson98using.html
  137. * ("Using de Bruijn Sequences to Index a 1 in a Computer Word")
  138. */
  139. extern unsigned char _debruijn_hash32[32]; /* see bit_scan.c */
  140. extern unsigned char _debruijn_hash64[64]; /* see bit_scan.c */
  141. #define DEBRUIJN_CT32 0x04653ADFU
  142. #define DEBRUIJN_CT64 0x0218A392CD3D5DBFULL
  143. #define DEBRUIJN_HASH32(x)\
  144. (((x)*DEBRUIJN_CT32)>>(sizeof(x)*8-5))
  145. #define DEBRUIJN_HASH64(x)\
  146. (((x)*DEBRUIJN_CT64)>>(sizeof(x)*8-6))
  147. #define bit_scan_forward_debruijn32(x) \
  148. ( _debruijn_hash32[DEBRUIJN_HASH32((x) & (-(x)))])
  149. #define bit_scan_forward_debruijn64(x) \
  150. ( _debruijn_hash64[DEBRUIJN_HASH64((x) & (-(x)))])
  151. static inline int bit_scan_reverse_debruijn32(unsigned int v)
  152. {
  153. unsigned int last;
  154. do{
  155. last=v;
  156. v=v&(v-1);
  157. }while(v); /* => last is 2^k */
  158. return _debruijn_hash32[DEBRUIJN_HASH32(last)];
  159. }
  160. static inline int bit_scan_reverse_debruijn64(unsigned long long v)
  161. {
  162. unsigned long long last;
  163. do{
  164. last=v;
  165. v=v&(v-1);
  166. }while(v); /* => last is 2^k */
  167. return _debruijn_hash64[DEBRUIJN_HASH64(last)];
  168. }
  169. #endif /* BIT_SCAN_DEBRUIJN */
  170. #ifdef BIT_SCAN_SLOW
  171. /* only for reference purposes (testing the other versions against it) */
  172. static inline int bit_scan_forward_slow32(unsigned int v)
  173. {
  174. int r;
  175. for(r=0; r<(sizeof(v)*8); r++, v>>=1)
  176. if (v&1) return r;
  177. return 0;
  178. }
  179. static inline int bit_scan_reverse_slow32(unsigned int v)
  180. {
  181. int r;
  182. for(r=sizeof(v)*8-1; r>0; r--, v<<=1)
  183. if (v& (1UL<<(sizeof(v)*8-1))) return r;
  184. return 0;
  185. }
  186. static inline int bit_scan_forward_slow64(unsigned long long v)
  187. {
  188. int r;
  189. for(r=0; r<(sizeof(v)*8); r++, v>>=1)
  190. if (v&1ULL) return r;
  191. return 0;
  192. }
  193. static inline int bit_scan_reverse_slow64(unsigned long long v)
  194. {
  195. int r;
  196. for(r=sizeof(v)*8-1; r>0; r--, v<<=1)
  197. if (v& (1ULL<<(sizeof(v)*8-1))) return r;
  198. return 0;
  199. }
  200. #endif /* BIT_SCAN_SLOW */
  201. #ifdef BIT_SCAN_BRANCH
  202. static inline int bit_scan_forward_br32(unsigned int v)
  203. {
  204. int b;
  205. b=0;
  206. if (v&0x01)
  207. return 0;
  208. if (!(v & 0xffff)){
  209. b+=16;
  210. v>>=16;
  211. }
  212. if (!(v&0xff)){
  213. b+=8;
  214. v>>=8;
  215. }
  216. if (!(v&0x0f)){
  217. b+=4;
  218. v>>=4;
  219. }
  220. if (!(v&0x03)){
  221. b+=2;
  222. v>>=2;
  223. }
  224. b+= !(v&0x01);
  225. return b;
  226. }
  227. static inline int bit_scan_reverse_br32(unsigned int v)
  228. {
  229. int b;
  230. b=0;
  231. if (v & 0xffff0000){
  232. b+=16;
  233. v>>=16;
  234. }
  235. if (v&0xff00){
  236. b+=8;
  237. v>>=8;
  238. }
  239. if (v&0xf0){
  240. b+=4;
  241. v>>=4;
  242. }
  243. if (v&0x0c){
  244. b+=2;
  245. v>>=2;
  246. }
  247. b+= !!(v&0x02);
  248. return b;
  249. }
  250. static inline int bit_scan_forward_br64(unsigned long long v)
  251. {
  252. int b;
  253. b=0;
  254. if (v&0x01ULL)
  255. return 0;
  256. if (!(v & 0xffffffffULL)){
  257. b+=32;
  258. v>>=32;
  259. }
  260. if (!(v & 0xffffULL)){
  261. b+=16;
  262. v>>=16;
  263. }
  264. if (!(v&0xffULL)){
  265. b+=8;
  266. v>>=8;
  267. }
  268. if (!(v&0x0fULL)){
  269. b+=4;
  270. v>>=4;
  271. }
  272. if (!(v&0x03ULL)){
  273. b+=2;
  274. v>>=2;
  275. }
  276. b+= !(v&0x01ULL);
  277. return b;
  278. }
  279. static inline int bit_scan_reverse_br64(unsigned long long v)
  280. {
  281. int b;
  282. b=0;
  283. if (v & 0xffffffff00000000ULL){
  284. b+=32;
  285. v>>=32;
  286. }
  287. if (v & 0xffff0000ULL){
  288. b+=16;
  289. v>>=16;
  290. }
  291. if (v&0xff00ULL){
  292. b+=8;
  293. v>>=8;
  294. }
  295. if (v&0xf0ULL){
  296. b+=4;
  297. v>>=4;
  298. }
  299. if (v&0x0cULL){
  300. b+=2;
  301. v>>=2;
  302. }
  303. b+= !!(v&0x02ULL);
  304. return b;
  305. }
  306. #endif /* BIT_SCAN_BRANCH */
  307. #ifdef BIT_SCAN_ASM
  308. #if defined __CPU_x86 || defined __CPU_x86_64
  309. #define HAS_BIT_SCAN_ASM
  310. static inline int bit_scan_forward_asm32(unsigned int v)
  311. {
  312. int r;
  313. asm volatile(" bsfl %1, %0": "=r"(r): "rm"(v) );
  314. return r;
  315. }
  316. static inline int bit_scan_reverse_asm32(unsigned int v)
  317. {
  318. int r;
  319. asm volatile(" bsrl %1, %0": "=r"(r): "rm"(v) );
  320. return r;
  321. }
  322. #ifdef __CPU_x86_64
  323. static inline int bit_scan_forward_asm64(unsigned long long v)
  324. {
  325. long r;
  326. asm volatile(" bsfq %1, %0": "=r"(r): "rm"(v) );
  327. return r;
  328. }
  329. static inline int bit_scan_reverse_asm64(unsigned long long v)
  330. {
  331. long r;
  332. asm volatile(" bsrq %1, %0": "=r"(r): "rm"(v) );
  333. return r;
  334. }
  335. #else
  336. static inline int bit_scan_forward_asm64(unsigned long long v)
  337. {
  338. if ((unsigned int)v)
  339. return bit_scan_forward_asm32((unsigned int)v);
  340. return 32+bit_scan_forward_asm32(*(((unsigned int*)(void*)&v)+1));
  341. }
  342. static inline int bit_scan_reverse_asm64(unsigned long long v)
  343. {
  344. if (v & 0xffffffff00000000ULL)
  345. return 32+bit_scan_reverse_asm32(*(((unsigned int*)(void*)&v)+1));
  346. return bit_scan_reverse_asm32((unsigned int)v);
  347. }
  348. #endif /* __CPU_x86_64 */
  349. #endif /* __CPU_x86 || __CPU_x86_64 */
  350. #endif /* BIT_SCAN_ASM */
  351. #endif