Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[34.236.152.203] |
|
Сообщ.
#1
,
|
|
|
Я недавно участвовал в беседе. И там обсуждался вопрос calling convention.
Известно, что если функция видима из других единиц трансляции, то компилятор должен придерживаться определенного ABI, которое обычно документируется. А если функция "невидима", то может ли компилятор менять эти соглашения по своему усмотрению. И сталкивались ли вы со случаями, когда скажем GCC или MSVC применял для таких функций что-то иное, чем всякие stdcall, thiscall, fastcal и прочие xxxcall? Кроме известного инлайнинга. |
Сообщ.
#2
,
|
|
|
Судя по молчанию, никто не встречал подобного. Я тоже не встречал. Вероятно, это слишком накладно с точки зрения реализации этого типа оптимизации при не весьма очевидном профите. Встраивание вызовов даёт такой профит, и тут всё хорошо в плане оптимизаций и их реализации, но вот невстроенный вызов... тут, пожалуй, имеет смысл только лишь оптимизация стартовых адресов функций для повышения эффективности кеша и их взаимное относительное расположение для улучшения статистики кеша переходов. Это даст очевидный профит, на фоне которого жонглирование параметрами ABI будет просто незаметно.
Добавлено Цитата applegame @ Не вполне точный термин. Есть internal linkage и no linkage. Ты какой имел в виду? Если последний, то я даже теряюсь, как для функций его можно бы получить в реальности. А если функция "невидима" ... |
Сообщ.
#3
,
|
|
|
Цитата Qraizer @ Судя по молчанию, никто не встречал подобного. Нечто похожее я встречал - кросс-компилер IAR иногда вообще вставлял функцию как "inline". А иногда наоборот - произвольно "вычленял" кусок из некой процедуры и делал этот кусок отдельной процедурой для общего использования. Turbo-C Borland 1988г умеет заменять far-процелуру на near в одном модуле. --- Теоретически такое возможно, но чтобы это выяснить надо подробно изучать ассемблерные листинги. Для микроконтроллеров это может иметь практический смысл. А для Виндус это не очень актуально.. Могу добавить, что иногда VC Микрософт произвольно и по непонятному алгоритму начинает менять взаимное расположение (последовательность следования) процедур, при микроскопическом изменении в исходниках. х/з зачем. |
Сообщ.
#4
,
|
|
|
В принципе применяемое по умолчанию соглашение близко к оптимуму - первые пара параметров передаются через регистры, остальные в стеке. Так что смысла менять его не много. Точки входа большинство компиляторов выравнивают уже на первой ступеньке оптимизации. Замена вызова на встраивание производится иногда даже для глобально видимых функций, в зависимости от её сложности. Так же объявленная inline функция, если оказывается слишком сложной для встраивания может быть скомпилирована, как нормальная и вызвана. Ограничено число встраиваний при рекурсивных вызовах. С некоторого не очень глубокого уровня вызывается отдельно расположенная функция.
|
Сообщ.
#5
,
|
|
|
Цитата Qraizer @ Что такое no linkage, я не знаю. Я про internal linkage. Например глобальные функции объявленные как static.Не вполне точный термин. Есть internal linkage и no linkage. Ты какой имел в виду? И о чем толкует чувак? Цитата 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 |
Сообщ.
#6
,
|
|
|
Кстати, вспомнил интересную оптимизацию вызовов в Turbo C 2.0. В моделях памяти large и medium (в которых код каждой единицы трансляции размещался в отдельном сегменте) при вызове функции внутри единицы трансляции (в том же сегменте) компилятор использовал не ожидаемый CALL FAR PTR, а загонял в стек регистр кода (PUSH CS), после чего делал CALL NEAR PTR. Чем экономил байт памяти и несколько тактов процессора.
|
Сообщ.
#7
,
|
|
|
Цитата applegame @ Даже на такие функции ты можешь взять указатель и куда-то передать. Тип linkage относится только к именам сущностей, по которым к ним можно обращаться явно. Косвенный метод доступа этим критериям неподвластен. Фактически linkage является именно характеристикой имени, а не самой сущности.Я про internal linkage. Например глобальные функции объявленные как static. Добавлено Цитата 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: Добавлено Например, no linkage будут просто обычные локальные переменные. Но вот функцию no linkage я как-то с трудом представляю. |
Сообщ.
#8
,
|
|
|
Цитата Qraizer @ Интересный вопрос. Соглашения о вызовах, насколько я понимаю, отданы на откуп компиляторам, а значит просто брать указатель на функцию и куда-то там передавать достаточно рискованно. Нужно согласовывать соглашения. Даже на такие функции ты можешь взять указатель и куда-то передать. |
Сообщ.
#9
,
|
|
|
Вот именно. Пожалуй, это самый главный аргумент, чтобы компиляторы не пытались мутить с нестандартностью соглашений. Т.б. какой модификатор у указателя имеется, поинтер на именно такую функцию в него и можно вфигачить. Так что любые такие соглашения должны быть документированы.
|
Сообщ.
#10
,
|
|
|
Тем не менее разные компиляторы мутят по своему соглашения.
|
Сообщ.
#11
,
|
|
|
Соглашение о вызове важно тогда, когда приходится на стык двух разных компиляторов (или сессий компилирования одним и тем же компилятором). До тех пор пока мы в рамках одного проекта, оптимизатор волен делать всё что угодно.
|
Сообщ.
#12
,
|
|
|
Цитата Mr.Delphist @ До тех пор пока мы в рамках одного проекта, оптимизатор волен делать всё что угодно. А вызовы функций из dll ? Полагаю, что правильнее такая логика: 1. Везде, где cоглашение о вызове указано явно в исходнике, компилер не должен его менять. 2. Там, где явного указания не имеется, компилятор может решить вопрос по своему усмотрению. |
Сообщ.
#13
,
|
|
|
Цитата ЫукпШ @ А вызовы функций из dll ? Это и есть тот самый "стык" - соглашение о вызове важно, противоречащие ему оптимизации - низзя |