标志-ffixed- <reg>总是在GCC中被窃听?

时间:2016-03-05 04:01:59

标签: c linux gcc clang intrinsics

我的linux 64位计算机上安装了3个gcc版本

  • gcc 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寄存器都被用作instruncted,但另一方面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 ); 
}

2 个答案:

答案 0 :(得分:3)

您可以将这组命令行选项更可读地编写为-ffixed-xmm{0..15}(bash语法)。

当你告诉它所有xmm regs都被保留,然后你尝试使用内在函数时,我并不感到惊讶。 gcc手册页说-ffixed-reg表示:

  

将名为reg的寄存器视为固定寄存器;生成的代码   永远不应该引用它(除了可能作为堆栈指针......

此外,gcc 4.9.2,5.x和gcc6快照全部为make perfectly find code。它们将所有对齐的加载折叠到paddsw的内存操作数中,因此函数是一个movdqa和十五paddsw(全部到xmm0)。

你没有优化编译吗?当然,asm会很糟糕,因为-O0要求每个本地在C语句之后都在内存中。

答案 1 :(得分:1)

几乎每当gcc显示以internal compiler error开头的消息时,您都应该提交错误消息。错误消息通常包含指向您可以提交文件的网站的链接(例如,您的发行版或上游gcc)。

这个规则有两个例外:

  1. 如果它显示internal compiler error: Killed (program xxx)之类的内容 - 大多数情况下这是由于您的系统耗尽了RAM。添加更多RAM,或增加交换,或在系统上执行其他操作来改善这一点。
  2. 如果您重试编译命令并且它可以正常工作 - 大部分时间,这是您计算机中的错误而不是gcc(例如操作系统有问题,或者硬件不稳定)。
  3. 你的例子似乎不是这两种情况,所以如果它仍然发生在gcc-5.3&amp;当前的gcc-6快照,如果您可以提交错误,那就太棒了。因为你正在使用gcc-6快照,我假设你是自己构建的,所以你可以直接进入gcc's bugzilla