Оптимизация компилятора с параметрами - PullRequest
1 голос
/ 23 сентября 2010

Допустим, у вас есть некоторые функции в некоторых классах, которые вызываются вместе, как это

myclass::render(int offset_x, int offset_y)
{
    otherClass.render(offset_x, offset_y)
}

Этот шаблон будет повторяться некоторое время, возможно, через 10+ классов, поэтому мой вопрос:

Достаточно ли умны современные компиляторы C ++, чтобы признать, что везде, где программа хранит параметры функции - из того, что википедия говорит мне, она может изменяться в зависимости от размера параметра, но для функции с двумя параметрами регистр процессора кажется вероятным - не нуждается быть переопределенным новыми значениями?

Если нет, то мне, возможно, придется взглянуть на реализацию моих собственных методов

Ответы [ 6 ]

3 голосов
/ 23 сентября 2010

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

#include <iostream>

class B {
public:
    void F( int x, int y ) {
        std::cout << x << ", " << y << std::endl; 
    }
};

class A {
    B b;

public:
    void F( int x, int y ) {
        b.F( x, y );
    }
};

int main() {
        A a;
        a.F( 32, 64 );
}

заставляет компилятор (cl.exe из VS 2010, пустой проект, ванильная конфигурация Release) выполнитьпроизводить сборку, которая полностью встраивается в дерево вызовов;в основном вы получаете «push 40h, push 20h, вызов std :: operator <<.» </p>

Злоупотребление __declspec(noinline) заставляет cl.exe понять, что A :: F просто пересылает B :: F и определениеA :: F - это не что иное, как «вызов A :: F» без манипуляций со стеком или регистром (так что в этом случае он выполнил необходимую вам оптимизацию).Но обратите внимание, что мой пример чрезвычайно надуманный и поэтому ничего не говорит о способности компилятора делать это хорошо в целом, только то, что это можно сделать.

В вашем реальном сценарии вам придется изучитьразборка самостоятельно.В частности, необходимо учитывать параметр 'this' (обычно cl.exe передает его через регистр ECX) - если вы выполняете какие-либо манипуляции с переменными-членами класса, которые могут повлиять на результаты.

2 голосов
/ 23 сентября 2010

Да, это так.Компилятор выполняет анализ потока данных перед распределением регистров, отслеживая, какие данные находятся, где и в какое время.И он увидит, что местоположение arg0 содержит значение, которое должно быть в расположении arg0, чтобы вызвать следующую функцию, и поэтому нет необходимости перемещать данные.

1 голос
/ 23 сентября 2010

Несмотря на ваш комментарий, я думаю, что вставка имеет отношение к этой дискуссии.Я не верю, что компиляторы C ++ будут делать то, что вы просите (повторно использовать параметры в стеке), ЕСЛИ БЕЗ того, что они также полностью указывают на метод.

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

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

1 голос
/ 23 сентября 2010

Я не специалист, но это очень похоже на проблему идеальной пересылки , которая будет решена в следующем стандарте (C ++ 0x) с помощью rvalue-reference.

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

0 голосов
/ 23 сентября 2010

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

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

0 голосов
/ 23 сентября 2010

Если я правильно понимаю вопрос, вы спрашиваете: «Достаточно ли умены компиляторы, чтобы встроить простую функцию, подобную этой», и ответ на этот вопрос - да.Однако обратите внимание на неявный параметр this, который является частью вашей функции (потому что ваша функция является частью класса), поэтому он может быть не полностью встроенным, если уровень вызова достаточно глубокий.

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