Будет ли GCC оптимизировать условия самовоспламенения внутри циклов? - PullRequest
0 голосов
/ 24 мая 2018

Если, например, у меня есть код, как показано ниже:

int b = 0;

// more stuff here

for ( int i = 0; i < 100; ++i ) {
    if ( !b ) {
        b = 1;
    } else {
        // do some other stuff
    }
}

Если первое условие истинно на первой итерации, оно обязательно никогда не будет истинным на следующих итерациях (и если оно ложно нана первой итерации она также будет ложной на следующих итерациях, если b не изменено в разделе «прочее»).Таким образом, для всех итераций цикла, кроме первой, будет выполняться только блок else.

Будет ли GCC (или аналогичные компиляторы) оптимизировать это, например, путем извлечения кода для первой итерации изапустить его до цикла, а затем запустить цикл с 1 и без условного?Или это то, что я должен был бы сделать сам, если бы я хотел быть наркоманом-исполнителем?

1 Ответ

0 голосов
/ 24 мая 2018

Это сильно зависит от того, что находится в закомментированных разделах.Как написано, если вы поместите это в функцию и просто вернете b примерно так:

int example() {
    int b = 0;
    // more stuff here
    for ( int i = 0; i < 100; ++i ) {
        if ( !b ) {
            b = 1;
        } else {
            // do some other stuff
        }
    }
    return b;
}

Если вы указали -O2 или выше, тогда gcc 4.4.7 ипозже скомпилируйте это в :

example():
  mov eax, 1
  ret

Таким образом, он полностью оценивает цикл.С другой стороны, если у вас есть что-то, что зависит от b и i, например, так:

extern int doSomeOtherStuff(int b, int i);

int example() {
    int b = 0;
    // more stuff here (that doesn't interfere with b)
    for ( int i = 0; i < 100; ++i ) {
        if ( !b ) {
            b = 1;
        } else {
            doSomeOtherStuff(b, i);
        }
    }
    return b;
}

Затем это компилируется ( по 4.4.7 ) в:

example():
  push rbx
  xor ebx, ebx
  jmp .L2
.L3:
  mov esi, ebx
  mov edi, 1
  call doSomeOtherStuff(int, int)
.L2:
  add ebx, 1
  cmp ebx, 100
  jne .L3
  mov eax, 1
  pop rbx
  ret

Здесь мы видим, что инструкция mov edi, 1 соответствует аргументу b, который всегда равен 1, когда вызывается doSomeOtherStuff.В GCC 8.1 это достаточно умно, чтобы развернуть цикл до первого вызова до doSomeOtherStuff, в то время как 4.4.7 испускает весь цикл.

...