Изменения в конструкции цикла gcc в коде сборки - PullRequest
1 голос
/ 11 октября 2011

Почему компилятор gcc преобразует циклы while в конструкции do-while при создании кода сборки? Я знаю, что любой цикл while можно переписать как do-while, например, в c

while (test) { ... }

можно переписать как

if ( !test ) goto skip;
do {
. . .
} while ( test );
skip:

Ответы [ 2 ]

4 голосов
/ 12 октября 2011

Основываясь на ответе анатолига, вы можете задаться вопросом , почему конструкция do-while более эффективна, особенно если учесть, что, как показано, тест был продублирован (поэтому сгенерированный код больше).Ответ заключается в том, что очень часто проверочное выражение всегда подтверждается при вводе в цикл, поэтому

    if ( !test ) goto skip;
loop:
    . . . // loop body
    if ( !test ) goto loop;
skip:
    . . . // continue the program

можно упростить до

loop:
    . . . // loop body
    if ( !test ) goto loop;
    . . . // continue program

Теперь почему бы не сделать это вто же самое время, что и исходное преобразование, и избегать исходного преобразования, если компилятор не может доказать, что цикл будет повторяться хотя бы один раз?Потому что алгоритм, который доказывает цикл будет по крайней мере один раз, на самом деле является общим оптимизатором if-условия.Обычная последовательность оптимизаций выглядит примерно так:

  1. Преобразуйте все циклы в "каноническую" форму (более или менее, как показано в первом блоке кода выше)
  2. Делайте лоты имного оптимизаций, которые ожидают циклы в этой канонической форме, такие как показанное исключение оператора if.
  3. После того, как вы закончите со всем, что заботится о циклах как таковых, попытайтесь деканонизировать, где это устранит избыточность.

Еще одна вещь, которую нужно знать, это то, что иногда дублирующий тест преднамеренно оставляют, потому что компилятор ожидает, что это приведет к лучшему поведению во время выполнения.Например, если у компилятора есть основания полагать, что цикл обычно повторяется много раз, но не может доказать, что цикл всегда хотя бы один раз, тогда инструкция условного перехода вышецикл почти всегда провалится, а условная ветвь под циклом почти всегда будет прыгать.В таком случае их разделение может повысить точность предсказания ветвления ЦП.Точность предсказания ветвления уступает только удобству кэширования как ограничивающему фактору скорости на современных процессорах с ошибками.

3 голосов
/ 12 октября 2011

В целом цикл do-while более эффективен, чем цикл while.Поскольку компилятор хочет создать быструю (а не читаемую) программу, он конвертирует большинство while циклов в do-while.

Фактически, реализация цикла while использует только if и goto (приблизительно на языке ассемблера) можно сделать следующим образом:

start:
    if ( !test ) goto skip;
    . . . // loop body
    goto start;
skip:
    ; // continue the program

Это эквивалентно, но, вероятно, менее эффективно, чем реализация do-while (поскольку последняя имеет на 1 строку кода внутри цикла):

    if ( !test ) goto skip;
loop:
    . . . // loop body
    if ( !test ) goto loop;
skip:
    ; // continue the program
...