AVX2 的 gcc 目标禁用 SSE 指令集
gcc target for AVX2 disabling SSE instruction set
我们有一个要用 AVX2 编译的翻译单元(只有那个):
它预先告诉 GCC,文件中的第一行:
#pragma GCC target "arch=core-avx2,tune=core-avx2"
这曾经适用于 GCC 4.8 和 4.9,但从 6 开始(也尝试过 7 和 8)我们收到此警告(我们将其视为错误):
error: SSE instruction set disabled, using 387 arithmetics
第一个返回浮点数的函数。我试过像这样启用 SSE 4.2(以及 avx 和 avx2)
#pragma GCC target "sse4.2,arch=core-avx2,tune=core-avx2"
但这还不够,错误仍然存在。
编辑:
相关编译器标志,我们针对大多数内容使用 AVX:
-mfpmath=sse,387 -march=corei7-avx -mtune=corei7-avx
EDIT2:最小样本:
#pragma GCC target "arch=core-avx2,tune=core-avx2"
#include <immintrin.h>
#include <math.h>
static inline float
lg1pf( float x ) {
return log1pf(x)*1.44269504088896338700465f;
}
int main()
{
log1pf(2.0f);
}
这样编译:
gcc -o test test.c -O2 -Wall -Werror -pedantic -std=c99 -mfpmath=sse,387 -march=corei7-avx -mtune=corei7-avx
In file included from /home/xxx/gcc-7.1.0/lib/gcc/x86_64-pc-linux-gnu/7.1.0/include/immintrin.h:45:0,
from test.c:3:
/home/xxx/gcc-7.1.0/lib/gcc/x86_64-pc-linux-gnu/7.1.0/include/avx512fintrin.h: In function ‘_mm_add_round_sd’:
/home/xxx/gcc-7.1.0/lib/gcc/x86_64-pc-linux-gnu/7.1.0/include/avx512fintrin.h:1412:1: error: SSE register return with SSE disabled
{
^
GCC 详细信息(虽然我没有用于编译它的标志)
gcc --版本
海合会 (海湾合作委员会) 7.1.0
版权所有 (C) 2017 Free Software Foundation, Inc.
这是免费软件;有关复制条件,请参阅来源。没有
保修单;甚至不是针对特定用途的适销性或适用性。
可能的解决方案
#pragma GCC target "avx2"
无需对代码进行其他更改即可为我工作。
将属性应用于单个函数也不起作用:
相关问题:
__attribute__((__target__("arch=broadwell"))) // does not compile
__m256 use_avx(__m256 a) { return _mm256_add_ps(a,a); }
__attribute__((__target__("avx2,arch=broadwell"))) // does not compile
__m256 use_avx(__m256 a) { return _mm256_add_ps(a,a); }
__attribute__((__target__("avx2"))) // compiles
__m256 use_avx(__m256 a) { return _mm256_add_ps(a,a); }
这看起来像是一个错误。 #pragma GCC target
在 #include <immintrin.h>
之前以某种方式打破了 header,IDK 为什么。即使在命令行上使用 -march=haswell
启用了 AVX2,#pragma 似乎也会破坏在那之后定义的任何内部函数的内联。
您可以在 header 之后使用 #pragma
,但随后使用未在命令行上启用的内部函数会失败。
即使像 #pragma GCC target "arch=haswell"
这样更现代的目标名称也会导致错误,所以一般来说并不是像 corei7-avx
这样的旧模糊目标名称被破坏了。他们仍然在命令行上工作。如果要为整个文件启用某些功能,标准方法是使用编译器选项和 not pragmas.
GCC 确实声称在 per-function 的基础上使用 pragma 或 __attribute__
支持目标选项。 https://gcc.gnu.org/onlinedocs/gcc/Function-Specific-Option-Pragmas.html.
这是我玩这个的最大程度 (Godbolt compiler explorer with gcc8.1)。 Clang 不受影响,因为它忽略了 #pragma GCC target
。 (所以这意味着 #pragma
不是很便携;您可能希望您的代码适用于任何 GNU C 编译器,而不仅仅是 gcc 本身。)
// breaks gcc when before immintrin.h
// #pragma GCC target "arch=haswell"
#include <immintrin.h>
#include <math.h>
//#pragma GCC target "arch=core-avx2,tune=core-avx2"
#pragma GCC target "arch=haswell"
//static inline
float
lg1pf( float x ) {
return log1pf(x)*1.44269504088896338700465f;
}
// can accept / return wide vectors
__m128 nop(__m128 a) { return a; }
__m256 require_avx(__m256 a) { return a; }
// but error on using intrinsics if #include happened without target options
//__m256 use_avx(__m256 a) { return _mm256_add_ps(a,a); }
// this works, though, because AVX is enabled at this point
// presumably so would __builtin_ia32_whatever
// Without `arch=haswell`, this breaks, so we know the pragma "worked"
__m256 use_native_vec(__m256 a) { return a+a; }
我们有一个要用 AVX2 编译的翻译单元(只有那个): 它预先告诉 GCC,文件中的第一行:
#pragma GCC target "arch=core-avx2,tune=core-avx2"
这曾经适用于 GCC 4.8 和 4.9,但从 6 开始(也尝试过 7 和 8)我们收到此警告(我们将其视为错误):
error: SSE instruction set disabled, using 387 arithmetics
第一个返回浮点数的函数。我试过像这样启用 SSE 4.2(以及 avx 和 avx2)
#pragma GCC target "sse4.2,arch=core-avx2,tune=core-avx2"
但这还不够,错误仍然存在。
编辑:
相关编译器标志,我们针对大多数内容使用 AVX:
-mfpmath=sse,387 -march=corei7-avx -mtune=corei7-avx
EDIT2:最小样本:
#pragma GCC target "arch=core-avx2,tune=core-avx2"
#include <immintrin.h>
#include <math.h>
static inline float
lg1pf( float x ) {
return log1pf(x)*1.44269504088896338700465f;
}
int main()
{
log1pf(2.0f);
}
这样编译:
gcc -o test test.c -O2 -Wall -Werror -pedantic -std=c99 -mfpmath=sse,387 -march=corei7-avx -mtune=corei7-avx
In file included from /home/xxx/gcc-7.1.0/lib/gcc/x86_64-pc-linux-gnu/7.1.0/include/immintrin.h:45:0,
from test.c:3:
/home/xxx/gcc-7.1.0/lib/gcc/x86_64-pc-linux-gnu/7.1.0/include/avx512fintrin.h: In function ‘_mm_add_round_sd’:
/home/xxx/gcc-7.1.0/lib/gcc/x86_64-pc-linux-gnu/7.1.0/include/avx512fintrin.h:1412:1: error: SSE register return with SSE disabled
{
^
GCC 详细信息(虽然我没有用于编译它的标志) gcc --版本 海合会 (海湾合作委员会) 7.1.0 版权所有 (C) 2017 Free Software Foundation, Inc. 这是免费软件;有关复制条件,请参阅来源。没有 保修单;甚至不是针对特定用途的适销性或适用性。
可能的解决方案
#pragma GCC target "avx2"
无需对代码进行其他更改即可为我工作。 将属性应用于单个函数也不起作用:
相关问题:
__attribute__((__target__("arch=broadwell"))) // does not compile
__m256 use_avx(__m256 a) { return _mm256_add_ps(a,a); }
__attribute__((__target__("avx2,arch=broadwell"))) // does not compile
__m256 use_avx(__m256 a) { return _mm256_add_ps(a,a); }
__attribute__((__target__("avx2"))) // compiles
__m256 use_avx(__m256 a) { return _mm256_add_ps(a,a); }
这看起来像是一个错误。 #pragma GCC target
在 #include <immintrin.h>
之前以某种方式打破了 header,IDK 为什么。即使在命令行上使用 -march=haswell
启用了 AVX2,#pragma 似乎也会破坏在那之后定义的任何内部函数的内联。
您可以在 header 之后使用 #pragma
,但随后使用未在命令行上启用的内部函数会失败。
即使像 #pragma GCC target "arch=haswell"
这样更现代的目标名称也会导致错误,所以一般来说并不是像 corei7-avx
这样的旧模糊目标名称被破坏了。他们仍然在命令行上工作。如果要为整个文件启用某些功能,标准方法是使用编译器选项和 not pragmas.
GCC 确实声称在 per-function 的基础上使用 pragma 或 __attribute__
支持目标选项。 https://gcc.gnu.org/onlinedocs/gcc/Function-Specific-Option-Pragmas.html.
这是我玩这个的最大程度 (Godbolt compiler explorer with gcc8.1)。 Clang 不受影响,因为它忽略了 #pragma GCC target
。 (所以这意味着 #pragma
不是很便携;您可能希望您的代码适用于任何 GNU C 编译器,而不仅仅是 gcc 本身。)
// breaks gcc when before immintrin.h
// #pragma GCC target "arch=haswell"
#include <immintrin.h>
#include <math.h>
//#pragma GCC target "arch=core-avx2,tune=core-avx2"
#pragma GCC target "arch=haswell"
//static inline
float
lg1pf( float x ) {
return log1pf(x)*1.44269504088896338700465f;
}
// can accept / return wide vectors
__m128 nop(__m128 a) { return a; }
__m256 require_avx(__m256 a) { return a; }
// but error on using intrinsics if #include happened without target options
//__m256 use_avx(__m256 a) { return _mm256_add_ps(a,a); }
// this works, though, because AVX is enabled at this point
// presumably so would __builtin_ia32_whatever
// Without `arch=haswell`, this breaks, so we know the pragma "worked"
__m256 use_native_vec(__m256 a) { return a+a; }