【问题标题】:Why did GCC generate mov %eax,%eax and what does it mean?为什么 GCC 会生成 mov %eax,%eax ,这是什么意思?
【发布时间】:2012-08-08 06:39:23
【问题描述】:

GCC 4.4.3 生成了以下 x86_64 程序集。让我困惑的部分是mov %eax,%eax。将寄存器移动到自身?为什么?

   23b6c:       31 c9                   xor    %ecx,%ecx        ; the 0 value for shift
   23b6e:       80 7f 60 00             cmpb   $0x0,0x60(%rdi)  ; is it shifted?
   23b72:       74 03                   je     23b77
   23b74:       8b 4f 64                mov    0x64(%rdi),%ecx  ; is shifted so load shift value to ecx
   23b77:       48 8b 57 38             mov    0x38(%rdi),%rdx  ; map base
   23b7b:       48 03 57 58             add    0x58(%rdi),%rdx  ; plus offset to value
   23b7f:       8b 02                   mov    (%rdx),%eax      ; load map_used value to eax
   23b81:       89 c0                   mov    %eax,%eax        ; then what the heck is this? promotion from uint32 to 64-bit size_t?
   23b83:       48 d3 e0                shl    %cl,%rax         ; shift rax/eax by cl/ecx
   23b86:       c3                      retq   

这个函数的C++代码是:

    uint32_t shift = used_is_shifted ? shift_ : 0;
    le_uint32_t le_map_used = *used_p();
    size_t map_used = le_map_used;
    return map_used << shift;

le_uint32_t 是一个在大端机器上包装字节交换操作的类。在 x86 上它什么也不做。 used_p() 函数从映射基址 + 偏移量计算一个指针,并返回一个正确类型的指针。

【问题讨论】:

标签: gcc assembly x86-64


【解决方案1】:

在 x86-64 中,32 位指令隐式零扩展:位 32-63 被清除 (to avoid false dependencies)。所以有时这就是为什么你会看到奇怪的指令。 (Is mov %esi, %esi a no-op or not on x86-64?)

但是,在这种情况下,之前的 mov-load 也是 32 位的,因此 %rax 的高半部分已经被清除。 mov %eax, %eax 似乎是多余的,显然只是 GCC 错过了优化。

【讨论】:

  • 这种NOP也可以起到流水线优化的作用。
猜你喜欢
  • 2014-10-28
  • 2019-03-30
  • 2012-05-21
  • 2011-10-12
  • 2011-03-14
  • 2017-05-05
  • 1970-01-01
相关资源
最近更新 更多