ベクトル組み込み関数を使用して個人の画像処理ライブラリを書き直すことにより、SIMD機能の使用方法を学んでいます。基本的な機能の1つは、単純な「配列+=
」です。
void arrayAdd(unsigned char* A, unsigned char* B, size_t n) {
for(size_t i=0; i < n; i++) { B[i] += A[i] };
}
任意の配列長の場合、明らかなSIMDコード(16で整列されていると仮定)は次のようになります。
size_t i = 0;
__m128i xmm0, xmm1;
n16 = n - (n % 16);
for (; i < n16; i+=16) {
xmm0 = _mm_load_si128( (__m128i*) (A + i) );
xmm1 = _mm_load_si128( (__m128i*) (B + i) );
xmm1 = _mm_add_epi8( xmm0, xmm1 );
_mm_store_si128( (__m128i*) (B + i), xmm1 );
}
for (; i < n; i++) { B[i] += A[i]; }
しかし、SIMD命令ですべての追加を行うことは可能ですか?私はこれを試してみようと思いました:
__m128i mask = (0x100<<8*(n - n16))-1;
_mm_maskmoveu_si128( xmm1, mask, (__m128i*) (B + i) );
余分な要素のために、しかしそれは未定義の振る舞いをもたらすでしょうか?配列のmask
境界を超えて実際にアクセスが行われないことを保証する必要があります(私は思います)。別の方法は、最初に追加の要素を実行することですが、次に配列をで整列させる必要がありますがn-n16
、これは正しくないようです。
ベクトル化されたループのような別のより最適なパターンはありますか?