簡體   English   中英

gcc(6.1.0)在SSE內在函數中使用“錯誤”指令

[英]gcc (6.1.0) using 'wrong' instructions in SSE intrinsics

背景 :我開發了一種用C / C ++編寫的計算密集型工具,該工具必須能夠在各種不同的x86_64處理器上運行。 為了加快浮點數和整數的計算速度,該代碼包含大量SSE *內部函數,它們具有針對不同CPU SSE功能量身定制的不同路徑。 (由於在程序啟動時檢測到CPU標志並用於設置布爾值,因此我假設針對定制代碼塊的分支預測將非常有效地工作)。

為簡單起見,我假設只需要考慮SSE2到SSE4.2。

為了通過4.2路徑訪問SSE4.2內部函數,我需要使用gcc的-msse4.2選項。

這個問題我遇到的問題是,至少在6.1.0,GCC去並實現了SSE2內在的,mm_cvtsi32_si128,與SSE4.2指令,pinsrd。

如果我使用-msse2限制編譯,它將使用sse2指令movd,即。 英特爾“本機指南”說應該使用的一種。

這在兩個方面都很煩人。

1)關鍵問題是,當程序在pre4.2 CPU上運行時,該程序現在由於一條非法指令而崩潰。 我無法控制使用什么硬件,因此可執行文件需要與舊計算機兼容,但是需要利用可用的新硬件上的功能。

2)根據Intel內在函數指南,pinsrd指令比它所取代的mov慢很多。 (pinsrd更一般,但這不是必需的)。

有誰知道如何使gcc 僅僅使用內在性指南說的應該使用的指令,但仍然允許在同一編譯單元中通過SSE4 *訪問所有SSE2?

更新:我還應該注意,相同的代碼是使用各種不同的編譯器在Linux,Windows和OSX下編譯的,因此,如果可能的話,希望避免或至少具有最少的編譯器特定擴展。

Update2:(感謝@PeterCordes)似乎如果啟用了優化,則gcc將在適當的情況下恢復使用pindsrd中的movd。

如果在編譯步驟中將-msse4.2標志提供給gcc的命令行,則將假定整個翻譯單元最多可以自由使用SSE 4.2指令集。 這可能導致您描述的行為。 如果您需要使用SSE2和以下代碼的代碼,則需要使用-msse2 (如果要為x86_64進行構建,則-msse2不使用標志)。

我可以想到的一些選擇是:

  • 如果您可以輕松地在功能級別分解代碼,那么gcc的多版本功能可以提供幫助。 它需要一個相對較新的編譯器版本,但是它允許您執行以下操作(來自上面的鏈接):

      __attribute__ ((target ("default"))) int foo () { // The default version of foo. return 0; } __attribute__ ((target ("sse4.2"))) int foo () { // foo version for SSE4.2 return 1; } __attribute__ ((target ("arch=atom"))) int foo () { // foo version for the Intel ATOM processor return 2; } __attribute__ ((target ("arch=amdfam10"))) int foo () { // foo version for the AMD Family 0x10 processors. return 3; } int main () { int (*p)() = &foo; assert ((*p) () == foo ()); return 0; } 

    在此示例中,gcc將自動編譯不同版本的foo()並在運行時根據CPU的功能將其分發給適當的版本。

  • 您可以將不同的實現(SSE2,SSE4.2等)分解為不同的轉換單元,然后在運行時將其適當地分派到正確的實現。

  • 您可以將所有SIMD代碼放入共享庫中,並使用不同的編譯器標志多次構建共享庫。 然后,在運行時,您可以檢測CPU的功能並加載適當版本的共享庫。 這是諸如英特爾的數學內核庫之類庫所采用的方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM