Встраивание сборки в C с компилятором, который находит регистры для вас
-
06-09-2019 - |
Вопрос
При встраивании ассемблерного кода в программу на C / C ++ вы можете избежать загромождения регистров, сохранив их с помощью команды push (или указав список загромождений, поддерживаемый компилятором).
Если вы включаете встроенную сборку и хотите избежать накладных расходов на нажатие и выталкивание заблокированных регистров, есть ли способ позволить gcc выбирать регистры для вас (напримерте, которые, как ему известно, не содержат в себе никакой полезной информации).
Решение
ДА.Вы можете указать, что хотите, чтобы конкретная переменная (входная или выходная) хранилась в регистре, но вам не обязательно указывать регистр.Видишь этот документ для получения подробного объяснения.По сути, встроенная сборка выглядит следующим образом:
asm("your assembly instructions"
: output1("=a"), // I want output1 in the eax register
output2("=r"), // output2 can be in any general-purpose register
output3("=q"), // output3 can be in eax, ebx, ecx, or edx
output4("=A") // output4 can be in eax or edx
: /* inputs */
: /* clobbered registers */
);
Другие советы
Встроенные функции компилятора это очень полезный способ смешивать ассемблер и код на C / C ++.Это объявления, которые выглядят как функции, но на самом деле компилируются непосредственно в отдельные собственные инструкции (через специальный регистр внутри компилятора).Это дает вам большую часть контроля над работой в ассемблере, но оставляет раскраску регистра и планирование на усмотрение компилятора.
Преимущество заключается в том, что тогда вы можете передать обычную переменную C во встроенную и позволить компилятору позаботиться о загрузке ее в регистр и планировании других операций вокруг нее.Например,
struct TwoVectors
{
__m128 a; __m128b;
}
// adds two vectors A += B using the native SSE opcode
inline void SimdADD( TwoVectors *v )
{
v->a = _mm_add_ps( v->a , v->b ); // compiles directly to ADDSS opcode
}
Хорошо, поэтому я не могу оставить комментарий выше, но я почти уверен, что правильный синтаксис (отличный от показанного выше) следующий:
asm ( "your assembly instructions"
: "=a"(output1),
"=r"(output2),
"=q"(output3),
"=A"(output4)
: /* inputs */
: /* clobbered registers */
);
Хотя вы можете оставить распределение регистров ввода и вывода компилятору, нет очевидного способа оставить распределение регистров scratch / temp (т.Е.используется для промежуточных значений, но не для ввода или вывода) компилятору.Исторически сложилось так, что я просто перечислил их явно в списке clobber (например"%xmm1", "%rcx"), но теперь я думаю, что было бы лучше перечислить их в качестве выходных данных, чтобы позволить компилятору выбирать их.Я не знаю ни одного источника, который бы решал эту проблему окончательно.