Какие реальные наборы правил используются компиляторами, чтобы решить, следует ли встроить функцию? - PullRequest
2 голосов
/ 10 февраля 2011

У нас есть макрос для сигнализации об ошибках в общей библиотеке утилит, который выглядит следующим образом:

#define OurMacro( condition ) \
    if( condition ) { \
    } else { \
        CallExternalFunctionThatWillThrowAnException( parametersListHere ); \
    } \

То, что я называю parametersListHere - это список констант и макросов, разделенных запятыми, который заполняется компилятором при каждом расширении макроса.

Этот вызов функции всегда преобразуется в вызов - реализация функции не предоставляется компилятору. Функция имеет шесть параметров, и в конфигурации отладки все они имеют значимые значения, в то время как в конфигурации выпуска только два имеют значащие значения, а другим передаются те же значения по умолчанию.

Обычно условие выполняется, поэтому мне все равно, насколько быстро выполняется вызов, меня интересует только раздувание кода. Для вызова этой функции с 6 параметрами требуется семь инструкций x86 (6 push es и одна call), и ясно, что 4 из этих push es можно избежать, если сигнатура функции имеет только два параметра - это может быть сделано путем введения промежуточной функции "gate", реализованной таким образом, что ее реализация не видна компилятору.

Мне нужно оценить, должен ли я настаивать на этом изменении. Пока что основное улучшение, на которое я рассчитываю, заключается в том, что при уменьшении количества параметров при каждом вызове будет сброшено 4 инструкции, что означает, что код, окружающий расширение макроса, станет меньше, и компилятор с большей вероятностью встроит его в код и будет оптимизировать выдаваемый код. *

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

Могу ли я увидеть какой-то точный набор правил того, как внутренние функции функции влияют на решение компилятора при вставке?

Ответы [ 3 ]

3 голосов
/ 10 февраля 2011

GCC имеет довольно большой набор опций, раскрывающих, как работает их процесс, задокументировано здесь . Это, конечно, не точно, учитывая, что со временем оно будет изменено и зависит от процессора.

Первое правило: «их тело меньше ожидаемого кода вызова функции». Второе правило - «статические функции, вызываемые один раз».

Существуют также параметры, влияющие на процесс прокалывания, например, max-inline-insns-single. insn является псевдоинструкцией в компиляторе GCC и используется здесь как мера сложности функции. Документация по параметру max-inline-insns-auto проясняет, что ручное объявление функции inline может привести к ее рассмотрению для встраивания, даже если она слишком велика для автоматического встраивания.

Встраивание не является процессом "все или ничего", так как есть флаг -fpartial-inlining.

Конечно, вы не можете рассматривать встраивание в изоляции. Common Subexpression Elission (CSE) делает код проще. Это этап оптимизации, который может сделать функцию достаточно маленькой, чтобы ее можно было встроить. После встраивания могут быть обнаружены новые общие подвыражения, так что проход CSE должен быть запущен снова, что, в свою очередь, может вызвать дальнейшее встраивание. И CSE - не единственная оптимизация, требующая перезапуска.

1 голос
/ 10 февраля 2011

Если вы используете Visual C ++, вы можете использовать __ forceinline to force компилятор для встроенной функции.

1 голос
/ 10 февраля 2011

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

В некоторых компиляторах есть механизм, с помощью которого вы можете отметить, что вы действительно хотите использовать функциюбыть встроенным, например, MSVC ++ имеет __forceinline.

...