Я собираю эту простую программу:
#include <numeric>
int main()
{
int numbers[] = {1, 2, 3, 4, 5};
auto num_numbers = sizeof(numbers)/sizeof(numbers[0]);
return std::accumulate(numbers, numbers + num_numbers, 0);
}
, которая суммирует целые числа от 1 до 5 и возвращает эту сумму (т. Е. 15).
Я понимаю, что std::accumulate
может иметьнемного хитрости в реализации, но все же, это довольно просто.Я удивлен тем, что получаю при компиляции этого (на GodBolt), хотя.
С -O3
и с C ++, являющимся языком, ориентированным на время компиляции, яполучите ожидаемое:
main:
mov eax, 15
ret
но если я уйду до -O2
- все еще какая-то тяжелая оптимизация - я не только не получу это вычисление во время компиляции, но я увижу этот странный фрагмент сборки:
main:
movabs rax, 8589934593
lea rdx, [rsp-40]
mov ecx, 1
mov DWORD PTR [rsp-24], 5
mov QWORD PTR [rsp-40], rax
lea rsi, [rdx+20]
movabs rax, 17179869187
mov QWORD PTR [rsp-32], rax
xor eax, eax
jmp .L3
.L5:
mov ecx, DWORD PTR [rdx]
.L3:
add rdx, 4
add eax, ecx
cmp rdx, rsi
jne .L5
ret
Теперь .L5
и .L3
Я получаю.Удивительной вещью являются эти странные movabs
инструкции от rax
.Что они имеют в виду и почему они существуют?
PS - Я скомпилировал, используя GCC 8.2 на x86_64 без установленного -march
.Если я добавлю -march=skylake
- -O3
тоже испортится! Редактировать: Кажется, это регрессия в GCC, см. Мой отчет об ошибках GCC .Спасибо @FlorianWeimer!