[英]specify simd level of a function that compiler can use
我編寫了一些代碼並使用帶有本機架構選項的 gcc 編譯它。
通常,我可以使用此代碼並在沒有 AVX2(只有 AVX)的舊計算機上運行它,並且它運行良好。 然而,似乎編譯器實際上是在發出 AVX2 指令(終於!),而不是我需要自己包含 SIMD 內在函數。
我想修改程序,以便支持兩種途徑(AVX2 和非 AVX2)。 換句話說,我想要以下偽代碼。
if (AVX2){
callAVX2Version();
}else if (AVX){
callAVXVersion();
}else{
callSSEVersion();
}
void callAVX2Version(){
#pragma gcc -mavx2
}
void callAVXVersion(){
#pragma gcc -mavx
}
我知道如何做運行時檢測部分,我的問題是是否可以做功能特定的 SIMD 選擇部分。
gcc 目標屬性可以像這樣立即使用
[[gnu::target("avx")]]
void foo(){}
[[gnu::target("default")]]
void foo(){}
[[gnu::target("arch=sandybridge")]]
void foo(){}
然后電話變成
foo();
此選項不需要以不同的方式命名函數。 例如,如果您查看Godbolt ,您會看到它為您創建了 @gnu_indirect_function。 首先將其設置為 .resolver 函數。 它讀取 __cpu_model 以找出可以使用的內容並將間接函數設置為該指針,因此任何后續調用都將是一個簡單的間接函數。 簡單是不是。 但是您可能需要更接近原始代碼庫,因此還有其他方法
如果您確實需要像原始示例中那樣的功能切換。 可以使用以下內容。 它使用了措辭優美的 buildtins,因此很明顯您正在切換架構
[[gnu::target("avx")]]
int foo_avx(){ return 1;}
[[gnu::target("default")]]
int foo(){return 0;}
[[gnu::target("arch=sandybridge")]]
int foo_sandy(){return 2;}
int main ()
{
if (__builtin_cpu_is("sandybridge"))
return foo_sandy();
else if (__builtin_cpu_supports("avx"))
return foo_avx();
else
return foo();
}
由於對其他人或平台問題更加冗長的原因,間接函數可能不受支持的用例。 下面是一種與第一個選項相同的方法,但都在 C++ 代碼中。 使用靜態局部函數指針。 這意味着您可以根據自己的喜好或在不支持內置的情況下為目標排序優先級。 你可以提供你自己的。
auto foo()
{
using T = decltype(foo_default);
static T* pointer = nullptr;
//static int (*pointer)() = nullptr;
if (pointer == nullptr)
{
if (__builtin_cpu_is("sandybridge"))
pointer = &foo_sandy;
else if (__builtin_cpu_supports("avx"))
pointer = &foo_avx;
else
pointer = &foo_default;
}
return pointer();
};
以下關於Godbolt 的模板化示例使用template<class ... Ts>
來處理函數的重載,這意味着如果您定義了callXXXVersion(int)
系列,那么 foo(int) 將很樂意為您調用重載版本。 只要你定義了整個家庭。
這是我的解決方案。 我可以在支持 AVX2 的情況下進行編譯,並且仍然可以在我的 Ivy Bridge 處理器(僅限 AVX)上正常運行。
功能是:
__attribute__((target("arch=haswell")))
void fir_avx2_std(STD_DEF){
STD_FIR;
}
__attribute__((target("arch=sandybridge")))
void fir_avx_std(STD_DEF){
STD_FIR;
}
//Use default - no arch specified
void fir_sse_std(STD_DEF){
STD_FIR;
}
電話是:
if (s.HW_AVX2 && s.OS_AVX){
fir_avx2_std(STD_Call);
}else if(s.HW_AVX && s.OS_AVX){
fir_avx_std(STD_Call);
}else{
fir_sse_std(STD_Call);
}
s
是根據我在網上找到的一些代碼填充的結構( https://github.com/Mysticial/FeatureDetector )
STD_FIR
是一個帶有實際代碼的宏,它針對每個架構進行了不同的優化。
我正在編譯: -std=c11 -ffast-math -O3
我最初也有-march=haswell
,但這導致了問題。
請注意,我不完全確定這是否是最好的目標故障......另外,我嘗試讓target_clones
工作,但我收到一個關於需要ifunc
的錯誤(我認為 gcc 為我做了這ifunc
......)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.