c - 这种悲伤教导的奇怪行为的原因是什么?

标签 c gcc sse simd avx2

我已经实现了 program使用SSE2分别比较AVX2和SSE2的vpsadbw指令和psadbw。以下代码是SSE2程序:

#define MAX1 4096
#define MAX2 MAX1
#define MAX3 MAX1

#define NUM_LOOP 1000000000

double pTime = 0, mTime = 5; 

//global data for sequentila matrix operations
unsigned char a_char[MAX1][MAX2] __attribute__(( aligned(16)));
unsigned char b_char[MAX2][MAX3] __attribute__(( aligned(16)));
unsigned char c_char[MAX1][MAX3] __attribute__(( aligned(16)));
unsigned short int temp[8];


int main()
{
    int i, j, w=0, sad=0;
    struct timespec tStart, tEnd;
    double tTotal , tBest=10000;
    __m128i vec1, vec2, vecT, sad_total;
    sad_total= _mm_setzero_si128();

    do{
        clock_gettime(CLOCK_MONOTONIC,&tStart);

        for(i=0; i<MAX1; i++){
            for(j=0; j<MAX2; j+=16){

                vec1 = _mm_load_si128((__m128i *)&a_char[i][j]);
                vec2 = _mm_load_si128((__m128i *)&b_char[i][j]);
                vecT = _mm_sad_epu8( vec1 , vec2);
                sad_total = _mm_add_epi64(vecT, sad_total);

                }
            }
        _mm_store_si128((__m128i *)&temp[0], sad_total);
        sad=temp[0]+temp[2]+temp[4]+temp[6];    

        clock_gettime(CLOCK_MONOTONIC,&tEnd);
        tTotal = (tEnd.tv_sec - tStart.tv_sec);
        tTotal += (tEnd.tv_nsec - tStart.tv_nsec) / 1000000000.0;
        if(tTotal<tBest)
            tBest=tTotal;
        pTime += tTotal;

    } while(w++ < NUM_LOOP && pTime < mTime);
    printf(" The best time: %lf sec in %d repetition for %dX result is %d matrix\n",tBest,w, MAX1, sad);

    return 0;
}

我使用gccskylakeLinux mint 当我生成汇编代码时,内部循环包含一些不需要的移动操作,如下所示(对于 SSE2):

.L26:
    vmovdqa xmm1, XMMWORD PTR a_char[rcx+rax]
    vpsadbw xmm1, xmm1, XMMWORD PTR b_char[rcx+rax]
    add rax, 16
    vpaddq  xmm3, xmm1, XMMWORD PTR [rsp]
    cmp rax, 4096
    vmovaps XMMWORD PTR [rsp], xmm3
    jne .L26

由于 AVX2 生成此汇编代码:

.L26:
    vmovdqa ymm1, YMMWORD PTR a_char[rcx+rax]
    vpsadbw ymm1, ymm1, YMMWORD PTR b_char[rcx+rax]
    add rax, 32
    vpaddq  ymm2, ymm2, ymm1
    cmp rax, 4096
    jne .L26

我不知道那两条明显违反性能的移动指令的原因。

最佳答案

原因是这样的:

_mm_store_si128((__m128i *)&temp[0], sad_total);

Clang 不介意并且无论如何都能编写出漂亮的代码,但 GCC 不喜欢它(也许是失败的启发式方法?)

将其替换为不会触发“这应该始终在堆栈上”启发式的内容后,GCC 会生成更好的代码,例如:(未测试)

    __m128i sad_total = _mm_setzero_si128();
    for(i = 0; i < MAX1; i++) {
        for(j = 0; j < MAX2; j += 16) {
            __m128i vec1 = _mm_load_si128((__m128i *)&a_char[i][j]);
            __m128i vec2 = _mm_load_si128((__m128i *)&b_char[i][j]);
            __m128i vecT = _mm_sad_epu8( vec1 , vec2);
            sad_total = _mm_add_epi64(sad_total, vecT);
        }
    }
    __m128i hsum = _mm_add_epi64(sad_total, _mm_bsrli_si128(sad_total, 8));
    sad = _mm_cvtsi128_si32(hsum);

内部循环现在看起来像

.L2:
    vmovdqa xmm1, XMMWORD PTR a_char[rdx+rax]
    vpsadbw xmm1, xmm1, XMMWORD PTR b_char[rdx+rax]
    add     rax, 16
    vpaddq  xmm2, xmm1, xmm2
    cmp     rax, 4096
    jne     .L2

关于c - 这种悲伤教导的奇怪行为的原因是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42055382/

相关文章:

C - 我使用什么选项来生成列表文件?

c - insmod : ERROR: Could not insert module : No such device

c - 代码中二进制/十六进制的无法解释的转换

python-3.x - 尝试使用 pip 安装 mysqlclient 包时编译错误

c - Intel 负载固有问题

java - JNI 什么时候需要复制原始类型的数组?

c - 分配的内存地址冲突

c - "safe"替代 "unsafe"C/C++ 标准库函数的 Mac 解决方案?

visual-studio-2010 - gcc 中的 error() 函数。它有什么作用以及它是否存在于 Visual Studio 中?

c - 使用 SSE (x*x*x) 的乘法