标志 -ffixed-<reg> 总是在 GCC 中被窃听吗?
Is the flag -ffixed-<reg> always bugged in GCC?
我的 linux 64 位机器上安装了 gcc
的 3 个版本
- 海湾合作委员会 4.9.2
- gcc 5.3.0
- gcc 6 [从 svn 快照构建]
当我尝试用
明确保留 xmm
寄存器时,所有 3 个编译器都给我同样的错误
-ffixed-xmm0 -ffixed-xmm1 -ffixed-xmm2 -ffixed-xmm3 -ffixed-xmm4 -ffixed-xmm5 -ffixed-xmm6 -ffixed-xmm7 -ffixed-xmm8 -ffixed-xmm9 -ffixed-xmm10 -ffixed-xmm11 -ffixed-xmm12 -ffixed-xmm13 -ffixed-xmm14 -ffixed-xmm15
错误是编译器错误
internal compiler error: in copy_to_mode_reg, at explow.c:595
return (__m128i)__builtin_ia32_paddsw128 ((__v8hi)__A, (__v8hi)__B);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Please submit a full bug report,
with preprocessed source if appropriate.
我应该提交错误吗?我注意到 clang
不支持类似的标志来控制代码生成,所以也许 gcc
很久以前就创建了这个标志,现在它不值得了吗?
当我查看使用 clang
从我的 C 函数生成的汇编代码时,没有字节溢出,看起来所有的 xmm 寄存器都按照指示使用,但是 gcc
另一方面并没有真正生成干净的程序集,我仍然想强加这种行为。
还有另一种方法可以强制使用 SSE 和 AVX 寄存器吗?当寄存器被误用时可能会收到警告?
谢谢。
用于测试目的的虚拟函数
#include <stdio.h>
#include <stdint.h>
#include <malloc.h>
#include <emmintrin.h>
typedef int32_t T;
void foo( T * ptr ) {
__m128i v0 = _mm_load_si128( (__m128i *) ( &ptr[0] ) );
__m128i v1 = _mm_load_si128( (__m128i *) ( &ptr[4] ) );
__m128i v2 = _mm_load_si128( (__m128i *) ( &ptr[8] ) );
__m128i v3 = _mm_load_si128( (__m128i *) ( &ptr[12] ) );
__m128i v4 = _mm_load_si128( (__m128i *) ( &ptr[16] ) );
__m128i v5 = _mm_load_si128( (__m128i *) ( &ptr[20] ) );
__m128i v6 = _mm_load_si128( (__m128i *) ( &ptr[24] ) );
__m128i v7 = _mm_load_si128( (__m128i *) ( &ptr[28] ) );
__m128i v8 = _mm_load_si128( (__m128i *) ( &ptr[32] ) );
__m128i v9 = _mm_load_si128( (__m128i *) ( &ptr[36] ) );
__m128i v10 = _mm_load_si128( (__m128i *) ( &ptr[40] ) );
__m128i v11 = _mm_load_si128( (__m128i *) ( &ptr[44] ) );
__m128i v12 = _mm_load_si128( (__m128i *) ( &ptr[48] ) );
__m128i v13 = _mm_load_si128( (__m128i *) ( &ptr[52] ) );
__m128i v14 = _mm_load_si128( (__m128i *) ( &ptr[56] ) );
__m128i v15 = _mm_load_si128( (__m128i *) ( &ptr[60] ) );
v0 = _mm_adds_epi16( v0, v1 );
v0 = _mm_adds_epi16( v0, v2 );
v0 = _mm_adds_epi16( v0, v3 );
v0 = _mm_adds_epi16( v0, v4 );
v0 = _mm_adds_epi16( v0, v5 );
v0 = _mm_adds_epi16( v0, v6 );
v0 = _mm_adds_epi16( v0, v7 );
v0 = _mm_adds_epi16( v0, v8 );
v0 = _mm_adds_epi16( v0, v9 );
v0 = _mm_adds_epi16( v0, v10 );
v0 = _mm_adds_epi16( v0, v11 );
v0 = _mm_adds_epi16( v0, v12 );
v0 = _mm_adds_epi16( v0, v13 );
v0 = _mm_adds_epi16( v0, v14 );
v0 = _mm_adds_epi16( v0, v15 );
_mm_store_si128( (__m128i *) ptr, v0 );
}
您可以将这组命令行选项编写为 -ffixed-xmm{0..15}
(bash 语法),这样更易读。
当您告诉编译器所有 xmm regs 都已保留,然后您尝试使用内部函数时,它会破坏编译器,我并不感到惊讶。 gcc 手册页说 -ffixed-reg
表示:
Treat the register named reg as a fixed register; generated code
should never refer to it (except perhaps as a stack pointer ...
此外,gcc 4.9.2、5.x 和 gcc6 快照全部 make perfectly find code。他们将所有对齐的负载折叠到 paddsw
的内存操作数中,因此函数是一个 movdqa
和十五个 paddsw
(全部到 xmm0
)。
你编译时没有优化吗?当然,asm 会很糟糕,因为 -O0
要求每个局部变量在每次 C 语句之后都在内存中。
几乎每次 gcc 显示以 internal compiler error
开头的消息时,您都应该提交错误。错误消息通常包含 link 到您可以提交它们的网站(例如,使用您的发行版或上游 gcc)。
我没想到,这条规则有两个例外:
- 如果它显示类似
internal compiler error: Killed (program xxx)
的内容 - 大多数情况下这是由于您的系统 运行 内存不足。添加更多 RAM,或增加交换空间,或在您的系统上做一些其他事情来改善这一点。
- 如果您重试编译命令并且它有效——大多数时候,这是您计算机中的错误而不是 gcc(例如 OS 有错误,或者硬件不稳定)。
你在这里的例子似乎不是这两种情况,所以如果 gcc-5.3 和当前的 gcc-6 快照仍然发生,如果你能提交一个错误就太好了。由于您使用的是 gcc-6 快照,我假设您是自己构建的,因此您可以直接转到 gcc's bugzilla.
我的 linux 64 位机器上安装了 gcc
的 3 个版本
- 海湾合作委员会 4.9.2
- gcc 5.3.0
- gcc 6 [从 svn 快照构建]
当我尝试用
明确保留xmm
寄存器时,所有 3 个编译器都给我同样的错误
-ffixed-xmm0 -ffixed-xmm1 -ffixed-xmm2 -ffixed-xmm3 -ffixed-xmm4 -ffixed-xmm5 -ffixed-xmm6 -ffixed-xmm7 -ffixed-xmm8 -ffixed-xmm9 -ffixed-xmm10 -ffixed-xmm11 -ffixed-xmm12 -ffixed-xmm13 -ffixed-xmm14 -ffixed-xmm15
错误是编译器错误
internal compiler error: in copy_to_mode_reg, at explow.c:595
return (__m128i)__builtin_ia32_paddsw128 ((__v8hi)__A, (__v8hi)__B);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Please submit a full bug report,
with preprocessed source if appropriate.
我应该提交错误吗?我注意到 clang
不支持类似的标志来控制代码生成,所以也许 gcc
很久以前就创建了这个标志,现在它不值得了吗?
当我查看使用 clang
从我的 C 函数生成的汇编代码时,没有字节溢出,看起来所有的 xmm 寄存器都按照指示使用,但是 gcc
另一方面并没有真正生成干净的程序集,我仍然想强加这种行为。
还有另一种方法可以强制使用 SSE 和 AVX 寄存器吗?当寄存器被误用时可能会收到警告?
谢谢。
用于测试目的的虚拟函数
#include <stdio.h>
#include <stdint.h>
#include <malloc.h>
#include <emmintrin.h>
typedef int32_t T;
void foo( T * ptr ) {
__m128i v0 = _mm_load_si128( (__m128i *) ( &ptr[0] ) );
__m128i v1 = _mm_load_si128( (__m128i *) ( &ptr[4] ) );
__m128i v2 = _mm_load_si128( (__m128i *) ( &ptr[8] ) );
__m128i v3 = _mm_load_si128( (__m128i *) ( &ptr[12] ) );
__m128i v4 = _mm_load_si128( (__m128i *) ( &ptr[16] ) );
__m128i v5 = _mm_load_si128( (__m128i *) ( &ptr[20] ) );
__m128i v6 = _mm_load_si128( (__m128i *) ( &ptr[24] ) );
__m128i v7 = _mm_load_si128( (__m128i *) ( &ptr[28] ) );
__m128i v8 = _mm_load_si128( (__m128i *) ( &ptr[32] ) );
__m128i v9 = _mm_load_si128( (__m128i *) ( &ptr[36] ) );
__m128i v10 = _mm_load_si128( (__m128i *) ( &ptr[40] ) );
__m128i v11 = _mm_load_si128( (__m128i *) ( &ptr[44] ) );
__m128i v12 = _mm_load_si128( (__m128i *) ( &ptr[48] ) );
__m128i v13 = _mm_load_si128( (__m128i *) ( &ptr[52] ) );
__m128i v14 = _mm_load_si128( (__m128i *) ( &ptr[56] ) );
__m128i v15 = _mm_load_si128( (__m128i *) ( &ptr[60] ) );
v0 = _mm_adds_epi16( v0, v1 );
v0 = _mm_adds_epi16( v0, v2 );
v0 = _mm_adds_epi16( v0, v3 );
v0 = _mm_adds_epi16( v0, v4 );
v0 = _mm_adds_epi16( v0, v5 );
v0 = _mm_adds_epi16( v0, v6 );
v0 = _mm_adds_epi16( v0, v7 );
v0 = _mm_adds_epi16( v0, v8 );
v0 = _mm_adds_epi16( v0, v9 );
v0 = _mm_adds_epi16( v0, v10 );
v0 = _mm_adds_epi16( v0, v11 );
v0 = _mm_adds_epi16( v0, v12 );
v0 = _mm_adds_epi16( v0, v13 );
v0 = _mm_adds_epi16( v0, v14 );
v0 = _mm_adds_epi16( v0, v15 );
_mm_store_si128( (__m128i *) ptr, v0 );
}
您可以将这组命令行选项编写为 -ffixed-xmm{0..15}
(bash 语法),这样更易读。
当您告诉编译器所有 xmm regs 都已保留,然后您尝试使用内部函数时,它会破坏编译器,我并不感到惊讶。 gcc 手册页说 -ffixed-reg
表示:
Treat the register named reg as a fixed register; generated code should never refer to it (except perhaps as a stack pointer ...
此外,gcc 4.9.2、5.x 和 gcc6 快照全部 make perfectly find code。他们将所有对齐的负载折叠到 paddsw
的内存操作数中,因此函数是一个 movdqa
和十五个 paddsw
(全部到 xmm0
)。
你编译时没有优化吗?当然,asm 会很糟糕,因为 -O0
要求每个局部变量在每次 C 语句之后都在内存中。
几乎每次 gcc 显示以 internal compiler error
开头的消息时,您都应该提交错误。错误消息通常包含 link 到您可以提交它们的网站(例如,使用您的发行版或上游 gcc)。
我没想到,这条规则有两个例外:
- 如果它显示类似
internal compiler error: Killed (program xxx)
的内容 - 大多数情况下这是由于您的系统 运行 内存不足。添加更多 RAM,或增加交换空间,或在您的系统上做一些其他事情来改善这一点。 - 如果您重试编译命令并且它有效——大多数时候,这是您计算机中的错误而不是 gcc(例如 OS 有错误,或者硬件不稳定)。
你在这里的例子似乎不是这两种情况,所以如果 gcc-5.3 和当前的 gcc-6 快照仍然发生,如果你能提交一个错误就太好了。由于您使用的是 gcc-6 快照,我假设您是自己构建的,因此您可以直接转到 gcc's bugzilla.