这个问题涉及到gcc(4.6.3 Ubuntu)在使用SSE指令时对于带立即数操作数的循环展开的行为。
一个带有立即数操作数的例子是_mm_blend_ps。它期望一个4位的立即整数,只能是一个常量。然而,使用-O3选项,编译器显然会自动展开循环(如果循环计数器的值可以在编译时确定),并产生多个相应的混合指令实例,具有不同的立即值。
这是一个简单的测试代码(blendsimple.c),它遍历了混合操作的16个可能的立即操作数的值。
您在混合内置函数中遇到了以下错误:
我希望行为与-O3完全相同。然而,编译器抱怨“最后一个参数必须是4位即时数”。有人知道问题出在哪里吗?我认为知道需要哪个标志才能启用此类循环展开很重要,这样可以使用#pragma GCC optimize或函数属性有选择地激活它。(我也很惊讶-O3显然甚至没有启用unroll-loops选项)。我将非常感谢任何帮助。这是我上SSE编程课的资料。编辑:感谢您的评论。jtaylor似乎是正确的。我找到了两个更新版本的gcc(4.7.3、4.8.2),4.8.2无论优化级别如何都会抱怨即时问题。此外,我后来注意到,gcc 4.6.3使用-O2-funroll-loops编译代码,但在4.8.2中也失败了。因此,显然不能信任此功能,并且应始终使用cpp或模板手动展开,正如Jason R所指出的那样。
一个带有立即数操作数的例子是_mm_blend_ps。它期望一个4位的立即整数,只能是一个常量。然而,使用-O3选项,编译器显然会自动展开循环(如果循环计数器的值可以在编译时确定),并产生多个相应的混合指令实例,具有不同的立即值。
这是一个简单的测试代码(blendsimple.c),它遍历了混合操作的16个可能的立即操作数的值。
#include <stdio.h>
#include <x86intrin.h>
#define PRINT(V) \
printf("%s: ", #V); \
for (i = 3; i >= 0; i--) printf("%3g ", V[i]); \
printf("\n");
int
main()
{
__m128 a = _mm_set_ps(1, 2, 3, 4);
__m128 b = _mm_set_ps(5, 6, 7, 8);
int i;
PRINT(a);
PRINT(b);
unsigned mask;
__m128 r;
for (mask = 0; mask < 16; mask++) {
r = _mm_blend_ps(a, b, mask);
PRINT(r);
}
return 0;
}
可以使用以下方式编译此代码
gcc -Wall -march=native -O3 -o blendsimple blendsimple.c
如果编译器可以正常工作,那么代码就可以运行。显然,编译器会展开循环并插入立即操作数的常量。
但是,如果使用以下方式编译代码
gcc -Wall -march=native -O2 -o blendsimple blendsimple.c
您在混合内置函数中遇到了以下错误:
error: the last argument must be a 4-bit immediate
现在我尝试找出在 -O3 中激活但在 -O2 中未激活的特定编译器标志,使编译器可以展开循环,但失败了。按照 gcc 在线文档所述
https://gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/Overall-Options.html
我执行了以下命令:
gcc -c -Q -O3 --help=optimizers > /tmp/O3-opts
gcc -c -Q -O2 --help=optimizers > /tmp/O2-opts
diff /tmp/O2-opts /tmp/O3-opts | grep enabled
该列表列出了由 -O3 启用但不由 -O2 启用的所有选项。当我将这 7 个列出的标志全部添加到 -O2 中时
gcc -Wall -march=native -O2 -fgcse-after-reload -finline-functions -fipa-cp-clone -fpredictive-commoning -ftree-loop-distribute-patterns -ftree-vectorize -funswitch-loops blendsimple blendsimple.c
我希望行为与-O3完全相同。然而,编译器抱怨“最后一个参数必须是4位即时数”。有人知道问题出在哪里吗?我认为知道需要哪个标志才能启用此类循环展开很重要,这样可以使用#pragma GCC optimize或函数属性有选择地激活它。(我也很惊讶-O3显然甚至没有启用unroll-loops选项)。我将非常感谢任何帮助。这是我上SSE编程课的资料。编辑:感谢您的评论。jtaylor似乎是正确的。我找到了两个更新版本的gcc(4.7.3、4.8.2),4.8.2无论优化级别如何都会抱怨即时问题。此外,我后来注意到,gcc 4.6.3使用-O2-funroll-loops编译代码,但在4.8.2中也失败了。因此,显然不能信任此功能,并且应始终使用cpp或模板手动展开,正如Jason R所指出的那样。