web-dev-qa-db-ja.com

bzhi(y、tzcnt(x))で不要なmov ecx、ecx命令を回避する

Tzcntを使用して計算されたビット位置(ゼロではない)があり、その位置から開始して上位ビットをゼロにしたいと考えています。これはC++と逆アセンブリのコードです(私はMSVCを使用しています)。

auto position = _tzcnt_u64(xxx); 
auto masked =_bzhi_u64(yyy, static_cast<uint32_t>(position));
tzcnt       rcx,rdx  
mov         ecx,ecx  
bzhi        rax,rbx,rcx 

BZHIは2番目のパラメーターとしてunsigned intを受け入れますが、rcxからのビット[7..0]のみを使用するため、この 'mov'命令は私の意見では不要です。

これを後でポップカウントを計算するために使用するので、代わりに<<(64-position)のようなものを使用することもできます。

問題は-これらの2つのコードの実行時間は同じですが、bzhiはsub + shlxよりも高速に実行する必要があるため、movがおそらく違いを生みます。

それを回避する方法はありますか、それともこのコンパイラのものですか?

3
Marka

これはコンパイラーのものです(Visual C++ 2019 00435-60000-00000-AA388現在)。
MSVCのimmintrin.hは、

__int64 _bzhi_u64(unsigned __int64, unsigned int);

intelの次善の 固有の定義コマンドドキュメント と矛盾します(すべてのbzhiパラメータは同じサイズです)。
clangはbmi2intrin.hにあります

unsigned long long _bzhi_u64(unsigned long long __X, unsigned long long __Y)

なので、_tzcnt_u64結果はコードになります。

私はMSVCのimmintrin.hにパッチを適用しました。悲しい!ピーターの洗練された回避策は私の場合には適用されないためです(lzcnt/bzhi、popcntは不可)。

0
pshufb