【问题标题】:Why isn't a constant multiply realized by a mul instruction? [duplicate]为什么 mul 指令不能实现常数乘法? [复制]
【发布时间】: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”要快。

标签: linux assembly x86 x86-64


【解决方案1】:

您的目标是具有专用地址计算单元的处理器。在地址计算器中计算小乘法可能比在通用算术/逻辑单元 (ALU) 中更快。

此外,根据您的处理器型号,ALU 可能与其他代码共享,这可能是由于超线程或同一线程内的推测性或乱序执行。您的编译器正在很好地估计如何最好地利用可用资源来提供良好的执行吞吐量而不会停止。

每条汇编指令等于一个处理器时钟周期”(甚至是固定数量的周期)的想法只在最简单的处理器上才成立。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-16
  • 2011-03-03
  • 2017-11-30
  • 2018-09-25
相关资源
最近更新 更多