Получите GCC, чтобы сохранить регистр SSE во всей функции, использующей встроенный ассемблер.
-
12-09-2019 - |
Вопрос
Я пишу программу на языке C, которая должна выполнить несколько быстрых математических вычислений.Я использую встроенные инструкции ассемблера SSE, чтобы получить некоторые действия SIMD (используя упакованные числа двойной точности с плавающей запятой).Я компилирую с использованием GCC в Linux.
Я нахожусь в ситуации, когда мне нужно перебрать некоторые данные, и я использую постоянный коэффициент в своих расчетах.Я хотел бы сохранить этот фактор в безопасном регистре во время цикла, чтобы мне не приходилось каждый раз перезагружать его.
Чтобы уточнить с помощью некоторого кода:
struct vect2 {
fltpt x;
fltpt y;
}__attribute__((aligned(16))); /* Align on 16B boundary for SSE2 instructions */
typedef struct vect2 vect2_t;
void function()
{
/* get a specific value set up in xmm1, and keep it there for the
* rest of the loop. */
for( int i = 0, i<N; i++ ){
asm(
"Some calculations;"
"on an element of;"
"a data set.;"
"The value in xmm1;"
"is needed;"
);
}
}
Я пробовал что-то сделать с ключевым словом «регистрация».Но, если я не ошибаюсь, похоже, я могу сохранить только указатель в эту структуру (в общий реестр).Этому пришлось бы пренебрегать на каждой итерации, теряя драгоценное время.
register vect2_t hVect asm("xmm1") = {h, h};
/* Gives error: data type of 'hVect' isn't suitable for a register */
register vect2_t *hVect2 asm("rax");
*hVect2 = (vect2_t){h,h};
/* Seems to work, but not what I'm looking for */
Мне не просто нравится предполагать, что GCC не изменит регистр xmm1, это слишком похоже на «демоны, вылетающие из носа» :-).Поэтому я надеюсь, что есть правильный способ сделать это.
Решение
Я думаю, что решение здесь состоит в том, чтобы сообщить gcc, что ваш vec2_t
type на самом деле является вектором;тогда вы можете просто вычислить значение, инвариантное к циклу, и рассматривать его как обычную переменную (за исключением того, что компилятор знает, что это векторный тип):
typedef double vec2_t __attribute__ ((vector_size (16)));
void function()
{
/* get a specific value set up, e.g. */
vec2_t invariant;
asm( "some calculations, soring result in invariant."
: "=x" (invariant) );
for( int i = 0; i<N; i++ ){
asm(
"Some calculations;"
"on an element of;"
"a data set.;"
"The value in xmm1;"
"is needed;"
: "x" (invariant) // and other SSE arguments
);
}
}
Я только что скомпилировал это с помощью простого расчета внутри цикла и, по крайней мере, с уровнем оптимизации 1, значение invariant
хранится в регистре XMM во время цикла.
(Все это предполагает, что вы не нуждаться ваш инвариант цикла в явном регистре XMM;и что вы можете использовать обычное распределение регистров GCC).
Другие советы
Я думаю, что лучше оставить назначение регистров компилятору.Вероятно, он сможет отслеживать это лучше, чем вы.GCC уже использует расширения SSE, но если вы уверены, что знаете лучше, используйте функции GCC __builtin.Честно говоря, я немного сомневаюсь, что так вы справитесь быстрее.
Удачи!
На эти сайты, вероятно, интересно посмотреть.
Я привык работать с ассемблером и C, и здесь я бы написал всю функцию на ассемблере.Если у вас гибкая система make, я рекомендую собрать функцию ASM отдельно и связать ее с вашим приложением.Единственная проблема заключается в том, что функция не может быть встроена компилятором.
недействительная функция (недействительная);//С
внешняя функция "C" (недействительная);//С++