如果速度更快,为什么编译器不将“n / 2.0”强制转换为“n * 0.5”?

-10 c c++ intrinsics compiler-optimization

我一直认为num * 0.5fnum / 2.0f是等价的,因为我认为编译器足够聪明,可以优化除法。所以今天我决定测试一下这个理论,但我发现的结果却难住了我。

给出以下示例代码:

float mul(float num) {
    return num * 0.5f;
}

float div(float num) {
    return num / 2.0f;
}
Run Code Online (Sandbox Code Playgroud)

x86-64 clang 和 gcc 都会生成以下汇编输出:

mul(float):
        push    rbp
        mov     rbp, rsp
        movss   DWORD PTR [rbp-4], xmm0
        movss   xmm1, DWORD PTR [rbp-4]
        movss   xmm0, DWORD PTR .LC0[rip]
        mulss   xmm0, xmm1
        pop     rbp
        ret
div(float):
        push    rbp
        mov     rbp, rsp
        movss   DWORD PTR [rbp-4], xmm0
        movss   xmm0, DWORD PTR [rbp-4]
        movss   xmm1, DWORD PTR .LC1[rip]
        divss   xmm0, xmm1
        pop     rbp
        ret
Run Code Online (Sandbox Code Playgroud)

当将其输入(循环)到https://uica.uops.info/上提供的代码分析器时,分别向我们显示 9.0 和 16.0 (skylake) CPU 周期的预测吞吐量。

我的问题是:为什么编译器不强制 div 函数与 mul 函数等效?当然,让 rhs 成为一个常数值应该会促进它,不是吗?

附言。我还在 Rust 中尝试了一个等效的例子,结果分别是 4.0 和 11.0 个 cpu 周期。

Hen*_*her 7

如果使用优化编译,两个编译器将归结为相同的实现-O2

https://godbolt.org/z/v3dhvGref

在此输入图像描述