_mm256_slli_si256:错误“最后一个参数必须是8位中间”

时间:2015-07-09 11:01:17

标签: 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);

代码编译没有问题(g++ -Wall -march=native -O3 -o shifttest shifttest.C)。

但是,如果我把它包装成一个函数

__m256i doit(__m256i x, const int imm)
{
  return _mm256_slli_si256(x, imm);
}

编译器抱怨

/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);

无论是否使用该功能。

对于立即操作数,这不是问题,因为如果我使用例如doit()函数编译相反,_mm256_slli_si32(x, imm)_mm256_slli_si32()也需要一个立即操作数。

有关于

的相关错误报告

https://gcc.gnu.org/bugzilla/show_bug.cgi?format=multiple&id=54825

但它已经很老了(2012)并且与gcc 4.8.0有关,所以我认为该补丁已经被整合到g ++ 4.8.4中了。

此问题是否有解决方法?

2 个答案:

答案 0 :(得分:7)

指示要移位的位数的参数必须是编译时常量,因为它在指令中被编码为立即值(即不从寄存器加载;实际移位值是指令编码的一部分) 。只要你直接使用它,就像这样:

__m256i x = _mm256_set1_epi8(0xff);
x = _mm256_slli_si256(x, 3);

然后编译器将shift值视为编译时常量,然而,当你在包装函数的上下文中时:

__m256i doit(__m256i x, const int imm)
{
  return _mm256_slli_si256(x, imm);
}

编译器无法在编译时推断imm的值,这是合成移位指令所必需的。 immconst int的事实并不意味着它的值在编译时是已知的,只是语言的语义不允许在doit()内修改它。功能范围。

如果编译器要内联doit(),那么它可能能够静态地确定imm的值并因此成功编译,但这可能太过分了肢体。

如果您正在使用C ++,另一个选择是使doit()成为一个带有指示移位大小的参数的函数模板,如下所示:

template <int Shift>
__m256i doit(__m256i x)
{
  return _mm256_slli_si256(x, Shift);
}

答案 1 :(得分:1)

问题是由于您的函数是公共的(即可以通过其他C / C ++模块中的函数调用)。如果您将其声明为static(或inline),编译器将不会为此函数执行代码生成,并且您不会收到错误。