Получить GCC, чтобы сохранить регистр SSE в функции, которая использует встроенный ассемблер - PullRequest
7 голосов
/ 09 августа 2009

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

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

Ответы [ 3 ]

8 голосов
/ 09 августа 2009

Я думаю, что решение здесь состоит в том, чтобы gcc знал, что ваш тип vec2_t на самом деле является вектором; тогда вы можете просто вычислить инвариантное для цикла значение и рассматривать его как нормальную переменную (за исключением того, что компилятор знает, что это векторный тип):

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).

3 голосов
/ 09 августа 2009

Я привык работать со сборкой и C, и здесь я хотел бы написать всю функцию в сборке. Если у вас есть гибкая система сборки, я рекомендую собрать функцию ASM отдельно и связать ее с вашим приложением. Единственная проблема в том, что эта функция не может быть встроена компилятором.

void function (void); // C

внешняя функция "C" (пусто); // C ++

3 голосов
/ 09 августа 2009

Я думаю, что лучше оставить присвоение регистра компилятору. Вероятно, он может отслеживать это лучше, чем вы. GCC уже будет использовать расширения SSE, но если вы уверены, что знаете лучше, используйте функции GCC __builtin. Честно говоря, я немного сомневаюсь, что вы так сделаете быстрее.

Удачи!

Эти сайты, вероятно, интересно посмотреть.

GCC X86 Встроенные функции

Работа с SIMD с GCC

...