Оптимизация компилятора GNU - PullRequest
3 голосов
/ 15 ноября 2011

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

 string foo = "bar";
 for(int i = 0; i < foo.length(); i++){
     //some code that does not modify the length of foo
 }

Будет ли компилятор GNU достаточно умным, чтобы понять, что длина foo не меняется в течение этого цикла, и заменить вызов foo.length()с правильным значением?Или foo.length() будет вызываться для каждого i сравнения?

Ответы [ 4 ]

7 голосов
/ 15 ноября 2011

Так как Mysticial и Kerrek по праву предлагают заглянуть в сгенерированную сборку, вот пример:

#include <string>
using namespace std;

int does_clang_love_me(string foo) {
    int j = 0;
    for (int i = 0; i < foo.length(); i++) {
        j++;
    }
    return j;
}

Я сохранил приведенный выше код в test.cpp и скомпилировал его так:

$ clang++ -o test.o -Os -c test.cpp

Ключ -Os указывает clang попытаться оптимизировать код до наименьшего размера.GCC имеет соответствующий переключатель, который вы можете использовать.Чтобы увидеть сборку, я нажал на получившийся объектный файл с помощью otool, поскольку в данный момент я использую Mac.Другие платформы имеют аналогичные инструменты.

$ otool -tv test.o

test.o:
(__TEXT,__text) section
__Z16does_clang_love_meSs:
0000000000000000    pushq   %rbp
0000000000000001    movq    %rsp,%rbp
0000000000000004    movq    (%rdi),%rax
0000000000000007    movq    0xe8(%rax),%rcx
000000000000000b    xorl    %eax,%eax
000000000000000d    testq   %rcx,%rcx
0000000000000010    je  0x0000001e
0000000000000012    cmpq    $0x01,%rcx
0000000000000016    movl    $0x00000001,%eax
000000000000001b    cmoval  %ecx,%eax
000000000000001e    popq    %rbp
000000000000001f    ret

Это как сказал мистик;это просто переменный доступ.

6 голосов
/ 15 ноября 2011

Единственный способ узнать наверняка - это попробовать и взглянуть на сборку.

Я предполагаю, что если вызов length() является встроенным, то Loop Invariant Code Motion выведет из цикла внутренние компоненты length() и заменит его единственной переменной.

Во-вторых, это может быть даже спорным.Размер строки, вероятно, просто простое поле в классе string, которое находится в стеке.Так что простое встраивание вызова в length() уже приведет к уменьшению вызова до простого доступа к переменной.

EDIT: В этом последнем случае даже не имеет значения,или не длина foo изменяется внутри цикла.Получение длины строки - это просто доступ к переменной.

2 голосов
/ 15 ноября 2011

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

То, что происходит в реальном примере, необходимо анализировать в каждом конкретном случае. Просто посмотрите на сборку, если вам интересно.

Типичный способ принудительного подъема - это просто сделать это вручную:

for (unsigned int i = 0, end = s.length(); i != end; ++i)

Возможно, вы также хотели бы рассмотреть современный for (char & c : s) в качестве альтернативы.

0 голосов
/ 15 ноября 2011

Честно говоря, я не знаю точно, как gcc оптимизирует этот фрагмент кода.Но перемещение кода избыточности за пределы цикла называется «Устранение частичной избыточности».Перемещение foo.length () за пределы цикла, которое называется движением инвариантного кода цикла, является одной из форм устранения частичной избыточности.Пожалуйста, взгляните на раздел 9.5 Книги Дракона (я также читаю эту главу), в котором подробно описывается, как решать подобные проблемы с помощью анализа потока данных.Вот слайд из Стэндфордского университета: http://suif.stanford.edu/~courses/cs243/lectures/l5.pdf. Надеюсь, что это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...