Как объединить элементы из 2 строк, используя NEON SIMD? - PullRequest
4 голосов
/ 27 июля 2010

У меня есть

A = a1 a2 a3 a4
    b1 b2 b3 b4
    c1 c2 c3 c4
    d1 d2 d3 d4

У меня есть 2 строки со мной,

float32x2_t a = a1 a2
float32x2_t b = b1 b2

Из них, как я могу получить -

float32x4_t result = b1 a1 b2 a2

Есть лилюбая одна инструкция NEON SIMD , которая может объединить эти две строки?Или как я могу добиться этого, используя как можно меньше шагов, используя встроенные функции?

Я думал об использовании встроенных функций zip / unzip , но тип данных zip function возвращает,который float32x2x2_t, мне не подходит, мне нужен тип данных float32x4_t.

float32x2x2_t vzip_f32 (float32x2_t, float32x2_t)

1 Ответ

5 голосов
/ 08 августа 2010

Это сложно. Нет ни одной инструкции, которая может это сделать, и наилучшее решение зависит от того, находятся ли ваши данные в памяти или они уже есть в регистрах.

Для преобразования вам нужно как минимум две операции. Сначала поворот вектора, который переставляет ваши аргументы следующим образом:

a = a1 a2
b = b1 b2

vtrn.32  a, b

a = a1 b1 
b = a2 b2

А затем вы должны поменять местами аргументы каждой операции. Либо путем обращения каждого вектора в отдельности, либо путем обработки двух векторов как четырехугольного вектора и выполнения длинного обратного хода.

temp = {a, b} 
temp = a1 b1 a2 b2

vrev64.32 temp, temp

temp = b1 a1 b2 a2    <-- this is what you want.

Если вы загружаете свои данные из памяти, вы можете пропустить первую инструкцию vtrn.32, потому что NEON может сделать это, пока она загружает данные, используя инструкцию vld2.32. Вот небольшая функция ассемблера, которая делает именно это:

.globl asmtest

asmtest:
        vld2.32     {d0-d1}, [r0]   # load two vectors and transose
        vrev64.32   q0, q0          # reverse within d0 and d1
        vst1.32     {d0-d1}, [r0]   # store result
        mov pc, lr                  # return from subroutine..

Кстати, небольшое примечание: инструкции vtrn.32, vzip.32 и vuzp.32 идентичны (но только если вы работаете с 32-битными сущностями)

А с присущим НЕОНУ свойством? Ну, просто сказал, что ты облажался. Как вы уже узнали, вы не можете напрямую приводить из одного типа в другой, и вы не можете напрямую смешивать четырехугольные и двойные векторы.

Это лучшее, что я придумал, используя встроенные функции (он не использует трюк vld2.32 для удобства чтения):

int main (int argc, char **args)
{
  const float32_t data[4] =
  {
    1, 2, 3, 4
  };

  float32_t     output[4];

  /* load test vectors */
  float32x2_t   a = vld1_f32 (data + 0);
  float32x2_t   b = vld1_f32 (data + 2);

  /* transpose and convert to float32x4_t */
  float32x2x2_t temp   = vzip_f32 (b,a);
  float32x4_t   result = vcombine_f32 (temp.val[0], temp.val[1]);

  /* store for printing */
  vst1q_f32 (output, result);

  /* print out the original and transposed result */
  printf ("%f %f %f %f\n", data[0],   data[1],   data[2],   data[3]);
  printf ("%f %f %f %f\n", output[0], output[1], output[2], output[3]);
}

Если вы используете GCC, это будет работать, но код, сгенерированный GCC, будет ужасным и медленным. Собственная поддержка NEON еще очень молода. Вы, вероятно, получите лучшую производительность с простым C-кодом здесь ..

...