SIMD / SSE:短点积和短最大值

时间:2015-02-09 10:43:08

标签: c++ x86 sse simd intrinsics

我正在尝试优化两个c风格阵列的点积,这些阵列包括小尺寸和短尺寸。

我已经阅读了几篇关于SIMD内在函数的文档以及许多关于使用此内在函数进行点积优化的博客文章/文章。

但是,我不明白使用此内在函数的短阵列上的点积如何能够给出正确的结果。在制作点积时,计算出的值可以(并且在我的情况下总是大于SHORT_MAX),因此是和。因此,我将它们存储在double类型的变量中。

据我所知,使用simd内在的点积,我们使用__m128i变量类型,并且操作返回__m128i。所以,我不明白为什么它不会“溢出”以及如何将结果转换为可以处理它的值类型?

感谢您的建议

2 个答案:

答案 0 :(得分:2)

根据数据值的范围,您可以使用诸如_mm_madd_epi16之类的内在函数,它对16位数据执行乘法/加法并生成32位项。然后,您需要定期将32位项累加到64位。您需要多长时间才能执行此操作取决于输入数据的范围,例如:如果它是12位灰度图像数据,那么在有可能发生溢出之前,你可以在每次迭代8个元素(即512个输入点)上进行64次迭代。然而,在最坏的情况下,如果输入数据使用完整的16位范围,则需要在每次迭代时(即每8个点)进行额外的64位累加。

答案 1 :(得分:0)

仅仅是为了记录,这里是我如何为2个int16数组大小36制作一个点积:

double dotprod(const int16_t* source, const int16_t* target, const int size){
#ifdef USE_SSE
    int res[4];
    __m128i* src = (__m128i *) source;
    __m128i* t = (__m128i *) target;
    __m128i s = _mm_madd_epi16(_mm_loadu_si128(src), mm_loadu_si128(t));
    ++src;
    ++t;
    s = _mm_add_epi32(s, _mm_madd_epi16(_mm_loadu_si128(src), _mm_loadu_si128(t)));
    ++src;
    ++t;
    s = _mm_add_epi32(s, _mm_madd_epi16(_mm_loadu_si128(src), _mm_loadu_si128(t)));
    ++src;
    ++t;
    s = _mm_add_epi32(s, _mm_madd_epi16(_mm_loadu_si128(src), _mm_loadu_si128(t)));

    /* return the sum of the four 32-bit sub sums */
    _mm_storeu_si128((__m128i*)&res, s);
    return res[0] + res[1] + res[2] + res[3] + source[32] * target[32] + source[33] * target[33] + source[34] * target[34] + source[35] * target[35];
#elif USE_AVX
    int res[8];
    __m256i* src = (__m256i *) source;
    __m256i* t = (__m256i *) target;
    __m256i s = _mm256_madd_epi16(_mm256_loadu_si256(src), _mm256_loadu_si256(t));
    ++src;
    ++t;
    s = _mm256_add_epi32(s, _mm256_madd_epi16(_mm256_loadu_si256(src), _mm256_loadu_si256(t)));

    /* return the sum of the 8 32-bit sub sums */
    _mm256_storeu_si256((__m256i*)&res, s);
    return res[0] + res[1] + res[2] + res[3] + res[4] + res[5] + res[6] + res[7] + source[32] * target[32] + source[33] * target[33] + source[34] * target[34] + source[35] * target[35];
#else
    return source[0] * target[0] + source[1] * target[1] + source[2] * target[2] + source[3] * target[3] + source[4] * target[4]+ source[5] * target[5] + source[6] * target[6] + source[7] * target[7] + source[8] * target[8] + source[9] * target[9] + source[10] * target[10] + source[11] * target[11] + source[12] * target[12] + source[13] * target[13] + source[14] * target[14] + source[15] * target[15] + source[16] * target[16] + source[17] * target[17] + source[18] * target[18] + source[19] * target[19] + source[20] * target[20] + source[21] * target[21] + source[22] * target[22] + source[23] * target[23] + source[24] * target[24] + source[25] * target[25] + source[26] * target[26] + source[27] * target[27] + source[28] * target[28] + source[29] * target[29] + source[30] * target[30] + source[31] * target[31] + source[32] * target[32] + source[33] * target[33] + source[34] * target[34] + source[35] * target[35];
#endif
}