На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
  
> Соглашения вызовов и оптимизация. , взгляд снизу
    Я недавно участвовал в беседе. И там обсуждался вопрос calling convention.
    Известно, что если функция видима из других единиц трансляции, то компилятор должен придерживаться определенного ABI, которое обычно документируется.
    А если функция "невидима", то может ли компилятор менять эти соглашения по своему усмотрению. И сталкивались ли вы со случаями, когда скажем GCC или MSVC применял для таких функций что-то иное, чем всякие stdcall, thiscall, fastcal и прочие xxxcall? Кроме известного инлайнинга.
      Судя по молчанию, никто не встречал подобного. Я тоже не встречал. Вероятно, это слишком накладно с точки зрения реализации этого типа оптимизации при не весьма очевидном профите. Встраивание вызовов даёт такой профит, и тут всё хорошо в плане оптимизаций и их реализации, но вот невстроенный вызов... тут, пожалуй, имеет смысл только лишь оптимизация стартовых адресов функций для повышения эффективности кеша и их взаимное относительное расположение для улучшения статистики кеша переходов. Это даст очевидный профит, на фоне которого жонглирование параметрами ABI будет просто незаметно.

      Добавлено
      Цитата applegame @
      А если функция "невидима" ...
      Не вполне точный термин. Есть internal linkage и no linkage. Ты какой имел в виду? Если последний, то я даже теряюсь, как для функций его можно бы получить в реальности.
        Цитата Qraizer @
        Судя по молчанию, никто не встречал подобного.

        Нечто похожее я встречал - кросс-компилер IAR иногда вообще вставлял функцию как "inline".
        А иногда наоборот - произвольно "вычленял" кусок из некой процедуры и делал этот кусок
        отдельной процедурой для общего использования.
        Turbo-C Borland 1988г умеет заменять far-процелуру на near в одном модуле.
        ---
        Теоретически такое возможно, но чтобы это выяснить надо подробно изучать
        ассемблерные листинги. Для микроконтроллеров это может иметь практический смысл.
        А для Виндус это не очень актуально..
        Могу добавить, что иногда VC Микрософт произвольно и по непонятному алгоритму
        начинает менять взаимное расположение (последовательность следования) процедур,
        при микроскопическом изменении в исходниках.
        х/з зачем.
        Сообщение отредактировано: ЫукпШ -
          В принципе применяемое по умолчанию соглашение близко к оптимуму - первые пара параметров передаются через регистры, остальные в стеке. Так что смысла менять его не много. Точки входа большинство компиляторов выравнивают уже на первой ступеньке оптимизации. Замена вызова на встраивание производится иногда даже для глобально видимых функций, в зависимости от её сложности. Так же объявленная inline функция, если оказывается слишком сложной для встраивания может быть скомпилирована, как нормальная и вызвана. Ограничено число встраиваний при рекурсивных вызовах. С некоторого не очень глубокого уровня вызывается отдельно расположенная функция.
            Цитата Qraizer @
            Не вполне точный термин. Есть internal linkage и no linkage. Ты какой имел в виду?
            Что такое no linkage, я не знаю. Я про internal linkage. Например глобальные функции объявленные как static.
            И о чем толкует чувак?
            Цитата
            It is a "convention" for a reason. Everybody has to follow the convention or you couldn't call your function from another module.

            However, if the function is not visible then GCC has options. It may inline the function or call it however it wants to. It might even split it into "hot" and "cold" parts and inline the hot code path. That usually only happens when building with profile guided optimization.

            If you want GCC to make optimizations like that, work on hiding your functions. If you are building an executable look at -fwhole-program. If you are building libraries look at -fvisibility=hidden. Also look into -flto.

            отсюда:
            https://stackoverflow.com/questions/2233124...ing-conventions
              Кстати, вспомнил интересную оптимизацию вызовов в Turbo C 2.0. В моделях памяти large и medium (в которых код каждой единицы трансляции размещался в отдельном сегменте) при вызове функции внутри единицы трансляции (в том же сегменте) компилятор использовал не ожидаемый CALL FAR PTR, а загонял в стек регистр кода (PUSH CS), после чего делал CALL NEAR PTR. Чем экономил байт памяти и несколько тактов процессора.
                Цитата applegame @
                Я про internal linkage. Например глобальные функции объявленные как static.
                Даже на такие функции ты можешь взять указатель и куда-то передать. Тип linkage относится только к именам сущностей, по которым к ним можно обращаться явно. Косвенный метод доступа этим критериям неподвластен. Фактически linkage является именно характеристикой имени, а не самой сущности.

                Добавлено
                Цитата applegame @
                Что такое no linkage, я не знаю.
                Цитата 3.5 Program and linkage
                2 A name is said to have linkage when it might denote the same object, reference, function, type, template, namespace or value as a name introduced by a declaration in another scope:
                • When a name has external linkage, the entity it denotes can be referred to by names from scopes of other translation units or from other scopes of the same translation unit.
                • When a name has internal linkage, the entity it denotes can be referred to by names from other scopes in the same translation unit.
                • When a name has no linkage, the entity it denotes cannot be referred to by names from other scopes.


                Добавлено
                Например, no linkage будут просто обычные локальные переменные. Но вот функцию no linkage я как-то с трудом представляю.
                Сообщение отредактировано: Qraizer -
                  Цитата Qraizer @
                  Даже на такие функции ты можешь взять указатель и куда-то передать.
                  Интересный вопрос. Соглашения о вызовах, насколько я понимаю, отданы на откуп компиляторам, а значит просто брать указатель на функцию и куда-то там передавать достаточно рискованно. Нужно согласовывать соглашения.
                    Вот именно. Пожалуй, это самый главный аргумент, чтобы компиляторы не пытались мутить с нестандартностью соглашений. Т.б. какой модификатор у указателя имеется, поинтер на именно такую функцию в него и можно вфигачить. Так что любые такие соглашения должны быть документированы.
                      Тем не менее разные компиляторы мутят по своему соглашения.
                        Соглашение о вызове важно тогда, когда приходится на стык двух разных компиляторов (или сессий компилирования одним и тем же компилятором). До тех пор пока мы в рамках одного проекта, оптимизатор волен делать всё что угодно.
                          Цитата Mr.Delphist @
                          До тех пор пока мы в рамках одного проекта, оптимизатор волен делать всё что угодно.

                          А вызовы функций из dll ?
                          Полагаю, что правильнее такая логика:
                          1. Везде, где cоглашение о вызове указано явно в исходнике, компилер не должен его менять.
                          2. Там, где явного указания не имеется, компилятор может решить вопрос по своему усмотрению.
                            Цитата ЫукпШ @
                            А вызовы функций из dll ?

                            Это и есть тот самый "стык" - соглашение о вызове важно, противоречащие ему оптимизации - низзя :blink:
                            0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                            0 пользователей:


                            Рейтинг@Mail.ru
                            [ Script execution time: 0,0387 ]   [ 17 queries used ]   [ Generated: 19.03.24, 11:17 GMT ]