Ral*_*alf 5 c gcc simd avx avx2
我有以下问题(g ++(Ubuntu 4.8.4-2ubuntu1~14.04)4.8.4):
当我_mm256_slli_si256()直接使用时,例如:
__m256i x = _mm256_set1_epi8(0xff);
x = _mm256_slli_si256(x, 3);
Run Code Online (Sandbox Code Playgroud)
代码编译没有问题(g++ -Wall -march=native -O3 -o shifttest shifttest.C).
但是,如果我将它包装成一个函数
__m256i doit(__m256i x, const int imm)
{
return _mm256_slli_si256(x, imm);
}
Run Code Online (Sandbox Code Playgroud)
编译器抱怨说
/usr/lib/gcc/x86_64-linux-gnu/4.8/include/avx2intrin.h: In function '__m256i doit(__m256i, int)':
/usr/lib/gcc/x86_64-linux-gnu/4.8/include/avx2intrin.h:651:58: error: the last argument must be an 8-bit immediate
return (__m256i)__builtin_ia32_pslldqi256 (__A, __N * 8);
Run Code Online (Sandbox Code Playgroud)
无论是否使用该功能.
这对于立即操作数来说不是问题,因为如果我使用eg _mm256_slli_si32(x, imm)而不是函数doit()编译,并且_mm256_slli_si32()还需要立即操作数.
有一个相关的错误报告
https://gcc.gnu.org/bugzilla/show_bug.cgi?format=multiple&id=54825
但它已经很老了(2012)并且与gcc 4.8.0有关,所以我认为这个补丁已经被整合到g ++ 4.8.4中了.
这个问题有解决方法吗?
指示要移位的位数的参数必须是编译时常量,因为它在指令中被编码为立即值(即不从寄存器加载;实际移位值是指令编码的一部分).只要你直接使用它,就像这样:
__m256i x = _mm256_set1_epi8(0xff);
x = _mm256_slli_si256(x, 3);
Run Code Online (Sandbox Code Playgroud)
然后编译器将shift值视为编译时常量,然而,在包装函数的上下文中:
__m256i doit(__m256i x, const int imm)
{
return _mm256_slli_si256(x, imm);
}
Run Code Online (Sandbox Code Playgroud)
编译器无法推断imm编译时的值,这是合成移位指令所必需的.事实imm是a const int并不意味着它的值在编译时是已知的,只是语言的语义不允许在doit()函数范围内修改它.
如果doit()要由编译器内联,那么它可能能够静态地确定其值imm并因此成功编译,但这可能在一个方面太过分了.
如果你正在使用C++,另一个选择是创建doit()一个带有指示移位大小的参数的函数模板,如下所示:
template <int Shift>
__m256i doit(__m256i x)
{
return _mm256_slli_si256(x, Shift);
}
Run Code Online (Sandbox Code Playgroud)