[Программирование, C++] Ваш ABI, скорее всего, неверен (перевод)

Автор Сообщение
news_bot ®

Стаж: 6 лет 3 месяца
Сообщений: 27286

Создавать темы news_bot ® написал(а)
07-Июн-2021 23:33


ABI, или двоичный интерфейс приложения (Application Binary Interface), определяет способ взаимодействия двоичных файлов друг с другом на конкретной платформе и включает соглашение о вызовах. Большинство ABI имеют один конструктивный недостаток, который снижает производительность.Давайте начнем с рассмотрения ABI System V для процессоров линейки x86. ABI классифицирует аргументы функции по ряду различных категорий; мы будем рассматривать только две:INTEGER: Этот класс состоит из целочисленных типов, которые помещаются в один из регистров общего назначения.MEMORY: Этот класс состоит из типов, которые будет переданы в память и возвращены через стек.Я не буду подробно описывать правила классификации аргументов; достаточно сказать, что в общем смысле:
  • Целые числа, указатели и небольшие структуры имеют класс INTEGER и передаются в регистры.
  • Если структура слишком большая, она имеет класс MEMORY и передается в стек.
  • Если аргументов слишком много, те, которые не помещаются в регистры, будут переданы в стек.
Другими словами, передача больших структур по значению влечет за собой большие копии, и это меня огорчает.Но что в этом плохого? Конечно, мы можем просто делать то, что делали во времена наивных компиляторов, и передавать структуры по указателю. К сожалению, это больше не работает; компиляторы сейчас умны, и им не нравится, когда объекты имеют псевдонимы.Например:
void foo(int*);
void bar(void);
int x = 5;
foo(&x);   // насколько нам известно, foo мог сохранить &x в глобальной переменной
x = 7;
bar();       // через которую, bar мог изменить x
return x;   // что означает, что это должно превратиться в фактическую загрузку; он не может быть обернут в константу
       // (Этого не произошло бы, если бы x был передан по значению, но, как мы знаем, это не всегда приемлемо для больших структур.)
restrict во спасение! Если бы параметр foo был аннотирован с restrict, foo не смог бы использовать его псевдоним (C11§6.7.3.1p4,11). К сожалению, компиляторы обычно не в курсе об этом факте. Более того, поскольку принудительного применения типа restrict в C нет, в общем понимании на добросовестность атрибута рассчитывать нельзя, даже если он может быть правильным в тех случаях, когда ABI C используется для связи между языками с более строгой типизацией.И действительно, ABI должен поступать правильно по умолчанию. void foo(struct bla) намного легче читать, чем void foo(const struct bla *restrict), не говоря уже о том, что он лучше передает намерение и фактически обеспечивает более сильную семантическую гарантию.Что ж, такова System V. Как обстоят дела с другими ABI? Microsoft похожа, но она передает структуры с указателем: Структуры или объединения [не малых] размеров передаются как указатель на память, выделенную вызывающей стороной.Это дает вам некоторую гибкость (хотя это также, вероятно, немного сбивает с толку переименователь памяти), но не решает реальной проблемы. «Память, выделенная вызывающей стороной», принадлежит вызываемой стороне, которая может изменять ее по своему желанию, поэтому вызывающей стороне по-прежнему необходимо излишнее копирование.Больше ABI! ARM (извините, AAA arch 64):Если тип аргумента является составным типом, размер которого превышает 16 байт, то аргумент копируется в память, выделенную вызывающей стороной, и аргумент заменяется указателем на копию.RISC-V:Агрегаты размером более 2×XLEN бит [примечание: какого черта вы говорите о битах?] передаются по ссылке и заменяются в списке аргументов адресом.[...]Аргументы, переданные по ссылке, могут быть изменены вызываемой стороной.PowerPC:Все [неоднородное] агрегаты передаются в последовательные регистры общего назначения (GPR), в регистры общего назначения и в память, или в память.MIPS n32:Структуры (structs), объединения (unions),или другие составные типы рассматриваются как последовательность двойных слов (doublewords), и передаются в целые регистры или регистры с плавающей запятой, как если бы они были простыми скалярными параметрами в той степени, в которой они помещаются, с любым избытком в стеке, упакованным в соответствии с обычной структурой памяти объекта.Все это повторения одних и тех же двух ошибок.Правильно установленный ABI должен передавать большие структуры по immutable ссылке, по большому счету избегая копирования. В случае, если требуется копия, это обычно происходит только один раз на вызываемой стороне, вместо того, чтобы повторяться каждой вызывающей стороной. Вызываемая сторона также обладает большей гибкостью и может копировать только те части структуры, которые фактически изменяются.Мотайте на ус, будущие создатели ABI!Ссылки:
Перевод материала подготовлен в рамках курса "C++ Developer. Professional". Если вам интересно узнать больше о курсе, приглашаем на день открытых дверей онлайн, на котором можно будет узнать о формате и программе курса, познакомиться с преподавателем. - ЗАПИСАТЬСЯ НА DEMO DAY

===========
Источник:
habr.com
===========

===========
Автор оригинала: elronnd.net
===========
Похожие новости: Теги для поиска: #_programmirovanie (Программирование), #_c++, #_programmirovanie (программирование), #_cplusplus, #_abi, #_blog_kompanii_otus (
Блог компании OTUS
)
, #_programmirovanie (
Программирование
)
, #_c++
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 10-Май 12:27
Часовой пояс: UTC + 5