2016-10-17 5 views
1

私はx86_64の組み込み関数に慣れていないので、私は256ビットのベクトルレジスタを使って次の操作をしたいと思います。 _mm256_maddubs_epi16(a、b)を使用していました。 char * charは16ビットの最大値を超える可能性があるので、この命令はオーバーフローの問題があるようです。 _mm256_unpackhi_epi32とそれに関連する指示を理解している問題があります。intrinsicsを使用して2つのchar配列を要素単位で掛け合わせ、その乗算をintに集計する方法は?

誰も私を詳しく説明し、私に目的地までの光を見せてもらえますか?ありがとうございました!

int sumup_char_arrays(char *A, char *B, int size) { 
    assert (size % 32 == 0); 
    int sum = 0; 
    for (int i = 0; i < size; i++) { 
     sum += A[i]*B[i]; 
    } 
    return sum; 
} 
+1

まず、SSEのバージョンを記述することをお勧めします。 16ビットにアンパックし、 '_mm_madd_epi16'を使って重い作業を行います。それは初心者のための挑戦であろうが、おそらくAVXの激しい分割レーンの問題はないだろう。いつでもSSEからAVXへ行くことができます。 –

答えて

1

解決策、特に削減の最終段階を改善するためのアイデアを見つけました。

int sumup_char_arrays(char *A, char *B, int size) { 
    assert (size % 32 == 0); 
    int sum = 0; 
    __m256i sum_tmp; 
    for (int i = 0; i < size; i += 32) { 
     __m256i ma_l = _mm256_cvtepi8_epi16(_mm_load_si128((__m128i*)A)); 
     __m256i ma_h = _mm256_cvtepi8_epi16(_mm_load_si128((__m128i*)(A+16))); 
     __m256i mb_l = _mm256_cvtepi8_epi16(_mm_load_si128((__m128i*)B)); 
     __m256i mb_h = _mm256_cvtepi8_epi16(_mm_load_si128((__m128i*)(B+16))); 
     __m256i mc = _mm256_madd_epi16(ma_l, mb_l); 
     mc = _mm256_add_epi32(mc, _mm256_madd_epi16(ma_h, mb_h)); 
     sum_tmp = _mm256_add_epi32(mc, sum_tmp); 
     //sum += A[i]*B[i]; 
    } 
    sum_tmp = _mm256_add_epi32(sum_tmp, _mm256_permute2x128_si256(sum_tmp, sum_tmp, 0x81)); 
    sum_tmp = _mm256_add_epi32(sum_tmp, _mm256_srli_si256(sum_tmp, 8)); 
    sum_tmp = _mm256_add_epi32(sum_tmp, _mm256_srli_si256(sum_tmp, 4));   
    sum = _mm256_extract_epi32(sum_tmp, 0); 
    return sum; 
} 
+1

char配列の1つがunsignedとして扱われない限り、[PMADDUBSW](http://www.felixcloutier.com/x86/PMADDUBSW.html)を使用することができない限り、私にはうまく見えます。水平縮小は、permuteを必要とせず、抽出して128にキャストするだけです。[この回答を参照してください(http://stackoverflow.com/questions/6996764/fastest-way-to-do-horizo​​ntal-float-vector-sum -on-x86)おそらく最適なパターンの水平方向の合計は、コードのバイト数を節約できるかもしれません。 –

関連する問題