【问题标题】:Why does Clang do this optimization trick only from Sandy Bridge onward?为什么 Clang 只从 Sandy Bridge 开始做这个优化技巧?
【发布时间】:2019-06-23 14:37:21
【问题描述】:

我注意到 Clang 为以下 sn-p 做了一个有趣的除法优化技巧

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

如果将 march 指定为 Sandy Bridge 或更高版本,则以下是程序集输出

        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 versionthe unsigned version 的 Godbolt 链接

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

我检查了this table,发现 Core2 和 Nehalem 上 32/64 位除法的延迟分别为 40/116 和 26/89。因此,如果操作数确实通常不宽,那么通过进行 32 位除法而不是 64 位除法所节省的成本可能与 SnB 上的一样值得

那么为什么它只对 SnB 和更高版本的微架构启用呢?为什么 GCC 或 ICC 等其他编译器不这样做?

【问题讨论】:

    标签: assembly optimization clang x86-64 division


    【解决方案1】:

    我猜 clang 开发人员测试了它在哪些 uarches 上好用,发现它只是 SnB 家族。

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


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

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


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

    英特尔非常不同:idiv r32 是 9 微指令,而 idiv r64 是 59 微指令,在 Haswell 上的最佳情况下吞吐量要差 3 倍。 SnB 家族的其他成员类似。

    为什么 GCC 或 ICC 等其他编译器不这样做?

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

    【讨论】:

    • 而不是shr rcx, 32; test rcx,rcx 可能mov rdi, 0xFFFFFFFF00000000; test rcx, rdi 也可以,虽然要长一些
    猜你喜欢
    • 2013-09-27
    • 1970-01-01
    • 2017-03-05
    • 2013-06-16
    • 1970-01-01
    • 2010-11-10
    • 1970-01-01
    • 2014-07-13
    • 2010-12-24
    相关资源
    最近更新 更多