使用结果浮点数时的 SSE SIMD 分段错误

Posted

技术标签:

【中文标题】使用结果浮点数时的 SSE SIMD 分段错误【英文标题】:SSE SIMD Segmentation Fault when using resulting float 【发布时间】:2016-11-16 19:45:53 【问题描述】:

我正在尝试使用 Intel Intrinsics 在float 数组上快速执行操作。操作本身似乎运行良好。但是,当我尝试将操作结果放入标准 C 变量时,我得到一个 SEGFAULT。如果我将下面指示的行注释掉,程序就会运行。如果我保存了指示行的结果,但不以任何方式对其进行操作,则程序运行良好。只有当我尝试(以任何方式)与_mm_cvtss_f32(C) 的结果交互时,我的程序才会崩溃。有什么想法吗?

float proc(float *a, float *b, int n, int c, int width) 
    // Operation: SUM: (A - B) ^ 2
    __m128 A, B, C;
    float total = 0;
    for (int d = 0, k = 0; k < c; d += width, k++) 
        for (int i = 0; i < n / 4 * 4; i += 4) 
            A = _mm_load_ps(&a[i + d]);
            B = _mm_load_ps(&b[i + d]);
            C = _mm_sub_ps(A, B);
            C = _mm_mul_ps(C, C);
            C = _mm_hadd_ps(C, C);
            C = _mm_hadd_ps(C, C);
            total += _mm_cvtss_f32(C); // SEGFAULT HERE
        
        for (int i = n / 4 * 4; i < n; i++) 
            int diff = a[i + d] - b[i + d];
            total += diff * diff;
        
    
    return total;

【问题讨论】:

您确定您的程序实际上在您引用的指令处崩溃,或者如果您删除 _mm_cvtss_f32() 行,编译器是否只是优化循环的其余部分(它没有任何其他可见的副作用)?潜在的失败原因是 ab 数组的不正确对齐,因为您使用的是对齐的加载指令。你确定它们是 16 字节对齐的吗?在当代 Intel 硬件上,16 字节对齐和未对齐加载之间的性能差异非常小(movaps 的指令编码比 movups 短,但仅此而已)。 谢谢,我将load 更改为loadu,现在似乎可以使用了! @JasonR:它们的编码长度相同。 felixcloutier.com/x86/MOVAPS.html 与 felixcloutier.com/x86/MOVUPS.html。如果您要比较反汇编,其中一个是否具有 REX 前缀或不同的寻址模式?无论如何,当数据在运行时对齐时,它们的性能相同,但是当 L1 缓存读取带宽成为瓶颈时,对齐负载具有优势。确保您的数据在廉价时保持一致是个好主意。 另外,@Simon:将 HADD 指令从循环中取出,并在最后进行水平求和。使用_mm_add_ps 将结果向量添加到向量累加器中。 (最好使用多个向量累加器展开以隐藏添加到累加器的延迟,因此它不会成为循环携带依赖链延迟的瓶颈。自动向量化在这里可能会很好,尤其是如果你告诉编译器指针对齐。) @PeterCordes:我绝对尊重您广泛的 x86 专业知识。我没有意识到现在对齐的负载还有任何剩余的优势。您对上面指出的 L1-cache-read-bandwidth 问题有参考吗? 【参考方案1】:

您确定您的程序实际上在您引用的指令处崩溃,或者如果您删除 _mm_cvtss_f32() 行(它没有任何其他可见的副作用),编译器是否只是优化了循环的其余部分?潜在的故障原因可能是 a 和 b 数组的不正确对齐,因为您使用的是对齐的加载指令。你确定它们是 16 字节对齐的吗?在当代 Intel 硬件上,16 字节对齐负载和非对齐负载之间的性能差异非常小(有关该问题的讨论,请参阅上述问题的 cmets)。

我在原始评论中提到movaps 的编码比movups 短。 这是不正确的。 我想的是 movapsmovapd 进行相同的内存传输,只是它们分别被标记为用于单精度和双精度数据.实际上,它们做同样的事情,但movaps 的编码更短。

【讨论】:

以上是关于使用结果浮点数时的 SSE SIMD 分段错误的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 SIMD 比较两个字符向量并将结果存储为浮点数?

SIMD,SSE,AVX - 掩码 8 浮动无符号字符? [复制]

在 X87 和 SSE FPU 中用户定义的点之后截断浮点数和双精度数

如何将无符号整数加载到 SIMD 中

使用内在函数将双 SSE2/AVX/AVX512 存储为浮点数的最佳方法

使用 SSE 将 4 个浮点数乘以 4 个浮点数的最有效方法是啥?