Передача параметров в Visual Studio и GCC - PullRequest
2 голосов
/ 20 июня 2011

Передача параметров в Visual Studio .Обратите внимание, как передаются __m128 типы.Означает ли это, что по значению должно быть передано не более 4 __m128 аргументов.

void good_function(__m128, __m128, __m128, __m128, __m128&);
void bad_function(__m128, __m128, __m128, __m128, __m128);

Применимо ли это правило к GCC?

Спасибо!

РЕДАКТИРОВАТЬ: Возможно ли, что пятый аргумент bad_function может быть выровнен?Я где-то читал, что только 3 аргумента передаются в регистрах (наверное, это Win32, а не x64).

Ответы [ 2 ]

2 голосов
/ 20 июня 2011

Передача аргумента определяется соглашением о вызовах из системы ABI (Application Binary Interface). Какой ABI используется, зависит от того, для какой цели (ОС + аппаратная платформа) вы компилируете. См., Например, AMD64 ABI , который * nix использует (грубо говоря, есть несколько небольших вариантов).


Ссылка, которую вы предоставили, была на статью о передаче параметров соглашения о вызовах Microsoft x64. Это отмечает:

  • __m128 всегда передаются по указателю, а не по значению
  • первые четыре целых числа или указатели всегда передаются в RCX, RDX, R8, R9

Таким образом, для любой функции с только __m128 аргументами до четырех будут передаваться как указатели в регистрах, а любые другие передаются как указатели в стеке. Как отмечает Джейсон в другом ответе, эти указатели будут указывать на значения, которые также вероятны в стеке.

__m128 и __m128 & (а также __m128 *), вероятно, эквивалентны по стоимости в соглашении о вызовах Microsoft x64 - все они проходят по указателю.


При чтении через AB64 AMD64 выглядит, как будто первые 8 регистров XMM (%xmm0 - %xmm8) имеют ширину 128 бит и будут принимать значение __m128 по значению. Таким образом, в системах, использующих AMD64 ABI (например, gcc в linux), первые восемь аргументов __m128 окажутся в регистрах.

В этом случае может имеет смысл передавать с 9 по 15 __m128 аргументы как ссылки / указатели - они могут использовать целочисленные регистры. Это позволит избежать копирования их в стек.


Я не уверен, какое соглашение использует gcc для windows (например, mingw). Предположительно он должен использовать соглашение Microsoft x64, если он взаимодействует с другими библиотеками.


Если вам интересно, я бы настоятельно рекомендовал провести несколько экспериментов и посмотреть на разборку - опция gcc -S отлично подходит для этого! Если вы находитесь в Visual Studio, вы можете использовать окно разборки в отладчике.

Всегда хорошо немного пиковаться под капотом, даже если вы не до конца понимаете, что происходит. Вы начнете видеть шаблоны и сможете задавать вопросы или исследовать то, что видите.

2 голосов
/ 20 июня 2011

Описание передачи параметров, с которым вы связаны, на самом деле представляет собой описание x86_64 Windows ABI (двоичный интерфейс приложения), демонстрирующее, как значения будут передаваться в функцию на уровне сборки (т. Е. Как компилятор будет переводить вызов C-функции в сборку). ). При этом первые четыре аргумента будут переданы как указатели на типы __m128 с использованием регистров на платформе x86_64. Поскольку платформа x86_64 имеет больше регистров для работы, по сравнению с 32-битным couterpart, этот тип передачи параметров выполняется для ускорения вызовов функций, поскольку доступ к аргументам, хранящимся в регистрах, будет быстрее, чем доступ к значениям аргументов, хранящимся в памяти на стек, как вы обычно видите при вызовах функций в стиле cdecl на 32-битной платформе x86. Если вы выходите за пределы 4 аргументов, то остальные указатели на тип __m128 сохраняются в стеке. Таким образом, не существует «хороших функций» или «плохих функций», просто основанных на количестве аргументов. В вашем примере обе ваши функции хороши, просто во втором примере остальные аргументы должны использовать пространство стека, так как количество доступных регистров, которые могут использоваться для передачи значений, было израсходовано.

При этом указатели на типы __m128, скорее всего, будут указывать на адреса, выделенные в стеке, если они являются автоматическими переменными. Так или иначе, вы, скорее всего, будете использовать пространство стека, либо для хранения указанных переменных, либо для передачи дополнительных аргументов функциям при работе со значениями, превышающими 64-битные, и другими агрегатными типами, такими как классы, объединения, массивы и т. д.

Что касается GCC, поскольку то, на что вы ссылались, на самом деле является зависимой от платформы реализацией ABI (в данном случае Windows x86_64), то, что вы увидите на других платформах, будет несколько отличаться, хотя, опять же, для большинства ОС x86_64 они будет использовать серию регистров для передачи первой пары аргументов вызова функции. Таким образом, GCC будет фактически использовать те же правила, что и Visual Studio в Windows x86_64, но на других платформах он создаст другую сборку на основе ABI x86_64 для этих платформ.

...