123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422 |
- /*
- * $Id$
- *
- * Copyright (C) 2007 iptelorg GmbH
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
- /*!
- * \file
- * \brief SIP-router core :: bit scan operations
- * \ingroup core
- * Module: \ref core
- *
- * bit scan operations
- *
- * - int bit_scan_forward(unsigned long v) - returns the index of the first
- * set bit (undefined value if v==0)
- * - int bit_scan_forward32(unsigned int v) - returns the index of the first
- * set bit (undefined value if v==0)
- * - int bit_scan_forward64(long long v) - returns the index of the first
- * set bit (undefined value if v==0)
- * - int bit_scan_reverse(unsigned long v) - returns the index of the last
- * set bit (undefined value if v==0)
- * - int bit_scan_reverse32(unsigned int v) - returns the index of the last
- * set bit (undefined value if v==0)
- * - int bit_scan_reverse64(long long v) - returns the index of the last
- * set bit (undefined value if v==0)
- *
- * Config defines: CC_GCC_LIKE_ASM - the compiler support gcc style
- * inline asm,
- * __CPU_x86, __CPU_x86_64,
- * ULONG_MAX (limits.h)
- */
- /*
- * History:
- * --------
- * 2007-06-23 created by andrei
- */
- #ifndef _bit_scan_h
- #define _bit_scan_h
- #include <limits.h>
- /*! \brief fix __CPU_i386 -> __CPU_x86 */
- #if defined __CPU_i386 && ! defined __CPU_x86
- #define __CPU_x86
- #endif
- #ifdef CC_GCC_LIKE_ASM
- #if defined __CPU_x86 || defined __CPU_x86_64
- #define BIT_SCAN_ASM
- #endif
- #endif
- /*! \brief set default bitscan versions, depending on the architecture
- * In general the order is asm, debruijn, br, slow for bit_scan_forward
- * and asm, br, slow, debruijn for bit_scan_reverse. */
- #ifdef BIT_SCAN_ASM
- /* have asm => use it */
- #define bit_scan_forward32(i) bit_scan_forward_asm32(i)
- #define bit_scan_forward64(i) bit_scan_forward_asm64(i)
- #define bit_scan_reverse32(i) bit_scan_reverse_asm32(i)
- #define bit_scan_reverse64(i) bit_scan_reverse_asm64(i)
- #elif defined __CPU_x86 || defined __CPU_x86_64
- /* no asm (e.g. no CC_GCC_LIKE_ASM) => debruijn for bit_scan_forward and
- * br for bit_scan_reverse */
- /* make sure debruijn an branch version are enabled */
- #ifndef BIT_SCAN_DEBRUIJN
- #define BIT_SCAN_DEBRUIJN
- #endif
- #ifndef BIT_SCAN_BRANCH
- #define BIT_SCAN_BRANCH
- #endif
- #define bit_scan_forward32(i) bit_scan_forward_debruijn32(i)
- #define bit_scan_forward64(i) bit_scan_forward_debruijn64(i)
- #define bit_scan_reverse32(i) bit_scan_reverse_br32(i)
- #define bit_scan_reverse64(i) bit_scan_reverse_br64(i)
- #elif defined __CPU_sparc64
- /* no asm yet => use branch for everything in 64 bit mode
- * and debruijn + branch in 32 bit mode
- * (in 64bit mode the branch method is slightly faster then debruijn,
- * however note that in 32 bit mode the roles are reversed for _forward)*/
- #ifndef BIT_SCAN_BRANCH
- #define BIT_SCAN_BRANCH
- #endif
- #define bit_scan_reverse32(i) bit_scan_reverse_br32(i)
- #define bit_scan_reverse64(i) bit_scan_reverse_br64(i)
- #ifdef LP64
- #define bit_scan_forward32(i) bit_scan_forward_br32(i)
- #define bit_scan_forward64(i) bit_scan_forward_br64(i)
- #else /* LP64 */
- #ifndef BIT_SCAN_DEBRUIJN
- #define BIT_SCAN_DEBRUIJN
- #endif
- #define bit_scan_forward32(i) bit_scan_forward_debruijn32(i)
- #define bit_scan_forward64(i) bit_scan_forward_debruijn64(i)
- #endif /* LP64 */
- #else /* __CPU_XXX */
- /* default - like x86 no asm */
- /* make sure debruijn an branch version are enabled */
- #ifndef BIT_SCAN_DEBRUIJN
- #define BIT_SCAN_DEBRUIJN
- #endif
- #ifndef BIT_SCAN_BRANCH
- #define BIT_SCAN_BRANCH
- #endif
- #define bit_scan_forward32(i) bit_scan_forward_debruijn32(i)
- #define bit_scan_forward64(i) bit_scan_forward_debruijn64(i)
- #define bit_scan_reverse32(i) bit_scan_reverse_br32(i)
- #define bit_scan_reverse64(i) bit_scan_reverse_br64(i)
- #endif /* __CPU_XXX */
- /*! \brief try to use the right version for bit_scan_forward(unisgned long l)
- */
- #if (defined (ULONG_MAX) && ULONG_MAX > 4294967295) || defined LP64
- /*! \brief long is 64 bits */
- #define bit_scan_forward(l) bit_scan_forward64((unsigned long long)(l))
- #define bit_scan_reverse(l) bit_scan_reverse64((unsigned long long)(l))
- #else
- /*! \brief long is 32 bits */
- #define bit_scan_forward(l) bit_scan_forward32((l))
- #define bit_scan_reverse(l) bit_scan_reverse32((l))
- #endif
- #ifdef BIT_SCAN_DEBRUIJN
- /*! \brief use a de Bruijn sequence to get the index of the set bit for a number
- * of the form 2^k (DEBRUIJN_HASH32() and DEBRUIJN_HASH64()).
- * bit_scan_forward & bit_scan_reverse would need first to convert
- * the argument to 2^k (where k is the first set bit or last set bit index)-
- * For bit_scan_forward this can be done very fast using x & (-x).
- * For more info about this method see:
- * http://citeseer.ist.psu.edu/leiserson98using.html
- * ("Using de Bruijn Sequences to Index a 1 in a Computer Word")
- */
- extern unsigned char _debruijn_hash32[32]; /* see bit_scan.c */
- extern unsigned char _debruijn_hash64[64]; /* see bit_scan.c */
- #define DEBRUIJN_CT32 0x04653ADFU
- #define DEBRUIJN_CT64 0x0218A392CD3D5DBFULL
- #define DEBRUIJN_HASH32(x)\
- (((x)*DEBRUIJN_CT32)>>(sizeof(x)*8-5))
- #define DEBRUIJN_HASH64(x)\
- (((x)*DEBRUIJN_CT64)>>(sizeof(x)*8-6))
- #define bit_scan_forward_debruijn32(x) \
- ( _debruijn_hash32[DEBRUIJN_HASH32((x) & (-(x)))])
- #define bit_scan_forward_debruijn64(x) \
- ( _debruijn_hash64[DEBRUIJN_HASH64((x) & (-(x)))])
- static inline int bit_scan_reverse_debruijn32(unsigned int v)
- {
- unsigned int last;
-
- do{
- last=v;
- v=v&(v-1);
- }while(v); /* => last is 2^k */
- return _debruijn_hash32[DEBRUIJN_HASH32(last)];
- }
- static inline int bit_scan_reverse_debruijn64(unsigned long long v)
- {
- unsigned long long last;
-
- do{
- last=v;
- v=v&(v-1);
- }while(v); /* => last is 2^k */
- return _debruijn_hash64[DEBRUIJN_HASH64(last)];
- }
- #endif /* BIT_SCAN_DEBRUIJN */
- #ifdef BIT_SCAN_SLOW
- /* only for reference purposes (testing the other versions against it) */
- static inline int bit_scan_forward_slow32(unsigned int v)
- {
- int r;
- for(r=0; r<(sizeof(v)*8); r++, v>>=1)
- if (v&1) return r;
- return 0;
- }
- static inline int bit_scan_reverse_slow32(unsigned int v)
- {
- int r;
- for(r=sizeof(v)*8-1; r>0; r--, v<<=1)
- if (v& (1UL<<(sizeof(v)*8-1))) return r;
- return 0;
- }
- static inline int bit_scan_forward_slow64(unsigned long long v)
- {
- int r;
- for(r=0; r<(sizeof(v)*8); r++, v>>=1)
- if (v&1ULL) return r;
- return 0;
- }
- static inline int bit_scan_reverse_slow64(unsigned long long v)
- {
- int r;
- for(r=sizeof(v)*8-1; r>0; r--, v<<=1)
- if (v& (1ULL<<(sizeof(v)*8-1))) return r;
- return 0;
- }
- #endif /* BIT_SCAN_SLOW */
- #ifdef BIT_SCAN_BRANCH
- static inline int bit_scan_forward_br32(unsigned int v)
- {
- int b;
-
- b=0;
- if (v&0x01)
- return 0;
- if (!(v & 0xffff)){
- b+=16;
- v>>=16;
- }
- if (!(v&0xff)){
- b+=8;
- v>>=8;
- }
- if (!(v&0x0f)){
- b+=4;
- v>>=4;
- }
- if (!(v&0x03)){
- b+=2;
- v>>=2;
- }
- b+= !(v&0x01);
- return b;
- }
- static inline int bit_scan_reverse_br32(unsigned int v)
- {
- int b;
-
- b=0;
- if (v & 0xffff0000){
- b+=16;
- v>>=16;
- }
- if (v&0xff00){
- b+=8;
- v>>=8;
- }
- if (v&0xf0){
- b+=4;
- v>>=4;
- }
- if (v&0x0c){
- b+=2;
- v>>=2;
- }
- b+= !!(v&0x02);
- return b;
- }
- static inline int bit_scan_forward_br64(unsigned long long v)
- {
- int b;
-
- b=0;
- if (v&0x01ULL)
- return 0;
- if (!(v & 0xffffffffULL)){
- b+=32;
- v>>=32;
- }
- if (!(v & 0xffffULL)){
- b+=16;
- v>>=16;
- }
- if (!(v&0xffULL)){
- b+=8;
- v>>=8;
- }
- if (!(v&0x0fULL)){
- b+=4;
- v>>=4;
- }
- if (!(v&0x03ULL)){
- b+=2;
- v>>=2;
- }
- b+= !(v&0x01ULL);
- return b;
- }
- static inline int bit_scan_reverse_br64(unsigned long long v)
- {
- int b;
-
- b=0;
- if (v & 0xffffffff00000000ULL){
- b+=32;
- v>>=32;
- }
- if (v & 0xffff0000ULL){
- b+=16;
- v>>=16;
- }
- if (v&0xff00ULL){
- b+=8;
- v>>=8;
- }
- if (v&0xf0ULL){
- b+=4;
- v>>=4;
- }
- if (v&0x0cULL){
- b+=2;
- v>>=2;
- }
- b+= !!(v&0x02ULL);
- return b;
- }
- #endif /* BIT_SCAN_BRANCH */
- #ifdef BIT_SCAN_ASM
- #if defined __CPU_x86 || defined __CPU_x86_64
- #define HAS_BIT_SCAN_ASM
- static inline int bit_scan_forward_asm32(unsigned int v)
- {
- int r;
- asm volatile(" bsfl %1, %0": "=r"(r): "rm"(v) );
- return r;
- }
- static inline int bit_scan_reverse_asm32(unsigned int v)
- {
- int r;
- asm volatile(" bsrl %1, %0": "=r"(r): "rm"(v) );
- return r;
- }
- #ifdef __CPU_x86_64
- static inline int bit_scan_forward_asm64(unsigned long long v)
- {
- long r;
- asm volatile(" bsfq %1, %0": "=r"(r): "rm"(v) );
- return r;
- }
- static inline int bit_scan_reverse_asm64(unsigned long long v)
- {
- long r;
- asm volatile(" bsrq %1, %0": "=r"(r): "rm"(v) );
- return r;
- }
- #else
- static inline int bit_scan_forward_asm64(unsigned long long v)
- {
- if ((unsigned int)v)
- return bit_scan_forward_asm32((unsigned int)v);
- return 32+bit_scan_forward_asm32(*(((unsigned int*)(void*)&v)+1));
- }
- static inline int bit_scan_reverse_asm64(unsigned long long v)
- {
- if (v & 0xffffffff00000000ULL)
- return 32+bit_scan_reverse_asm32(*(((unsigned int*)(void*)&v)+1));
- return bit_scan_reverse_asm32((unsigned int)v);
- }
- #endif /* __CPU_x86_64 */
- #endif /* __CPU_x86 || __CPU_x86_64 */
- #endif /* BIT_SCAN_ASM */
- #endif
|