Почему Mac ABI требует выравнивания стека на 16 байт для x86-32?
-
03-07-2019 - |
Вопрос
Я могу понять это требование для старых систем PPC RISC и даже для x86-64, но для старого проверенного x86?В этом случае стек должен быть выровнен только по границам в 4 байта.Да, некоторые инструкции MMX / SSE требуют выравнивания в 16 байт, но если это требование вызываемого абонента, то оно должно гарантировать правильность выравнивания.Зачем обременять каждый вызывающий абонент с этим дополнительным требованием?На самом деле это может привести к некоторому снижению производительности, поскольку каждый сайт вызова должен соответствовать этому требованию.Я что-то упускаю?
Обновить: После еще некоторого изучения этого вопроса и консультаций с некоторыми внутренними коллегами у меня появилось несколько теорий на этот счет:
- Согласованность между версиями операционной системы для PPC, x86 и x64
- Похоже, что GCC codegen теперь последовательно выполняет sub esp, xxx, а затем "перемещает" данные в стек, а не просто выполняет инструкцию "push".На самом деле это могло бы быть быстрее на некотором оборудовании.
- Хотя это немного усложняет работу сайтов вызовов, при использовании соглашения cdecl по умолчанию, в котором вызывающий объект очищает стек, дополнительных накладных расходов очень мало.
Проблема, с которой я сталкиваюсь с последним пунктом, заключается в том, что для соглашений о вызовах, которые полагаются на то, что вызываемый объект очищает стек, вышеуказанные требования действительно "уродует" кодеген.Например, какой-нибудь компилятор решил реализовать более быстрый стиль вызова на основе регистров для своего собственного внутреннего использования (т. Е. любой код, который не предназначен для вызова с других языков или источников)?Эта проблема с выравниванием стека может свести на нет некоторые улучшения производительности, достигнутые за счет передачи некоторых параметров в регистрах.
Обновить: До сих пор единственными реальными ответами была последовательность, но для меня это слишком простой ответ.У меня более чем 20-летний опыт работы с архитектурой x86, и если действительно причиной является согласованность, а не производительность или что-то другое конкретное, то я со всем уважением предполагаю, что требовать этого от разработчиков немного наивно.Они игнорируют почти три десятилетия инструментов и поддержки.Особенно, если они ожидают, что поставщики инструментов быстро и легко адаптируют свои инструменты для своей платформы (возможно, нет...IT является Apple ...) без необходимости перепрыгивать через несколько, казалось бы, ненужных обручей.
Я уделю этой теме еще день или около того, а затем закрою ее...
Похожие
Решение
Из "Справочного руководства по оптимизации архитектур Intel®64 и IA-32", раздел 4.4.2:
"Для достижения наилучшей производительности потоковые расширения SIMD и Streaming SIMD Extensions 2 требуют, чтобы их операнды памяти были выровнены по 16-байтовым границам.Невыровненные данные могут привести к значительному снижению производительности по сравнению с выровненными данными ".
Из Приложения D:
"Важно убедиться, что фрейм стека выровнен по 16-байтовой границе при вводе функции, чтобы локальные данные __m128, параметры и местоположения разлива регистра XMM были выровнены во время вызова функции".
Другие советы
Я не уверен, поскольку у меня нет доказательств из первых рук, но я полагаю, что причина в SSE.SSE выполняется намного быстрее, если ваши буферы уже выровнены по границе в 16 байт (movps vs movups), а любой x86 имеет по крайней мере sse2 для mac os x.Об этом может позаботиться пользователь приложения, но стоимость довольно значительна.Если общие затраты на то, чтобы сделать его обязательным в ABI, не слишком значительны, возможно, оно того стоит.SSE довольно широко используется в mac os X:ускорить фреймворк и т.д...
Я полагаю, это для того, чтобы поддерживать его в соответствии с x86-64 ABI.
Во-первых, обратите внимание, что выравнивание в 16 байт является исключением, введенным Apple в System V IA-32 ABI.
Выравнивание стека необходимо только при вызове системных функций, поскольку многие системные библиотеки используют расширения SSE или Altivec, которые требуют выравнивания в 16 байт.Я нашел явную ссылку в справочная страница libgmalloc.
Вы можете идеально обрабатывать свой фрейм стека так, как хотите, но если вы попытаетесь вызвать системную функцию со смещенным стеком, вы получите смещенный_stack_error Сообщение.
Редактировать: Для справки, вы можете избавиться от проблем с выравниванием при компиляции с помощью GCC, используя mstack-перестройка вариант.
Это вопрос эффективности.
Проверка того, что стек выровнен по 16 байтам в каждой функции, использующей новые инструкции SSE, увеличивает накладные расходы на использование этих инструкций, эффективно снижая производительность.
С другой стороны, постоянное выравнивание стека на 16 байт гарантирует, что вы можете свободно использовать инструкции SSE без снижения производительности.Это не требует затрат (стоимость, по крайней мере, указана в инструкциях).Это включает в себя только изменение константы в прологе функции.
Тратить впустую пространство стека дешево, это, вероятно, самая горячая часть кэша.
Я предполагаю, что Apple считает, что все просто используют XCode (gcc), который выравнивает стек для вас.Таким образом, требование выравнивания стека так, чтобы ядру не приходилось этого делать, - это просто микрооптимизация.
Хотя я не могу толком ответить на ваш вопрос о ТОМ, ПОЧЕМУ, вы можете найти полезными руководства на следующем сайте:
http://www.agner.org/optimize/
Что касается ABI, обратите особое внимание на:
http://www.agner.org/optimize/calling_conventions.pdf
Надеюсь, это полезно.
Хм, разве OS X ABI также не делала забавные RISC-подобные вещи, такие как передача небольших структур в регистрах?
Так что это указывает на согласованность с теорией других платформ.
Если подумать, API системного вызова FreeBSD также выравнивает 64-разрядные значения.(например, напримерlseek и mmap)
Для того, чтобы поддерживать согласованность в ядре.Это позволяет загружать одно и то же ядро на нескольких архитектурах без внесения изменений.
Не уверен, почему никто не рассмотрел возможность легкой переносимости с устаревшей платформы на базе PowerPC?
Читать это:
А затем увеличил масштаб до "32-разрядных соглашений о вызове функций PowerPC" и, наконец, это:
"Это режимы выравнивания при внедрении, доступные в 32-разрядной версии Среда PowerPC:
Режим выравнивания мощности базируются на правилах выравнивания, используемого Компилятор IBM XLC, в операционной системе AIX.Это режим выравнивания по умолчанию для версии GCC с архитектурой PowerPC, используемой в AIX и Mac OS X.Поскольку этот режим, скорее всего, будет совместим между компиляторами PowerPC-архитектуры разных производителей, он обычно используется со структурами данных, которые совместно используются различными программами."
Учитывая унаследованный опыт OSX на базе PowerPC, переносимость является важным фактором - она диктует следовать соглашению вплоть до компилятора AIX XLC.Когда вы думаете с точки зрения необходимости убедиться, что все инструменты и приложения будут работать вместе с минимальными доработками, я думаю, что важно придерживаться того же устаревшего ABI, насколько это возможно.
Это дает философию, и дальнейшее чтение - это явно упомянутое правило ("Пролог и эпилог").:
Вызываемая функция отвечает за выделение своего собственного фрейма стека, гарантируя сохранение 16-байтового выравнивания в стеке .Эта операция выполняется разделом кода, называемым prolog, который компилятор помещает перед телом подпрограммы.После тела подпрограммы компилятор помещает эпилог, чтобы восстановить процессор в состояние, в котором он находился до подпрограммы вызов.