- __builtin_clz, __builtin_ctz, _BitScanForward, _BitScanReverse の仕様
- MSVC の _BitScanForward, _BitScanReverse を使った __builtin_clz, __builtin_ctz 互換関数
- gcc の __builtin_clz, __builtin_ctz を使った _BitScanForward, _BitScanReverse 互換関数
- ついでに、gcc のインラインアセンブラを使った _BitScanForward, _BitScanReverse 互換関数
__builtin_clz, __builtin_ctz, _BitScanForward, _BitScanReverse の仕様
- int __builtin_clz(unsigned int)
00000000 10110011 11111100 11010100 のとき、上位ビットの連続する 0 の数は8個なので、戻り値は 8 となる。
全ビットが0のときの戻り値は未定義。
- int __builtin_ctz(unsigned int)
00000000 10110011 11111100 11010100 のとき、下位ビットの連続する 0 の数は2個なので、戻り値は 2 となる。
全ビットが0のときの戻り値は未定義。
- unsigned char _BitScanForward(unsigned long *Index, unsigned long Mask)
00000000 10110011 11111100 11010100 のとき、下位ビットから見て最初の1の位置は2(最下位ビットの位置は0)なので、*Index に2を設定したあと、非0の値が戻り値となる。
下位から見て最初の1が見つかるまでのビットはすべて0なので、最初の1の位置は、下位の連続する0の個数と同じ値となる。したがって、__builtin_ctz を使えば _BitScanForward が実装できるし、_BitScanForward を使えば、__builtin_ctz を実装できる。
- unsigned char _BitScanReverse(unsigned long *Index, unsigned long Mask)
00000000 10110011 11111100 11010100 のとき、上位ビットから見て最初の1の位置は23(最下位ビットの位置は0)なので、*Index に23を設定したあと、非0の値が戻り値となる。
上位から見て最初の1が見つかるまでのビットはすべて0なので、最初の1の位置は上位の連続する0の個数から簡単な計算で求まる。したがって、__builtin_clz を使えば _BitScanReverse が実装できるし、_BitScanReverse を使えば、__builtin_clz を実装できる。
MSVC の _BitScanForward, _BitScanReverse を使った __builtin_clz, __builtin_ctz 互換関数
#include <intrin.h>
int __builtin_clz(unsigned int n)
{
unsinged long index;
/* n が0のときの __builtin_clz の戻り値は未定義なので、
* _BitScanReverse の戻り値チェックは割愛する。
*/
_BitScanReverse(&index, n);
return 31 - index;
}
int __builtin_ctz(unsigned int n)
{
unsinged long index;
/* n が0のときの __builtin_ctz の戻り値は未定義なので、
* _BitScanForward の戻り値チェックは割愛する。
*/
_BitScanForward(&index, n);
return index;
}
gcc の __builtin_clz, __builtin_ctz を使った _BitScanForward, _BitScanReverse 互換関数
unsigned char inline _BitScanForward(unsigned int *Index, unsigned int Mask)
{
if (Mask) {
*Index = __builtin_ctz(Mask);
return 1;
} else {
/* 戻り値が0のとき、*Index がどうなるかは未定義。*/
return 0;
}
}
unsigned char inline _BitScanForward(unsigned int *Index, unsigned int Mask)
{
if (Mask) {
*Index = 31 - __builtin_clz(Mask);
return 1;
} else {
/* 戻り値が0のとき、*Index がどうなるかは未定義。*/
return 0;
}
}
gcc のインラインアセンブラを使った _BitScanForward, _BitScanReverse 互換関数
unsigned char inline _BitScanForward(unsigned int *Index, unsigned int Mask)
{
unsigned char rv;
__asm(
"bsfl %2, %0;"
"setne %1;"
: "=r"(*Index),"=r"(rv)
: "g"(Mask)
: "cc");
return rv;
}
unsigned char inline _BitScanReverse(unsigned int *Index, unsigned int Mask)
{
unsigned char rv;
__asm(
"bsrl %2, %0;"
"setne %1;"
: "=r"(*Index),"=r"(rv)
: "g"(Mask)
: "cc");
return rv;
}
No comments:
Post a Comment