_mm256_slli_si256: 错误 "last argument must be an 8-bit intermediate"
_mm256_slli_si256: error "last argument must be an 8-bit intermediate"
我有以下问题(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);
}
问题是由于您的函数是 public(即可由其他 C/C++ 模块中的函数调用)。如果您将其声明为 static
(或 inline
),编译器将不会为此函数生成代码,您也不会得到错误。
我有以下问题(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);
}
问题是由于您的函数是 public(即可由其他 C/C++ 模块中的函数调用)。如果您将其声明为 static
(或 inline
),编译器将不会为此函数生成代码,您也不会得到错误。