Почему g ++ использует movabs со странной константой для простого сокращения? - PullRequest
0 голосов
/ 06 октября 2018

Я собираю эту простую программу:

#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!

1 Ответ

0 голосов
/ 06 октября 2018

8589934593 - это 0x200000001 в шестнадцатеричном формате, а 17179869187 - это 0x400000003.Эти две movabs инструкции просто загружают две int константы в каждый 64-битный регистр для инициализации массива в стеке.Вы можете отключить эту оптимизацию GCC, используя -fno-store-merging, тогда вы получите что-то вроде этого в -O2 для инициализации массива:

movl    $1, -40(%rsp)
…
…
movl    $2, -36(%rsp)
…
movl    $3, -32(%rsp)
movl    $4, -28(%rsp)
movl    $5, -24(%rsp)

Отсутствие оптимизации для одной константы выглядит как регрессия GCC,Кстати.Я не вижу этого с GCC 6.3.На самом деле это может быть связано со слиянием магазинов, которое я не считаю частью GCC 6.

...