我在计算机架构类中遇到以下代码:
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会有这样的行为吗?
答案 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
的比较的屏幕截图: