2013-07-12 60 views
1

我一直在調試一些SSE優化的向量代碼,並注意到一些奇怪的行爲。公平的說,代碼風格非常糟糕,但編譯器對我來說似乎仍然是錯誤的。這裏是有問題的功能:Visual C++逗號運算符和sse intrinsics

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

混合內部函數和逗號是一個非常糟糕的主意 - 看起來您碰到編譯器邊緣案例的可能性很大。由於逗號似乎沒有做任何事情,爲什麼不把它們放在不同的線路上,看看你是否得到了預期的行爲? –

+0

Microsoft Connect上的錯誤793948,如果任何人感覺就像投票。 – Tom

+0

@MichaelDorgan - 是的,這就是我所做的,但是想在提交針對編譯器的錯誤之前向其他人詢問行爲是否真的不正確。 – Tom

回答

2

使用Microsoft Visual Studio 2008,2010和2012構建此代碼顯示它們都消除了逗號運算符的左操作數。只有啓用優化時纔會發生這種情況。當此代碼使用gcc 4.8.1構建時,即使使用完全優化,逗號運算符的左操作數也不會被消除。

C99規範規定:「逗號運算符的左操作數評估爲空表達式;評估後有一個序列點,然後評估右操作數」。

在我看來,Microsoft優化器是不正確的刪除此代碼。這是因爲語言規範說兩個操作數都被評估。逗號運算符的兩個操作數之間的唯一區別是它們的評估順序,以及哪個運算符爲逗號運算符提供了結果。在這種情況下,結果是無效的。

解決方法:用分號替換逗號。

+0

同意,+1。 VC在這個分數上肯定是錯誤的。它不會是規範中唯一不正確的東西。 – EJP