c - 总和字节的 SSE 代码。错误在哪里?

标签 c algorithm visual-studio-2005 sse

我编写了 SSE 代码来汇总字节值。 (VS2005.)

因为它足够简单,所以工作起来非常好(而且速度很快)。只有某些大小的数组会发生崩溃。而且它只在 Release模式下崩溃——在调试中永远不会。也许有人看到了“明显”的错误? 任何帮助表示赞赏。

__int64 Sum (const unsigned char* pData, const unsigned int& nLength)
{
    __int64 nSum (0);

    __m128i* pp = (__m128i*)pData;

    ATLASSERT( ( (DWORD)pp & 15 ) == 0 ); // pointer must point to address multiple of 16 (cache line)

    __m128i zero = _mm_setzero_si128(),
        a, b, c, d, tmp;

    unsigned int i (0);

    for ( ; i < nLength; i+=64) // 4-fach loop-unroll (x 16)
    {
        a = _mm_sad_epu8( *(pp++), zero);           
        b = _mm_sad_epu8( *(pp++), zero);  // It crashes here.
        c = _mm_sad_epu8( *(pp++), zero);
        d = _mm_sad_epu8( *(pp++), zero);

        // commenting the following line prevents the crash (???)
        tmp = _mm_add_epi64( _mm_add_epi64( _mm_add_epi64( a, b ), c ), d);

        a = _mm_srli_si128 ( tmp, 8 );

        nSum += _mm_cvtsi128_si32( a ) + _mm_cvtsi128_si32( tmp );
    }

    // ... the rest
    if (nLength % 64)
        for (i -= 64; i < nLength; i++)
            nSum += pData [i];

    return nSum;
}

函数是这样调用的:

unsigned int nLength = 3571653;  // One of the values that causes crash
unsigned char *pData = (unsigned char*) _aligned_malloc(nLength, 16);
Sum (pData,  nLength);

最佳答案

您的 for 循环需要定义如下:

for ( ; i < (nLength - 63); i+=64)

基本上假设您传入一个 nLength 为 120 的数组。您在第一次运行时没有问题。 i 现在等于 64。 i < 120 所以你再做一个循环。不幸的是,您在到达 128 之前就通过了数组的末尾,并且您进入了未定义的行为区域。这可能表现为会导致崩溃的访问冲突 (0xC0000005)。

现在以 nLength=128 为例,根据我建议的修改,它应该在优化循环中完美运行。第一个循环 i 很好并且 i = 64。 i 小于 65 所以执行另一个循环。 i 现在等于 128 并且循环退出。外循环也不运行,因为 i == nLength。工作完成:)

关于c - 总和字节的 SSE 代码。错误在哪里?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15510597/

相关文章:

algorithm - 匈牙利算法和多重因素

c - 如何解决 Visual Studio 2005 中的错误 C2664 _vswprintf_c_l 错误?

javascript - 查看 jQuery 源代码,如何在伪代码中实现此缓动功能?

c++ - 返回第 n 个斐波那契数的快速递归函数

c++ - autoexp.dat 不解析 union ?

visual-studio-2005 - Visual Studio ClickOnce 部署 - 证书过期

c - 前面的零被忽略

c - 如何将堆栈变量对齐到 16 字节边界

c - nftw 目录的总大小与 du 输出不同

c - 如何修复 C 中字符串数组的二分搜索