Вопрос не имеет смысла.
Если вы подумаете о встраивании и его последствиях, вы поймете это:
- Предотвращает вызов функции (со всем сохранением регистра/ frame frame)
- Предоставляет оптимизатору больше контекста (мертвые хранилища, мертвый код, удаление общего подвыражения ...)
- Дублирует код (раздувает кэш команд и размер исполняемого файла,среди прочего)
При принятии решения о включении или нет, компилятор, таким образом, выполняет балансировку между созданным потенциальным раздувом и ожидаемым увеличением скорости.На это действие балансировки влияют опции: для gcc -O3
означает оптимизацию по скорости, в то время как -Oz
означает оптимизацию по размеру, при встраивании они имеют квази противоположное поведение!
Следовательно, важен не «уровень вложенности»«это номер инструкции (возможно, взвешенный, поскольку не все созданы равными).
Это означает, что простая функция пересылки:
int foo(int a, int b) { return foo(a, b, 3); }
по существу« прозрачна »от точки вставкизрения.
С другой стороны, функция, считающая сто строк кода, вряд ли будет встроена.За исключением того, что static
свободные функции, вызываемые только один раз, являются квази-систематически встроенными, поскольку в этом случае это не создает никакого дублирования.
Из этих двух примеров мы получаем догадку о том, как ведет себя эвристика:
- чем меньше инструкций у функции, тем лучше для ввода
- чем реже она вызывается, тем лучше для вставки
После этого они являются параметрами, которые выдолжна быть в состоянии установить влияние так или иначе (MSVC как __force_inline
, который сильно намекает на inling, gcc
, поскольку они -finline-limit
помечают, чтобы "поднять" порог на счетчике команд, и т. д ...)
По касательной: знаете ли вы о частичное встраивание ?
Он был введен в gcc в 4.6.Идея, как следует из названия, состоит в том, чтобы частично встроить функцию.Главным образом, чтобы избежать накладных расходов на вызов функции, когда функция «охраняется» и может (в некоторых случаях) возвращаться почти сразу.
Например:
void foo(Bar* x) {
if (not x) { return; } // null pointer, pfff!
// ... BIG BLOC OF STATEMENTS ...
}
void bar(Bar* x) {
// DO 1
foo(x);
// DO 2
}
могла бы быть оптимизирована"as:
void foo@0(Bar* x) {
// ... BIG BLOC OF STATEMENTS ...
}
void bar(Bar* x) {
// DO 1
if (x) { foo@0(x); }
// DO 2
}
Конечно, снова применяются эвристики для встраивания, но они применяются более избирательно!
И, наконец, если вы не используете WPO (оптимизация всей программы)или LTO (оптимизация времени соединения), функции могут быть встроены, только если их определение находится в том же TU (блок перевода), что и сайт вызова.