[英]Choose assembly implementation to use based on supported instructions
我正在開發一個C庫,它編譯/鏈接到.a
文件,用戶可以靜態鏈接到他們的代碼。 庫的性能非常重要,因此我在x86-64匯編中編寫性能關鍵的例程來優化性能。
對於某些例程,如果使用BMI2指令,我可以獲得明顯更好的性能,而不是堅持使用“標准”x86-64指令集。 麻煩的是,BMI2最近剛推出,我的一些用戶使用不支持這些指令的處理器。
所以,我寫了兩次優化例程,一次使用BMI2指令,一次不使用它們。 在我目前的設置中,我將分發兩個版本的.a
文件:一個需要支持BMI2指令的“快速”版本,以及一個不需要支持BMI2指令的“慢”版本。
我問是否有辦法通過分發單個.a
文件來簡化這一過程,該文件將根據最終應用程序運行的CPU是否支持BMI2指令動態選擇正確的實現。
與StackOverflow上的類似問題不同,這里有兩個特點:
if
語句也可能很重要。 我到目前為止提出的最快解決方案是執行以下操作:
cpuid
指令檢查CPU是否支持BMI2指令。 true
或false
。 我對這種方法不滿意,因為它有兩個缺點:
cpuid
並在程序開頭設置一個全局變量,因為我正在分發一個.a
文件並且無法控制最終二進制文件中的main
函數。 如果它提供了更好的解決方案,我很高興在這里使用C ++,只要最終的庫仍然可以與C程序鏈接和調用。 有沒有比我上面詳述的更有效的解決方案?
x264使用init函數(在調用其他任何東西之前需要調用庫的用戶,或類似的東西)來根據CPUID結果設置函數指針的結構。 包括考慮到pshufb
在一些支持它的早期CPU上pshufb
緩慢。
如果你的功能依賴於pdep
/ pext
,你可能想要檢測AMD與英特爾,因為AMD的pdep
/ pext
非常慢,並且可能不值得在Ryzen上使用,即使它可用。 (有關說明表,請參閱https://agner.org/optimize/ 。)
函數指針的開銷相當低,與調用共享庫或DLL中的函數大致相同。 call [rel funcptr]
而不是call func
。 (在編譯器生成的asm中調用您的函數)。
CPU依賴代碼:如何避免函數指針? 在C中展示了一個非常簡單的例子,並且正在尋找避免它的方法。 通過動態鏈接,您可以在動態鏈接時進行CPU檢測,因此動態鏈接間接也成為您的CPU調度間接(就像glibc選擇優化的memcpy
實現一樣)。
但是對於.a
靜態鏈接,只需創建靜態初始化為基線版本的函數指針,並且您的CPU初始化函數(希望在任何函數指針被解除引用之前運行)將其重寫為指向最佳版本的當前的CPU。
如果您使用的是gcc,則可以讓編譯器自動實現所有樣板代碼。 關於函數多版本化的gcc手冊頁
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.