c - GCC 中 -ffixed-<reg> 标志是否总是有问题?

标签 c linux gcc clang intrinsics

我的 Linux 64 位机器上安装了 3 个版本的 gcc

  • 海湾合作委员会4.9.2
  • 海湾合作委员会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 code> 另一方面并没有真正生成干净的程序集,我仍然想强加这种行为。

还有另一种方法可以强制使用 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 寄存器都被保留,然后您尝试使用内在函数时,它会破坏编译器,我对此并不感到惊讶。 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 语句之后的局部变量都位于内存中。

关于c - GCC 中 -ffixed-<reg> 标志是否总是有问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35809832/

相关文章:

gcc - 为什么 GCC 提示 'sizeof' 之前缺少不存在的标识符?

c - DirectFB教程无效参数

c - 如何使用 sendmsg() 通过 2 个进程之间的套接字发送文件描述符?

c++ - 模板 - 巨大的目标文件导致链接器崩溃

linux - 用另一个程序写入scanf

linux - 使用 PuTTY 连接后无法使用 Perl 脚本连接到 Linux Oracle 数据库

c - 在 gcc 中禁用可变长度自动数组

c - Printf 返回的是从 scanf 输入的错误数字

c - C内核编程中的invbool有什么意义?

c - 填充和打印二维数组