Поведение развертки цикла в GCC
этот вопрос частично является последующим вопросом к разворачивание петли GCC 5.1.
по словам документация GCC, и, как указано в моем ответе на вышеуказанный вопрос, флаги, такие как -funroll-loops
поворот на " полный пилинг петли (т. е. полное удаление петель с небольшим постоянным числом итераций)". Поэтому, когда такой флаг включен, компилятор может развернуть цикл, если он определяет, что это оптимизирует выполнение данного фрагмента кода.
тем не менее, я заметил в одном из моих проектов, что GCC иногда разворачивает петли даже если соответствующие флаги не были включены. Например, рассмотрим следующий простой фрагмент кода:
int main(int argc, char **argv)
{
int k = 0;
for( k = 0; k < 5; ++k )
{
volatile int temp = k;
}
}
при компиляции с -O1
, цикл развернут и следующий код сборки генерируется с любой современной версией GCC:
main:
movl , -4(%rsp)
movl , -4(%rsp)
movl , -4(%rsp)
movl , -4(%rsp)
movl , -4(%rsp)
movl , %eax
ret
даже при компиляции с дополнительным -fno-unroll-loops -fno-peel-loops
чтобы убедиться, что флаги отключен, GCC неожиданно по-прежнему выполняет развертывание цикла на примере, описанном выше.
-O0
)?
интересно лязгом компилятор имеет ожидаемое поведение здесь и, похоже, выполняет развертывание только тогда, когда -funroll-loops
включен, а не в других случаях.
заранее спасибо, любые дополнительные идеи по этому вопросу будут очень признательны!
1 ответов
почему GCC выполняет развертывание цикла, даже если флаги соответствующее поведение отключено?
подумайте об этом с прагматической точки зрения: что вы хотите при передаче такого флага компилятору? Ни один разработчик C++ не попросит GCC развернуть или не развернуть циклы, просто ради того, чтобы иметь циклы или нет в сборочном коде, есть цель. Цель с -fno-unroll-loops
, например, пожертвовать немного скорости, чтобы уменьшить размер вашего двоичного файла, если вы разрабатываете встроенное программное обеспечение с ограниченным объемом памяти. С другой стороны, цель с -funrool-loops
это сказать компилятору, что вас не волнует размер вашего двоичного файла, поэтому он не должен стесняться разворачивать циклы.
но это не означает, что компилятор будет втемную разверните или не все ваши петли!
в вашем примере причина проста: цикл содержит только один инструкция-несколько байтов на любых платформах - и компилятор знает, что это пренебрежимо мало и в любом случае займет почти тот же размер, что и код сборки, необходимый для цикла (sub
+ mov
+ jne
на x86-64).
вот почему gcc 6.2, с -O3 -fno-unroll-loops
получается этот код:
int mul(int k, int j)
{
for (int i = 0; i < 5; ++i)
volatile int k = j;
return k;
}
... к следующему коду сборки:
mul(int, int):
mov DWORD PTR [rsp-0x4],esi
mov eax,edi
mov DWORD PTR [rsp-0x4],esi
mov DWORD PTR [rsp-0x4],esi
mov DWORD PTR [rsp-0x4],esi
mov DWORD PTR [rsp-0x4],esi
ret
он не слушает вас, потому что он (почти, в зависимости от архитектуры) не изменит размер двоичного файла, но это быстрее. Однако, если вы увеличить укусил счетчик петель...
int mul(int k, int j)
{
for (int i = 0; i < 20; ++i)
volatile int k = j;
return k;
}
... он следует вашему намеку:
mul(int, int):
mov eax,edi
mov edx,0x14
nop WORD PTR [rax+rax*1+0x0]
sub edx,0x1
mov DWORD PTR [rsp-0x4],esi
jne 400520 <mul(int, int)+0x10>
repz ret
вы получите такое же поведение, если вы держите счетчик циклов в 5
но вы добавить некоторый код в цикл.
подводя итог, подумайте обо всех этих флагах оптимизации как подсказка для компилятора, и с прагматической точки зрения разработчика. Это всегда компромисс, и когда вы создаете программное обеспечение, вы никогда хочу попросить все или нет развертывание циклов.
и наконец, еще один очень похожий пример:-f(no-)inline-functions
флаг. Я борюсь каждый день с компилятором для inline (или нет!) некоторые из моих функций (с inline
ключевого слова __attribute__ ((noinline))
С GCC), и когда я проверяю код сборки, я вижу, что этот smartass все еще делает иногда то, что он хочет, когда я хочу встроить функцию, которая определенно слишком длинна для ее вкуса. И большую часть времени, это право что делать, и я счастлив!