2016-10-17 60 views
1

我对x86_64内在函数不熟悉,我想使用256位向量寄存器进行以下操作。 我正在使用_mm256_maddubs_epi16(a,b);然而,似乎这个指令有溢出问题,因为char * char可能超过16位的最大值。我有问题了解_mm256_unpackhi_epi32和相关说明。如何使用内在函数来将两个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数组可以被当作unsigned,所以你可以使用[PMADDUBSW](http://www.felixcloutier.com/x86/PMADDUBSW.html)。水平减少不需要置换,只需提取并将其转换为128.参见[这个答案](http://stackoverflow.com/questions/6996764/fastest-way-to-do-horizo​​ntal-float-vector-sum -on-x86)为可能最佳的水平和模式,可能会节省一些代码字节与您的模式。 –