2016-11-16 49 views
0

我试图使用Intel Intrinsics在float阵列上快速执行操作。这些行动本身似乎运作良好;但是,当我尝试将操作的结果转换为标准C变量时,我得到一个SEGFAULT。如果我将下面的指示线注释掉,程序就会运行。如果我保存指定行的结果,但不以任何方式操纵它,程序运行正常。只有当我试图(以任何方式)与_mm_cvtss_f32(C)的结果进行交互时,我的程序才会崩溃。有任何想法吗?使用生成的浮点数时出现SSE SIMD分段错误

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; 
} 
+4

你确定你的程序实际上是在你引用的指令上崩溃的,或者是编译器只是优化了剩余的循环,如果你删除'_mm_cvtss_f32()'行(它没有任何其他可见的副作用) ?由于使用对齐的加载指令,因此潜在的故障原因可能是“a”和“b”阵列的不正确对齐。你确定它们是16字节对齐的吗?在当代英特尔硬件上,16字节对齐和不对齐负载之间的性能差别非常小(“movaps”的指令编码比“movups”短,但就是这一点)。 –

+1

谢谢你,我把'load'改成了'loadu',它现在好像工作了! – Simon

+1

@JasonR:它们的编码长度相同。 http://www.felixcloutier.com/x86/MOVAPS.html与http://www.felixcloutier.com/x86/MOVUPS.html。如果您比较反汇编,其中一个是否有REX前缀或不同的寻址模式?无论如何,当数据在运行时对齐时,它们的表现完全相同,但当L1高速缓存读取带宽是瓶颈时,对齐的负载具有优势。确保您的数据在价格低廉时保持​​一致是个不错的主意。 –

回答

0

你确定你的程序崩溃其实在你提到的指令,或者是编译器只是优化循环的其余部分路程,如果你删除_mm_cvtss_f32()行(它不具有任何其他可见侧效果)?由于您使用的是对齐的加载指令,潜在的故障原因将是a和b阵列的不正确对齐。你确定它们是16字节对齐的吗?在当代英特尔硬件上,16字节对齐和未对齐的负载之间几乎没有性能差异(请参阅上面关于该问题讨论的问题的评论)。

我在我的原始评论中提到movaps的编码比movups短。 这是不正确的。我在想,而不是movapsmovapd,它们进行相同的内存传输,只是将它们分别标记为单精度和双精度数据。在实践中,他们做同样的事情,但movaps有一个较短的编码。