Получите GCC, чтобы сохранить регистр SSE во всей функции, использующей встроенный ассемблер.

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

Вопрос

Я пишу программу на языке 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.Честно говоря, я немного сомневаюсь, что так вы справитесь быстрее.

Удачи!

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

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

Работа с SIMD с GCC

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

недействительная функция (недействительная);//С

внешняя функция "C" (недействительная);//С++

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