閱讀this interesting article on the results of intrinsic-guided optimization of SSE code in different C++ compilers我決定自己做一個測試,特別是因爲這個帖子已經過了幾年了。我使用了MSVC,它在帖子作者的測試中做得很差(雖然在VS 2010版本中),並決定堅持一個非常基本的場景:將一些值打包到XMM寄存器中,並進行簡單操作,如添加。在文章中,_mm_set_ps翻譯成標舉的一個奇怪的序列,並解壓縮指令,讓我們看看:如何改進編譯器對我的SSE內部函數的處理?
int _tmain(int argc, _TCHAR* argv[])
{
__m128 foo = _mm_set_ps(1.0f, 2.0f, 3.0f, 4.0f);
__m128 bar = _mm_set_ps(5.0f, 6.0f, 7.0f, 8.0f);
__m128 ret = _mm_add_ps(foo, bar);
// need to do something so vars won't be optimized out in Release
float *f = (float *)(&ret);
for (int i = 0; i < 4; i++)
{
cout << "f[" << i << "] = " << f[i] << endl;
}
}
接下來,我編譯和運行這個調試器裏面,看着拆卸:
調試:
__m128 foo = _mm_set_ps(1.0f,2.0f,3.0f,4.0f);
00B814F0 MOVAPS XMM0,xmmword PTR DS:[0B87840h]
00B814F7 MOVAPS xmmword PTR [EBP-190H],XMM0
00B814FE MOVAPS XMM0,xmmword PTR [EBP-190H]
00B81505 MOVAPS xmmword的ptr [富],XMM0
__m128 bar = _mm_set_ps(5.0f,6.0f,7.0f,8.0f);
00B81509 MOVAPS XMM0,xmmword PTR DS:[0B87850h]
00B81510 MOVAPS xmmword PTR [EBP-170H],XMM0
00B81517 MOVAPS XMM0,xmmword PTR [EBP-170H]
00B8151E MOVAPS xmmword的ptr [巴],XMM0
__m128 ret = _mm_add_ps(foo,bar);
00B81522 MOVAPS XMM0,xmmword的ptr [巴]
00B81526 MOVAPS xmm1中,xmmword的ptr [富]
00B8152A ADDPS xmm1中,XMM0
00B8152D MOVAPS xmmword PTR [EBP-150H],xmm1中
00B81534 MOVAPS XMM0,xmmword PTR [EBP-150H]
00B8153B MOVAPS xmmword的ptr [RET],XMM0
心亂如麻;爲什麼將xmmword放入__m128需要四個MOVAPS?首先,它將數據放入xmm0中(我認爲這是四個浮點值存儲在某處的文字,不知道如何查看它),然後將xmm0複製到某處由ebp指向的位置和一個偏移量,僅將其複製回來到xmm0(?),最後到應該存儲變量的位置。爲什麼這麼多工作?
發佈: 這一次,我期待編譯器可避免儲存xmmword在內存中的所有,只是把一個在XMM0,其他xmm1中,在內存中做一個ADDPS,把結果和用它做。相反,我得到:
__m128 foo = _mm_set_ps(1.0f,2.0f,3.0f,4.0f);
__m128 bar = _mm_set_ps(5.0f,6.0f,7.0f,8.0f);
__m128 ret = _mm_add_ps(foo,bar);
003E1009 MOVAPS XMM0,xmmword PTR DS:[3E2130h]
003E1010推ESI
003E1011 MOVAPS xmmword的ptr [ESP + 10H],XMM0
顯然,不需要ADDPS。我猜測編譯器注意到這兩個xmmwords是編譯時常量,所以它只是添加了它們,將結果作爲文字輸入到代碼中?奇怪的推動可能與隨後的for循環有關,因爲esi被用作循環計數器,據我所知。儘管如此,爲什麼不將數據段中的預先計算的文字放入xmm0,然後放入局部變量(esp + 10h),爲什麼不直接使用文字?總而言之,Debug版本比我預期的更愚蠢(或者我可能沒有收到什麼東西),而發佈版本卻意想不到。任何意見解釋這種行爲將不勝感激。謝謝。
編輯:的答案是很有啓發性,但我還是想知道如果有什麼我可以做些什麼來改善編譯器的輸出,這就是爲什麼我從詢問到的這種解釋改變的問題目前的形式。
例如,纔有可能以某種方式引導編譯器富和酒吧不存儲在內存中(因爲我不添加後需要他們),只需將它們裝入xmmN寄存器,並讓他們那裏?可能ret呢?引用文章的作者說,MSVC只是「按照它所告訴的那樣做」。任何方式來改善(讀:避免內存傳輸)代碼,而不明確寫一個__asm塊?謝謝。
一個非常好的解釋! – us2012 2013-02-14 14:33:53
謝謝@Hans,您是否也會好好處理Q上的編輯?謝謝。 – neuviemeporte 2013-02-14 15:18:43
要做任何事情來改善它都沒有意義。只需構建您的項目的發佈版本即可完成。在調試版本中打開優化器只會讓調試更加困難,調試版本的目的是讓它更容易*。如果你真的想,你可以幫助你瞭解它有多難。 – 2013-02-14 15:27:41