gpt4 book ai didi

assembly - 为什么 Clang 只从 Sandy Bridge 开始做这个优化技巧?

转载 作者:行者123 更新时间:2023-12-03 15:48:15 26 4
gpt4 key购买 nike

我注意到 Clang 为以下代码段做了一个有趣的除法优化技巧

int64_t s2(int64_t a, int64_t b)
{
return a/b;
}

如果指定 march,则以下是程序集输出作为桑迪桥或以上
        mov     rax, rdi
mov rcx, rdi
or rcx, rsi
shr rcx, 32
je .LBB1_1
cqo
idiv rsi
ret
.LBB1_1:
xor edx, edx
div esi
ret

这是 the signed version 的 Godbolt 链接和 the unsigned version

据我了解,它检查两个操作数的高位是否为零,如果为真则进行 32 位除法

我查了 this table并看到 Core2 和 Nehalem 上 32/64 位划分的延迟分别为 40/116 和 26/89。因此,如果操作数确实通常不宽,那么通过进行 32 位除法而不是 64 位除法所节省的费用可能与 SnB 相同

那么为什么它只为 SnB 和后来的微架构启用呢?为什么其他编译器如 GCC 或 ICC 不这样做?

最佳答案

我猜 clang 开发人员测试了它适用于哪些 uarches,并发现它只是 SnB 系列。

这听起来不错,因为 P6 系列上的一个时髦的停顿,以及 AMD 的不同分频器。

使用 P6 系列上的移位 imm8(不是隐式移位 1)的标志结果会导致前端在发出标志读取指令之前停顿,直到移位退出。 (因为 P6 解码器不会检查 imm8=0 的情况以保留未修改的标志,而 SnB 会检查)。 INC instruction vs ADD 1: Does it matter? .这可能就是 clang 不将它用于 P6 系列的原因。

可能有一种不同的方式来检查不会导致此停顿的相关条件(例如 test rcx,rcx 之前的 je ,在 Core2/Nehalem 上值得这样做)。 但是,如果 clang 开发人员没有意识到它在 P6 系列上运行缓慢的原因,他们就不会考虑修复它,并且只是没有为 SnB 之前的目标完成它。 (不幸的是,没有人将我添加到有关此的补丁审查或错误 CC 列表中;这是我第一次看到 clang 进行此优化。虽然我想我可能在其他一些 LLVM 审查或bug。无论如何,尝试添加 test 可能会很有趣,看看这是否对 Nehalem 有意义。)

根据 Agner Fog 的说法,无论操作数大小如何,AMD 的除法器都具有相同的最佳 div 性能,大概仅取决于输入的实际幅度。只有最坏的情况会随着操作数大小而增长。 所以我认为运行idiv r64是无害的在 AMD 上使用小输入符号扩展到 128/64 位。 (AMD 上的 div/idiv 对于所有操作数大小都是 2 uop(除了 8 位,因为它只需要写入一个输出寄存器:AH 和 AL = AX。与 Intel 的微编码整数除法不同。)

英特尔很不一样:idiv r32是 9 uops,而 idiv r64是 59 uop,在 Haswell 上,最佳情况下的吞吐量要差 3 倍。 SnB 家族的其他成员是类似的。

Why don't other compilers like GCC or ICC do it?



可能是因为clang开发者想到了,gcc/icc还没有复制过来。如果您看过钱德勒·卡鲁斯 (Chandler Carruth) 的演讲 perf ,他使用的一个例子是玩弄一个分支来跳过 div .我猜这个优化是他的主意。看起来很漂亮。 :)

关于assembly - 为什么 Clang 只从 Sandy Bridge 开始做这个优化技巧?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54438477/

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