Почему Mac ABI требует выравнивания стека на 16 байт для x86-32?

StackOverflow https://stackoverflow.com/questions/612443

Вопрос

Я могу понять это требование для старых систем PPC RISC и даже для x86-64, но для старого проверенного x86?В этом случае стек должен быть выровнен только по границам в 4 байта.Да, некоторые инструкции MMX / SSE требуют выравнивания в 16 байт, но если это требование вызываемого абонента, то оно должно гарантировать правильность выравнивания.Зачем обременять каждый вызывающий абонент с этим дополнительным требованием?На самом деле это может привести к некоторому снижению производительности, поскольку каждый сайт вызова должен соответствовать этому требованию.Я что-то упускаю?

Обновить: После еще некоторого изучения этого вопроса и консультаций с некоторыми внутренними коллегами у меня появилось несколько теорий на этот счет:

  1. Согласованность между версиями операционной системы для PPC, x86 и x64
  2. Похоже, что GCC codegen теперь последовательно выполняет sub esp, xxx, а затем "перемещает" данные в стек, а не просто выполняет инструкцию "push".На самом деле это могло бы быть быстрее на некотором оборудовании.
  3. Хотя это немного усложняет работу сайтов вызовов, при использовании соглашения cdecl по умолчанию, в котором вызывающий объект очищает стек, дополнительных накладных расходов очень мало.

Проблема, с которой я сталкиваюсь с последним пунктом, заключается в том, что для соглашений о вызовах, которые полагаются на то, что вызываемый объект очищает стек, вышеуказанные требования действительно "уродует" кодеген.Например, какой-нибудь компилятор решил реализовать более быстрый стиль вызова на основе регистров для своего собственного внутреннего использования (т. Е. любой код, который не предназначен для вызова с других языков или источников)?Эта проблема с выравниванием стека может свести на нет некоторые улучшения производительности, достигнутые за счет передачи некоторых параметров в регистрах.

Обновить: До сих пор единственными реальными ответами была последовательность, но для меня это слишком простой ответ.У меня более чем 20-летний опыт работы с архитектурой x86, и если действительно причиной является согласованность, а не производительность или что-то другое конкретное, то я со всем уважением предполагаю, что требовать этого от разработчиков немного наивно.Они игнорируют почти три десятилетия инструментов и поддержки.Особенно, если они ожидают, что поставщики инструментов быстро и легко адаптируют свои инструменты для своей платформы (возможно, нет...IT является Apple ...) без необходимости перепрыгивать через несколько, казалось бы, ненужных обручей.

Я уделю этой теме еще день или около того, а затем закрою ее...

Похожие

Это было полезно?

Решение

Из "Справочного руководства по оптимизации архитектур Intel®64 и IA-32", раздел 4.4.2:

"Для достижения наилучшей производительности потоковые расширения SIMD и Streaming SIMD Extensions 2 требуют, чтобы их операнды памяти были выровнены по 16-байтовым границам.Невыровненные данные могут привести к значительному снижению производительности по сравнению с выровненными данными ".

Из Приложения D:

"Важно убедиться, что фрейм стека выровнен по 16-байтовой границе при вводе функции, чтобы локальные данные __m128, параметры и местоположения разлива регистра XMM были выровнены во время вызова функции".

http://www.intel.com/Assets/PDF/manual/248966.pdf

Другие советы

Я не уверен, поскольку у меня нет доказательств из первых рук, но я полагаю, что причина в 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?

Читать это:

http://developer.apple.com/library/mac/#documentation/DeveloperTools/Conceptual/LowLevelABI/100-32-bit_PowerPC_Function_Calling_Conventions/32bitPowerPC.html#//apple_ref/doc/uid/TP40002438-SW20

А затем увеличил масштаб до "32-разрядных соглашений о вызове функций PowerPC" и, наконец, это:

"Это режимы выравнивания при внедрении, доступные в 32-разрядной версии Среда PowerPC:

Режим выравнивания мощности базируются на правилах выравнивания, используемого Компилятор IBM XLC, в операционной системе AIX.Это режим выравнивания по умолчанию для версии GCC с архитектурой PowerPC, используемой в AIX и Mac OS X.Поскольку этот режим, скорее всего, будет совместим между компиляторами PowerPC-архитектуры разных производителей, он обычно используется со структурами данных, которые совместно используются различными программами."

Учитывая унаследованный опыт OSX на базе PowerPC, переносимость является важным фактором - она диктует следовать соглашению вплоть до компилятора AIX XLC.Когда вы думаете с точки зрения необходимости убедиться, что все инструменты и приложения будут работать вместе с минимальными доработками, я думаю, что важно придерживаться того же устаревшего ABI, насколько это возможно.

Это дает философию, и дальнейшее чтение - это явно упомянутое правило ("Пролог и эпилог").:

Вызываемая функция отвечает за выделение своего собственного фрейма стека, гарантируя сохранение 16-байтового выравнивания в стеке .Эта операция выполняется разделом кода, называемым prolog, который компилятор помещает перед телом подпрограммы.После тела подпрограммы компилятор помещает эпилог, чтобы восстановить процессор в состояние, в котором он находился до подпрограммы вызов.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top