while (i--) оптимизация с помощью gcc и clang: почему они не используют sub / jnc? - PullRequest
0 голосов
/ 20 января 2019

Некоторые люди пишут такой код, когда им нужен цикл без счетчика или с n-1, ..., 0 счетчиком:

while (i--) { ... }

Конкретный пример:

volatile int sink;
void countdown_i_used() {
    unsigned i = 1000;
    while (i--) {
         sink = i;  // if i is unused, gcc optimizes it away and uses dec/jnz
    }
}

В GCC 8.2 ( в проводнике компилятора Godbolt ) он компилируется в

# gcc8.2 -O3 -march=haswell
.L2:
    mov     DWORD PTR sink[rip], eax
    dec     eax                      # with tune=generic,  sub eax, 1
    cmp     eax, -1
    jne     .L2

On clang (https://godbolt.org/z/YxYZ95),, если счетчик не используется, он превращается в

if(i) do {...} while(--i);

но если используется, как GCC, он превращается в

add esi, -1
cmp esi, -1
jnz lp

Однако, это, кажется, лучшая идея:

sub esi, 1
jnc lp

Почему эти два компилятора не используют этот способ?

Потому что способ cmp лучше? Или потому, что они не будут экономить место таким образом и будут иметь почти одинаковую скорость?

Или они просто не рассматривают этот вариант?

1 Ответ

0 голосов
/ 20 января 2019

Да, это пропущенная оптимизация.Семейство Intel Sandybridge может объединить макрос sub / jcc в один моп, поэтому sub / jnc сохраняет размер кода, инструкции x86 и мопы на этих процессорах.

На других процессорах (например, AMD, которые могут только сливатьсяtest / cmp с jcc), это все еще сохраняет размер кода, так что, по крайней мере, немного лучше.Ничем не хуже.

Было бы неплохо сообщить об ошибках при пропущенной оптимизации на https://bugs.llvm.org и https://gcc.gnu.org/bugzilla/.

...