gpt4 book ai didi

c - 指定编译器可以使用的函数的 simd 级别

转载 作者:太空宇宙 更新时间:2023-11-04 03:11:21 25 4
gpt4 key购买 nike

我编写了一些代码并使用带有本地架构选项的 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 target 属性可以像这样随意使用

[[gnu::target("avx")]]
void foo(){}

[[gnu::target("default")]]
void foo(){}

[[gnu::target("arch=sandybridge")]]
void foo(){}

调用就变成了

foo();

此选项消除了以不同方式命名函数的需要。如果你 checkout 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) 会很乐意为您调用重载版本。只要你定义了整个家庭。

关于c - 指定编译器可以使用的函数的 simd 级别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56007974/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com