web-dev-qa-db-ja.com

__builtin_clzの実装

GCC(4.6+)___builtin_clz_の実装は何ですか? Intel x86_64 (AVX)の一部のCPU命令に対応していますか?

23
Cartesius00

Bit Scan Reverse 命令に変換し、減算する必要があります。 BSRは、先頭の1のインデックスを提供し、Wordのサイズからそれを引くと、先頭のゼロの数を取得できます。

編集:CPUがLZCNT(リーディングゼロカウント)をサポートしている場合、おそらくそれでもうまくいきますが、すべてのx86-64チップにその命令があるわけではありません。

22
chisophugis

はいといいえ。

CLZ(カウントリーディングゼロ)とBSR(ビットスキャンリバース)は関連していますが異なります。 CLZは等しい(タイプビット幅-1)-BSR。 CTZ(ゼロに続くカウント)、別名FFS(最初のセットを見つける)はBSF(ビットスキャンフォワード)と同じです。

ゼロで操作する場合、これらはすべて未定義であることに注意してください!

質問への回答では、ほとんどの場合x86およびx86_64では、__ builtin_clzは31(または型の幅が何であれ)から減算されたBSR演算を生成し、__ builting_ctzはBSF演算を生成します。

GCCが生成しているアセンブラーを知りたい場合は、知ることが最善の方法です。 -Sフラグは、指定された入力に対して生成したアセンブラーをgcc出力します。

gcc -S -o test.S test.c

考慮してください:

unsigned int clz(unsigned int num) {
    return __builtin_clz(num);
}

unsigned int ctz(unsigned int num) {
    return __builtin_ctz(num);
}

X86でclz gcc(-O2)を実行すると、以下が生成されます。

bsrl    %edi, %eax
xorl    $31, %eax
ret

そしてctzの場合:

bsfl    %edi, %eax
ret

Clzではなくbsrが本当に必要な場合は、31-clz(32ビット整数の場合)を実行する必要があることに注意してください。これは、XOR 31 as x XOR 31 == 31-x(このIDは、2 ^ y-1からの数にのみ当てはまります)したがって、

num = __builtin_clz(num) ^ 31;

収量

bsrl    %edi, %eax
ret
21
theycallhimart