Встраивание сборки в C с компилятором, который находит регистры для вас

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

Вопрос

При встраивании ассемблерного кода в программу на 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"), но теперь я думаю, что было бы лучше перечислить их в качестве выходных данных, чтобы позволить компилятору выбирать их.Я не знаю ни одного источника, который бы решал эту проблему окончательно.

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