c - _mm256_slli_si256 : error "last argument must be an 8-bit intermediate"

标签 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 中了。

这个问题有解决办法吗?

最佳答案

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

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

然后编译器将移位值视为编译时常量 3。但是,当在包装函数的上下文中时:

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

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

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

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

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

关于c - _mm256_slli_si256 : error "last argument must be an 8-bit intermediate",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31315491/

相关文章:

c - 使用 SSE 从 _m128i 寄存器中提取非零值

创建一个非阻塞定时器来删除数据

Windows 下 Visual Studio 2012/英特尔编译器的 C++ double 失败

c - 如何将无符号整数加载到 SIMD 中

在 Windows 上使用 Makefile 编译 C 文件

c++ - 错误 : '_mm512_loadu_epi64' was not declared in this scope

c - 计算网格上连接组的相邻空点的有效方法

抛弃常量会导致未定义的行为吗?

android - 计时器在 Android 的 sleep 状态下不会准确地过期

c - C中的插入二叉搜索树