背景:我開發了一個用C/C++編寫的計算密集型工具,必須能夠在各種不同的x86_64處理器上運行。爲了加快float和integer的計算速度,代碼中包含了很多SSE *內在函數,並針對不同的CPU SSE功能量身定製了不同的路徑。 (由於CPU標誌在程序開始時被檢測到並用於設置布爾值,因此我假設對於量身定製的代碼塊的分支預測將非常有效地工作)。在SSE內部函數中使用'錯誤'指令的gcc(6.1.0)
爲簡單起見,我認爲只有SSE2到SSE4.2需要考慮。
爲了訪問4.2路徑的SSE4.2 intrinsics,我需要使用gcc的-msse4.2選項。
問題 我遇到的問題是,至少在6.1.0,GCC去,並實現了SSE2內在的,mm_cvtsi32_si128,與SSE4.2指令,pinsrd。
如果我通過使用-msse2來限制編譯,它將使用sse2指令movd,即。英特爾「內在指南」說它應該使用的那個。
這是兩個煩人的問題。
1)關鍵的問題是,當程序在4.2版本的CPU上運行時,程序現在會崩潰並出現非法指令。我無法控制使用何種硬件,因此可執行文件需要與舊機器兼容,但需要利用新硬件上的功能。
2)根據Intel intrinsics指南,pinsrd指令比它取代的mov慢得多。 (pinsrd更通用但不需要)。
有誰知道如何使GCC 只是使用內部函數指南說應該使用卻仍然允許通過SSE4 *在同一編譯單元訪問所有SSE2指令?
更新:我還應該注意,使用各種不同的編譯器在Linux,Windows和OSX下編譯相同的代碼,所以如果可能的話,寧願避免或至少具有最少的編譯器特定擴展。
Update2 :(感謝@PeterCordes)似乎如果啓用了優化,gcc將在適當情況下恢復爲使用來自pinsrd的movd。
嘗試看着嘩嘩的代碼生成一段時間 - 這將完全重新編寫SIMD內在的某些序列與它認爲是(而且經常是)一個「更好」的指令序列。 –
你可以在gcc選擇PINSRD的地方顯示代碼嗎?你確定它沒有用它來優化掉下面的'_mm_unpacklo_epi32'什麼的? (PINSRD解碼爲與MOVD + PUNPCKLDQ相同的端口,但佔用較少的代碼字節,所以當您告訴編譯器允許使用SSE4.2指令時,這是個不錯的選擇)。 –
無論如何,處理這個問題的常用方法是將您的SSE4函數放在與您的基準x86-64函數不同的獨立翻譯單元中。如果其中任何一個從其他翻譯單元調用小函數,鏈接時優化可能會有所幫助。 –