Оптимизация компилятора, приводящая к замедлению работы программы - PullRequest
9 голосов
/ 19 августа 2011

У меня есть следующий фрагмент кода, который я написал на C. Он довольно прост, так как он просто сдвигает биты x для каждого цикла for.

int main() {
   int x = 1;
   for (int i = 0; i > -2; i++) {
      x >> 2;
   }
}

Теперь странная вещь, котораяслучается так, что когда я просто компилирую его без каких-либо оптимизаций или с оптимизацией первого уровня (-O), он работает просто отлично (я синхронизирую исполняемый файл и его примерно 1.4s с -O и 5.4s без какой-либо оптимизации.

Теперь, когда я добавляю -O2 или -O3 ключ для компиляции и определения времени получающегося исполняемого файла, он не останавливается (я проверял до 60s).

Любойидеи о том, что может быть причиной этого?

Ответы [ 3 ]

17 голосов
/ 19 августа 2011

Оптимизированный цикл создает бесконечный цикл, который зависит от вашего целочисленного переполнения знакового . Целочисленное переполнение со знаком является неопределенным поведением в C и не должно зависеть от него. Это не только может смутить разработчиков, но и оптимизировать их компилятором.

Сборка (без оптимизации): gcc -std=c99 -S -O0 main.c

_main:
LFB2:
    pushq   %rbp
LCFI0:
    movq    %rsp, %rbp
LCFI1:
    movl    $1, -4(%rbp)
    movl    $0, -8(%rbp)
    jmp L2
L3:
    incl    -8(%rbp)
L2:
    cmpl    $-2, -8(%rbp)
    jg  L3
    movl    $0, %eax
    leave
    ret


Сборка (оптимизированный уровень 3): gcc -std = c99 -S -O3 main.c

_main:
LFB2:
    pushq   %rbp
LCFI0:
    movq    %rsp, %rbp
LCFI1:
L2:
    jmp L2  #<- infinite loop
7 голосов
/ 19 августа 2011

Вы получите окончательный ответ, взглянув на двоичный файл, который создается (используя objdump или что-то еще).

Но, как уже отмечали другие, это возможно потому, что вы полагаетесь на неопределенное поведение. Одним из возможных объяснений является то, что компилятор может предположить, что i никогда не будет меньше -2, и поэтому полностью исключит условное выражение и преобразует его в бесконечный цикл.

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

2 голосов
/ 19 августа 2011

Дополнительную информацию о том, почему целочисленные переполнения не определены, можно найти здесь:

http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html

Поиск абзаца «Переполнение целого числа со знаком».

...