1

我一直在调试一些 SSE 优化的矢量代码,并注意到一些奇怪的行为。公平地说,代码风格很糟糕,但编译器所做的对我来说仍然是错误的。这是有问题的功能:

inline void daxpy(int n, double alph, const double* x, int incx, double* y, int incy) {
    __m128d sse_alph = _mm_load1_pd(&alph);
    while (n >= 4) {
        n -= 4;
        __m128d y1 = _mm_load_pd(y+n), y2 = _mm_load_pd(y+n+2);
        __m128d x1 = _mm_load_pd(x+n), x2 = _mm_load_pd(x+n+2);
        y1 = _mm_add_pd(y1, _mm_mul_pd(x1, sse_alph));
        y2 = _mm_add_pd(y2, _mm_mul_pd(x2, sse_alph));
        _mm_store_pd(y+n, y1), _mm_store_pd(y+n+2, y2);
    }
}

函数是数组y = y + alph * x。我们保证两个数组都具有相同的长度,n即 4 的倍数,并且 x 和 y 在 16 字节边界上对齐(为了清楚起见,我省略了相关的断言)。

循环的最后一行是用逗号运算符编写的,因此它看起来像两条加载线。问题是第一次_mm_store_pd调用没有被执行。那不是错了吗?我猜编译器可能已经决定只需要第二次调用来评估表达式,但内部函数似乎很明显有副作用。

我误解了这里发生了什么吗?我意识到使用像这样的逗号运算符是很糟糕的风格 - 我的问题是编译器是否错误。有问题的编译器是 Visual C++ 2010 SP 1。

4

1 回答 1

2

使用 Microsoft Visual Studio 2008、2010 和 2012 构建此代码表明它们都消除了逗号运算符的左操作数。仅当启用优化时才会发生这种情况。当使用 gcc 4.8.1 构建此代码时,即使使用完全优化,逗号运算符的左操作数也不会被消除。

C99 规范规定,“逗号运算符的左操作数被评估为 void 表达式;在其评估之后有一个序列点。然后评估右操作数”。

在我看来,微软优化器删除此代码是不正确的。这是因为语言规范说两个操作数都被评估。逗号运算符的两个操作数之间的唯一区别是它们的求值顺序以及哪一个为逗号运算符提供结果。在这种情况下,结果无效。

解决方法:用分号替换逗号。

于 2013-07-14T00:18:19.497 回答