Встраивание ассемблера в C с помощью регистров поиска компилятора для вас - PullRequest
3 голосов
/ 31 мая 2009

При встраивании ассемблерного кода в программу на C / C ++ вы можете избежать дублирования регистров, сохранив их с помощью инструкции push (или укажите, что список компиляторов поддерживает это).

Если вы используете встроенную сборку и хотите избежать накладных расходов, связанных с перемещением и извлечением засоренных регистров, существует ли способ позволить gcc выбирать регистры для вас (например, те, которые, как он знает, не содержат полезной информации).

Ответы [ 3 ]

9 голосов
/ 31 мая 2009

Да. Вы можете указать, что вы хотите, чтобы конкретная переменная (вход или выход) была сохранена в регистре, но вам не нужно указывать регистр. См. этот документ для подробного объяснения. По сути, встроенная сборка выглядит так:

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 */
   );
0 голосов
/ 08 августа 2012

ОК, поэтому я не могу оставить комментарий выше, но я уверен, что правильный синтаксис (отличный от показанного выше):

asm ( "your assembly instructions"
    : "=a"(output1),
      "=r"(output2),
      "=q"(output3),
      "=A"(output4)
    : /* inputs */
    : /* clobbered registers */
);

Хотя вы можете оставить распределение входных и выходных регистров компилятору, нет очевидного способа оставить выделение чистых / временных регистров (т. Е. Используемых для промежуточных значений, но не для ввода или вывода) для компилятора. Исторически, я просто перечислял их явно в списке clobber (например, "% xmm1", "% rcx"), но теперь я думаю, что было бы лучше перечислить их как выходные данные, чтобы компилятор мог их выбрать. Я не знаю ни одного источника, который бы решал эту проблему окончательно.

0 голосов
/ 18 ноября 2010

Встроенные функции компилятора - очень полезный способ смешивания ассемблера и кода 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
}
...