SSE (SSE 4.2 まで) を使用して 8 ビットの符号なし比較を実行する最も効率的な方法を見つけようとしています。
私が取り組んでいる最も一般的なケースは、> 0U の比較です。
_mm_cmpgt_epu8(v, _mm_setzero_si128()) // #1
(もちろん、これは非ゼロの単純なテストと見なすこともできます。)
しかし、私はより一般的なケースにも多少興味があります。
_mm_cmpgt_epu8(v1, v2) // #2
最初のケースは、0 と比較して結果を反転するなど、さまざまな方法を使用して 2 つの命令で実装できます。2 番目のケースでは通常、3 つの命令が必要です。たとえば、両方のオペランドから 128 を減算し、符号付き比較を実行します。(さまざまな 3 つの命令ソリューションについては、この質問を参照してください。)
私が理想的に探しているのは、#1 の単一命令ソリューションと #2 の 2 つの命令ソリューションです。これらのどちらも可能でない場合、最新の Intel CPU (Sandy Bridge、Ivy Bridge、Haswell) で最も効率的な 2 つまたは 3 つの命令のさまざまな実装についての考えにも興味があります。
これまでのケース #2 の最適な実装:
- unsigned max と等しいかどうかを比較し、結果を反転します。
#define _mm_cmpgt_epu8(v0, v1) \ _mm_andnot_si128(_mm_cmpeq_epi8(_mm_max_epu8(v0, v1), v1), \ _mm_set1_epi8(-1))
2 つの算術命令 + 1 つのビット単位 = 1.33 スループット。
- 両方の引数の符号ビットを反転し (== 128 を減算)、符号付き比較を使用します。
#define _mm_cmpgt_epu8(v0, v1) \ _mm_cmpgt_epi8(_mm_xor_si128(v0, _mm_set1_epi8(-128)), \ _mm_xor_si128(v1, _mm_set1_epi8(-128)))
1 つの算術命令 + 2 つのビット単位 = 1.16 スループット。
上記のケース #2 の実装から派生した、ケース #1 の最適な実装:
- 1.
#define _mm_cmpgtz_epu8(v0) \ _mm_andnot_si128(_mm_cmpeq_epi8(v0, _mm_set1_epi8(0)), \ _mm_set1_epi8(-1))
1 つの算術命令 + 1 つのビット単位 = 0.83 スループット。
- 2.
#define _mm_cmpgtz_epu8(v0) \ _mm_cmpgt_epi8(_mm_xor_si128(v0, _mm_set1_epi8(-128)), \ _mm_set1_epi8(-128)))
1 つの算術命令 + 1 つのビット単位 = 0.83 スループット。