编译器真的优化使这两个函数成为同一个程序集吗?

Does the compiler really optimize to make these two functions the same assembly?

我将其插入到 Godbolt 中,令我惊喜的是这两个函数调用 a()b()-O0 以外的任何情况下都是等效的(使用大多数主要编译器):

#include <cmath>

struct A {
    int a,b,c;
    float bar() {
        return sqrt(a + b + c);
    }
};

struct B {
    int a[3];
    float bar() {
        int ret{0};
        for (int i = 0; i<3; ++i) {
            ret += a[i];
        }
        return sqrt(ret);
    }
};

float a() {
    A a{55,67,12};
    return a.bar();
}

float b() {
    B b{55,67,12};
    return b.bar();
}

Godbolt 输出是:

a():
        movss   xmm0, DWORD PTR .LC0[rip]
        ret
b():
        movss   xmm0, DWORD PTR .LC0[rip]
        ret
.LC0:
        .long   1094268577

我不是装配专家,但我想知道这是否真的是真的,他们在做相同的工作。我什至看不到这个程序集中哪里有对 sqrt 的调用,或者 long“常量”(?) 在那里做什么。

这个函数:

float a() {
    A a{55,67,12};
    return a.bar();
}

具有与此完全相同的可观察行为:

float a() {
    return sqrt(55+67+12);
}

b()也是如此。此外,sqrt(55+67+12) == sqrt(134) == 11.5758369028.

Binary representation of the IEEE-754 floating point value 11.5758369028 is 01000001001110010011011010100001. And that binary as integer is 1094268577.

编译器应用所谓的 as if rule 将两个函数替换为具有与原始代码完全相同的可观察行为的程序集:两个函数 return a float with value 11.5758369028.