Я не вижу очевидных пропущенных оптимизаций в вашем выводе -O1
.За исключением, конечно, установки RBP в качестве указателя кадра, но вы использовали -fno-omit-frame-pointer
, так что вы ясно знаете, почему GCC не оптимизировал это.
Функция не имеет локальных переменных
Ваша функция является нестатической функцией-членом класса, поэтому имеет один неявный аргумент: this
in rdi
.Какой g ++ выливается в стек из-за -O0
.Аргументы функций считаются локальными переменными.
Как циклическое перемещение без эффекта улучшает процесс отладки.Пожалуйста, уточните.
Для улучшения отладки C / C ++ : форматы debug-info могут описывать только местоположение переменной C относительно RSP или RBP, а не регистр, в котором она в настоящее время находится.Таким образом, вы можете изменить любую переменную с помощью отладчика и продолжить, получая ожидаемые результаты, как если бы вы делали это на абстрактной машине C ++.Каждый оператор скомпилирован в отдельный блок asm без значений в регистрах (забавный факт: кроме register int foo
: это ключевое слово влияет на код режима отладки gen).
Почему clang производит неэффективноasm с -O0 (для этой простой суммы с плавающей запятой)? относится также к G ++ и другим компиляторам.
Какие параметры мне нужно установить?
Если вы читаете / отлаживаете asm, используйте по крайней мере -Og
или выше , чтобы отключить режим spill-everything-между-между-операторами отладки режима -O0
.Желательно -O2
или -O3
, если вы не хотите видеть еще больше пропущенных оптимизаций, чем при полной оптимизации.Но -Og
или -O1
выполнит распределение регистров и создаст вменяемые циклы (с условной ветвью внизу) и различные простые оптимизации.Хотя все еще не является стандартным глазком для обнуления xor.
Как удалить "шум" из вывода сборки GCC / clang? объясняет, как писать функции, принимающие аргументыи вернуть значение, чтобы вы могли писать функции, которые не оптимизируются.
Загрузка в RAX, а затем movq %rax, %rdi
- это просто побочный эффект -O0
.GCC тратит так мало времени на оптимизацию внутренних представлений программной логики в GIMPLE и / или RTL (до создания ассемблера x86), что даже не замечает, что он мог изначально загрузиться в RDI.Частью -O0
является быстрая компиляция и последовательная отладка.
Почему оператор subq $8, %rsp
вообще генерируется?
Поскольку ABI требует выравнивания стека 16 байтов перед call
инструкцией , и эта функция выполняла четное число 8-байтовых push
es.(call
сам выдвигает обратный адрес).Он уйдет на -O1
без -fno-omit-frame-pointer
, потому что вы не заставляете g ++ использовать push / pop RBP, а также регистр с сохранением вызовов, который ему действительно необходим.
Почему System V /AMD64 ABI требует выравнивания стека 16 байт?
Интересный факт: clang будет часто использовать фиктивный push %rcx
/ pop
или что-то в зависимости от параметров -mtune
вместо 8-байтовыхsub.
Если бы это была листовая функция, g ++ просто использовал бы красную зону ниже RSP для локальных, даже на -O0
. Почему в этом прологе функции нет инструкции "sub rsp" и почему параметры функции хранятся с отрицательным смещением rbp?
В неоптимизированном коде это не редкостьдля G ++ выделить дополнительные 16 байтов, которые он никогда не использует .Даже иногда с включенной оптимизацией g ++ слишком сильно округляет размер выделения стека, стремясь к 16-байтовой границе.Это ошибка пропущенной оптимизации.например, Распределение памяти и адресация в сборке