Вы не можете заставить компилятор передавать функцию arg в EAX / RAX в 64-битном режиме.В 32-битном режиме вы можете использовать соглашение о вызовах gcc "regparm", например __attribute__((regparm(3))) int my_func(int,int);
, для передачи аргументов в EAX, ECX, EDX в этом порядке.(Таким образом, компилятору потребуется mov
перед встроенным asm, который имеет функцию arg в EAX).
Или вы можете объявить свои функции с помощью __attribute__((sysv_abi))
, чтобы всегда использовать SysV ABI, даже при компиляции в Windows,Но это работает только в том случае, если все абоненты скомпилированы GCC / clang / ICC, а не MSVC.И это хуже в 32-битном режиме;Соглашение о вызовах i386 System V - это дерьмо: передача всех аргументов в стеке, и только ed64_t возвращается в edx: eax, а не в 64-разрядных структурах с двумя членами.
Вызов функции sysv_abi
также может бытьms_abi
функция для сохранения / восстановления всего xmm6..15, если только вызов функции sysv_abi не может быть встроен и оптимизирован.Таким образом, в целом это, вероятно, плохой план, если функция еще не интенсивно использовала регистры XMM и сохранила / восстановила большинство из них.
Использование фиксированных ограничений ввода / вывода регистров не являетсяобычно полезно, если вы не используете инструкции с неявными регистрами (например, счетчик сдвигов в cl
, если вы не можете использовать BMI2 shlx
/ shrx
).
Пусть компилятор зарегистрируетсяраспределение с использованием ограничений "r"
и "+r"
.(Или "=r"
и "0"
соответствия ограничениям), чтобы ваша функция могла эффективно работать, независимо от того, где находятся значения.Также используйте "re"
для входов, которые могут быть регистровыми или 32-битными.Или даже "rem"
для входов, которые также могут быть памятью.Но если вы используете входные данные несколько раз, может быть лучше, чтобы компилятор загрузил их для вас перед ассемблером.
См. Также https://stackoverflow.com/tags/inline-assembly/info
Жесткое кодирование распределения регистров частично нарушаетцель использования встроенного asm вместо автономных функций asm, которые компилятор должен вызывать вместо встраивания.
Посмотрите на сгенерированный компилятором asm для вашего кода, чтобы увидеть, какой окружающий код он сгенерировал, и как он заполнилв шаблоне, выбрав операнды.
Также обратите внимание, что "r"
выбирает 16-битные регистры для 16-битных типов и 32-битные регистры для 32-битных типов, так что все эти вещи по размеру типов в основномненужным.(Хотя в зависимости от того, как были записаны ваши входные данные, использование 32-битного xor
может быть лучше, чем 16-битного xor, возможно, следует избегать частичных остановок регистров, если что-то позже прочитает полные 32 или 64-битные регистры. Но если ваши входные регистры былизаписанный с размером 16-битного операнда, тогда на процессорах семейства P6 32-битный xor создаст частичную регистрацию.) Вы можете переопределить размер, заполненный для замены шаблона "xor %0"
, с помощью "%k0"
для 32размер бита и т. д. См. x86 Модификаторы операнда в руководстве по GCC .