如何使用NEON SIMD合并2行的元素?

Hag*_*ble 4 simd intrinsics neon

我有一个

A = a1 a2 a3 a4
    b1 b2 b3 b4
    c1 c2 c3 c4
    d1 d2 d3 d4
Run Code Online (Sandbox Code Playgroud)

我有2排,

float32x2_t a = a1 a2
float32x2_t b = b1 b2
Run Code Online (Sandbox Code Playgroud)

从这些我怎么能得到一个 -

float32x4_t result = b1 a1 b2 a2
Run Code Online (Sandbox Code Playgroud)

是否有任何单个NEON SIMD指令可以合并这两行?或者我如何使用内在函数尽可能使用最少的步骤来实现这一目标?

我想过使用zip/unzip内在函数但是zip函数返回的数据类型,这float32x2x2_t对我来说不合适,我需要一个float32x4_t数据类型.

float32x2x2_t vzip_f32 (float32x2_t, float32x2_t)
Run Code Online (Sandbox Code Playgroud)

Nil*_*nck 5

这很难..没有一条指令可以做到这一点,最好的解决方案取决于您的数据是在内存中还是已经在寄存器中.

你至少需要两个操作来进行转换.首先是一个向量转换,它会像你这样置换你的参数:

a = a1 a2
b = b1 b2

vtrn.32  a, b

a = a1 b1 
b = a2 b2
Run Code Online (Sandbox Code Playgroud)

然后你必须交换每个操作的参数.通过自己反转每个矢量或者将两个矢量视为四元矢量并进行长反转.

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

vrev64.32 temp, temp

temp = b1 a1 b2 a2    <-- this is what you want.
Run Code Online (Sandbox Code Playgroud)

如果从内存加载数据,可以跳过第一条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..
Run Code Online (Sandbox Code Playgroud)

顺便说一下,注意事项:指令vtrn.32,vzip.32和vuzp.32是相同的(但只有当你使用32位实体时)

还有NEON内在函数?好吧 - 简单地说你被搞砸了.正如您已经发现的那样,您不能直接从一种类型转换为另一种类型,也不能直接混合四向和双向量.

这是我提出的使用内在函数的最佳方法(它不使用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]);
}
Run Code Online (Sandbox Code Playgroud)

如果您正在使用GCC,这将起作用,但GCC生成的代码将是可怕且缓慢的.NEON的内在支持还很年轻.你可能会在这里使用直接的C代码获得更好的性能.