gpt4 book ai didi

c - 在进行除法乘法时,额外的移动会以某种方式更快吗?

转载 作者:行者123 更新时间:2023-12-03 09:27:31 25 4
gpt4 key购买 nike

考虑这个函数:

unsigned long f(unsigned long x) {
return x / 7;
}

-O3 , 叮当 turns the division into a multiplication ,正如预期的那样:
f:                                      # @f
movabs rcx, 2635249153387078803
mov rax, rdi
mul rcx
sub rdi, rdx
shr rdi
lea rax, [rdi + rdx]
shr rax, 2
ret

除了使用 rdx 之外,GCC 基本上做了同样的事情。 Clang 使用的地方 rcx .但他们似乎都在做额外的举动。为什么不是这个呢?
f:
movabs rax, 2635249153387078803
mul rdi
sub rdi, rdx
shr rdi
lea rax, [rdi + rdx]
shr rax, 2
ret

特别是,他们都把分子放在 rax ,但通过将魔数(Magic Number)放在那里,您根本不必移动分子。如果这实际上更好,我很惊讶 GCC 和 Clang 都没有这样做,因为这感觉很明显。他们的方式实际上比我的方式快吗?

Godbolt link .

最佳答案

这很像是 gcc 和 clang 都错过的优化;对那个额外的 mov 没有任何好处。

如果尚未报告,GCC 和 LLVM 都接受遗漏优化错误报告:https://bugs.llvm.org/https://gcc.gnu.org/bugzilla/ .对于 GCC,甚至还有一个错误标签“missed-optimization”。

浪费 mov不幸的是,指令并不罕见,尤其是在查看输入/输出 regs 确定调用约定而不是寄存器分配器的小函数时。有时确实会在循环中发生,就像每次迭代都做一些额外的工作,这样一切都在循环后运行一次的代码的正确位置。/面掌。

零延迟 mov (mov-elimination) 有助于降低这种错过优化的成本(以及 mov 无法避免的情况),但它仍然需要前端 uop,所以它实际上更糟。 (除非偶然它有助于稍后对齐某些内容,但如果这是原因,那么 nop 会一样好)。

并且它占用了 ROB 中的空间,减少了乱序 exec 在缓存未命中或其他停顿后可以看到的距离。 mov永远不会真正免费,只有执行单元和延迟部分被消除 - Can x86's MOV really be "free"? Why can't I reproduce this at all?

我对编译器内部结构的总猜测:

可能 gcc/clang 的内部机制需要了解这种除法模式是可交换的,并且可以将输入值放在其他寄存器中并将常量放在 RAX 中。

在循环中,他们希望常量在其他寄存器中,以便他们可以重用它,但希望编译器仍然可以在它有用的情况下弄清楚这一点。

关于c - 在进行除法乘法时,额外的移动会以某种方式更快吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61470328/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com