【发布时间】:2017-03-07 16:06:23
【问题描述】:
让我们考虑以下函数:
#include <stdint.h>
uint64_t foo(uint64_t x) { return x * 3; }
如果我要写它,我会写的
.global foo
.text
foo:
imul %rax, %rdi, $0x3
ret
另一方面,编译器生成两个加法,-O0:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 48 89 7d f8 mov %rdi,-0x8(%rbp)
8: 48 8b 55 f8 mov -0x8(%rbp),%rdx
c: 48 89 d0 mov %rdx,%rax
f: 48 01 c0 add %rax,%rax
12: 48 01 d0 add %rdx,%rax
15: 5d pop %rbp
16: c3 retq
或lea 与-O2:
0000000000000000 <foo>:
0: 48 8d 04 7f lea (%rdi,%rdi,2),%rax
4: c3 retq
为什么?由于每条汇编指令等于一个处理器时钟滴答,我的版本应该在 2 个 CPU 时钟周期内运行(因为它有两条指令),在 -O0 我们需要 4 个周期来执行加法,因为它可以重写为
mov %rdi,%rax
add %rax,%rax
add %rdi,%rax
retq
lea 也需要两个周期。
【问题讨论】:
-
“由于每条汇编指令都等于一个处理器时钟滴答”,这是不正确的。
-
您的标题不反映您问题的主体。
-
标题本质上是“
q是干什么用的?” -
是的,我给了它错误的标题。解决了这个问题。
-
通常编译器比人类更清楚什么是最快的方法。有时不是,但通常是。我记得在 X86 上,编译器总是产生序列“push bp; mov bp, sp; sub sp,xxx”,而不是单一的“enter xxx”。事实证明编译器是对的,这三个指令比单个“输入xxx”要快。