) превращает их в кучу переменных SSA, если это возможно. Так что, по крайней мере, в clang «антиоптимизация» не происходит, обычные оптимизации просто отключены.
бираю этот код на llvm clang Apple LLVM версии 8.0.0 (clang-800.0.42.1):
int main() {
float a=0.151234;
float b=0.2;
float c=a+b;
printf("%f", c);
}
Я скомпилировал без спецификаций -O, но я также попытался с -O0 (дает то же самое) и -O2 (фактически вычисляет значение и сохраняет его предварительно вычисленным)
В результате разборка выглядит следующим образом (я удалил части, которые не имеют отношения)
-> 0x100000f30 <+0>: pushq %rbp
0x100000f31 <+1>: movq %rsp, %rbp
0x100000f34 <+4>: subq $0x10, %rsp
0x100000f38 <+8>: leaq 0x6d(%rip), %rdi
0x100000f3f <+15>: movss 0x5d(%rip), %xmm0
0x100000f47 <+23>: movss 0x59(%rip), %xmm1
0x100000f4f <+31>: movss %xmm1, -0x4(%rbp)
0x100000f54 <+36>: movss %xmm0, -0x8(%rbp)
0x100000f59 <+41>: movss -0x4(%rbp), %xmm0
0x100000f5e <+46>: addss -0x8(%rbp), %xmm0
0x100000f63 <+51>: movss %xmm0, -0xc(%rbp)
...
Видимо, он делает следующее:
загрузка двух поплавков в регистры xmm0 и xmm1положить их в стекзагрузить одно значение (а не то, которое было раньше у xmm0) из стека в xmm0выполнить сложение.сохранить результат обратно в стек.Я считаю это неэффективным, потому что:
Все можно сделать в реестре. Я не буду использовать a и b позже, поэтому он может просто пропустить любую операцию, связанную со стеком.даже если бы он хотел использовать стек, он мог бы сохранить перезагрузку xmm0 из стека, если бы он выполнял операцию в другом порядке.Учитывая, что компилятор всегда прав, почему он выбрал эту стратегию?