提供されたコードでは、 関数 __mm_add_epi32_inplace_purego はアセンブリを使用して最適化できます。パフォーマンスを向上させます。特に内側のループは、より高速に実行できるように最適化できます。
位置人口をカウントするために提供されるアルゴリズムは、「位置人口カウント」と呼ばれます。このアルゴリズムは機械学習で使用され、一連のバイト内の設定ビット数をカウントします。指定されたコードでは、_mm_add_epi32_inplace_purego が 2 レベルのループで呼び出され、目的は内部ループを最適化することです。
提供されたコードは、主に と呼ばれる 8 ビット整数の配列で動作します。カウントします。内部ループはバイト スライスを反復し、バイトごとに、ビット パターンの配列 (_expand_byte) から対応するビット位置を counts 配列に追加します。 _expand_byte 配列には、各バイトを個別のビットに拡張するビット パターンが含まれています。
アセンブリを使用して内部ループを最適化するには、パフォーマンスを向上させるために汎用レジスターにカウンターを保持する必要があります。ストリーミング動作を改善するために、かなり前もってメモリをプリフェッチします。単純なシフトと加算の組み合わせ (SHRL/ADCL) を使用して、スカラー人口カウントを実装することもできます。
最適化されたアセンブリ コード の例を以下に示します。このコードは特定のプロセッサ アーキテクチャ用に書かれており、他のシステムで実行するには変更が必要な場合があります。
<code class="assembly">#include "textflag.h" // func PospopcntReg(counts *[8]int32, buf []byte) TEXT ·PospopcntReg(SB),NOSPLIT,-32 MOVQ counts+0(FP), DI MOVQ buf_base+8(FP), SI // SI = &buf[0] MOVQ buf_len+16(FP), CX // CX = len(buf) // load counts into register R8--R15 MOVL 4*0(DI), R8 MOVL 4*1(DI), R9 MOVL 4*2(DI), R10 MOVL 4*3(DI), R11 MOVL 4*4(DI), R12 MOVL 4*5(DI), R13 MOVL 4*6(DI), R14 MOVL 4*7(DI), R15 SUBQ , CX // pre-subtract 32 bit from CX JL scalar vector: VMOVDQU (SI), Y0 // load 32 bytes from buf PREFETCHT0 384(SI) // prefetch some data ADDQ , SI // advance SI past them VPMOVMSKB Y0, AX // move MSB of Y0 bytes to AX POPCNTL AX, AX // count population of AX ADDL AX, R15 // add to counter VPADDD Y0, Y0, Y0 // shift Y0 left by one place VPMOVMSKB Y0, AX // move MSB of Y0 bytes to AX POPCNTL AX, AX // count population of AX ADDL AX, R14 // add to counter VPADDD Y0, Y0, Y0 // shift Y0 left by one place VPMOVMSKB Y0, AX // move MSB of Y0 bytes to AX POPCNTL AX, AX // count population of AX ADDL AX, R13 // add to counter VPADDD Y0, Y0, Y0 // shift Y0 left by one place VPMOVMSKB Y0, AX // move MSB of Y0 bytes to AX POPCNTL AX, AX // count population of AX ADDL AX, R12 // add to counter VPADDD Y0, Y0, Y0 // shift Y0 left by one place VPMOVMSKB Y0, AX // move MSB of Y0 bytes to AX POPCNTL AX, AX // count population of AX ADDL AX, R11 // add to counter VPADDD Y0, Y0, Y0 // shift Y0 left by one place VPMOVMSKB Y0, AX // move MSB of Y0 bytes to AX POPCNTL AX, AX // count population of AX ADDL AX, R10 // add to counter VPADDD Y0, Y0, Y0 // shift Y0 left by one place VPMOVMSKB Y0, AX // move MSB of Y0 bytes to AX POPCNTL AX, AX // count population of AX ADDL AX, R9 // add to counter VPADDD Y0, Y0, Y0 // shift Y0 left by one place VPMOVMSKB Y0, AX // move MSB of Y0 bytes to AX POPCNTL AX, AX // count population of AX ADDL AX, R8 // add to counter SUBQ , CX JGE vector // repeat as long as bytes are left scalar: ADDQ , CX // undo last subtraction JE done // if CX=0, there's nothing left loop: MOVBLZX (SI), AX // load a byte from buf INCQ SI // advance past it SHRL , AX // CF=LSB, shift byte to the right ADCL , R8 // add CF to R8 SHRL , AX ADCL , R9 // add CF to R9 SHRL , AX ADCL , R10 // add CF to R10 SHRL , AX ADCL , R11 // add CF to R11 SHRL , AX ADCL , R12 // add CF to R12 SHRL , AX ADCL , R13 // add CF to R13 SHRL , AX ADCL , R14 // add CF to R14 SHRL , AX ADCL , R15 // add CF to R15 DECQ CX // mark this byte as done JNE loop // and proceed if any bytes are left // write R8--R15 back to counts done: MOVL R8, 4*0(DI) MOVL R9, 4*1(DI) MOVL R10, 4*2(DI) MOVL R11, 4*3(DI) MOVL R12, 4*4(DI) MOVL R13, 4*5(DI) MOVL R14, 4*6(DI) MOVL R15, 4*7(DI) VZEROUPPER // restore SSE-compatibility RET</code>
要約すると、 最適化にはカウンター用の汎用レジスタの使用が含まれます。事前にメモリをプリフェッチし、SHRL/ADCL を使用してスカラー人口カウントを実装します。このアプローチにより、位置人口カウント アルゴリズムのパフォーマンスが大幅に向上します。
以上がアセンブリを使用して 8 ビットの位置ポップカウント アルゴリズムを最適化するにはどうすればよいでしょうか。具体的には、内部ループに焦点を当て、プリフェッチやスカラー人口カウントなどの手法を利用することによって実現できますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。