汇编代码一般化

时间:2017-03-06 17:12:18

标签: c gcc assembly optimization x86

我在计算机架构类中遇到以下代码:

void mystery( long A[], long B[], long n )
{
  long i;
  for ( i = 0; i < n; i++ ) {
    B[i] = A[n-(i+1)];
  }
}

我的教授展示了GCC在Ubuntu机器上生成的相应汇编代码,他似乎也感到困惑:

mystery:
    pushq   %rbp
    movq    %rsp, %rbp
    movq    %rdi, -24(%rbp)
    movq    %rsi, -32(%rbp)
    movq    %rdx, -40(%rbp)
    movq    $0, -8(%rbp)
    jmp .L2
.L3:
    movq    -8(%rbp), %rax
    leaq    0(,%rax,8), %rdx
    movq    -32(%rbp), %rax
    addq    %rax, %rdx
    movq    -8(%rbp), %rax
    notq    %rax
    movq    %rax, %rcx
    movq    -40(%rbp), %rax
    addq    %rcx, %rax
    leaq    0(,%rax,8), %rcx
    movq    -24(%rbp), %rax
    addq    %rcx, %rax
    movq    (%rax), %rax
    movq    %rax, (%rdx)
    addq    $1, -8(%rbp)
.L2:
    movq    -8(%rbp), %rax
    cmpq    -40(%rbp), %rax
    jl  .L3
    popq    %rbp
    ret

但是我无法理解为什么编译器会生成这段代码。看起来A,B和n被压入堆栈但堆栈指针%rsp没有改变它的值。此外,-16(%rbp)似乎也已分配,但永远不会放入值。 GCC会有这样的行为吗?

1 个答案:

答案 0 :(得分:1)

Compiler Explorer (godbolt.org)是一个很好的工具,可以查看来自各种编译器和不同标志的生成程序集。以下是g++7 -O2为您的代码生成的内容:

mystery(long*, long*, long):
        test    rdx, rdx
        jle     .L1
        lea     rax, [rdi-8+rdx*8]
        sub     rdi, 8
.L3:
        mov     rdx, QWORD PTR [rax]
        sub     rax, 8
        add     rsi, 8
        mov     QWORD PTR [rsi-8], rdx
        cmp     rax, rdi
        jne     .L3
.L1:
        rep ret

回答你的问题:通过优化禁用编译通常会出现意外/不太合理的输出。 “为什么?”是一个难以回答的问题,因为这在很大程度上取决于编译器的实现方式。

以下是显示-O2-O0-Ofast的比较的屏幕截图:

comparison

在此处试试:https://godbolt.org/g/pQ637a