mirror of https://github.com/sipwise/kamailio.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
423 lines
9.7 KiB
423 lines
9.7 KiB
/*
|
|
* $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
|