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

Posted

技术标签:

【中文标题】如何使用 NEON SIMD 合并 2 行的元素?【英文标题】:How to merge elements of 2 rows using NEON SIMD? 【发布时间】:2010-07-27 11:59:57 【问题描述】:

我有一个

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 函数 返回的数据类型 float32x2x2_t 不适合我,我需要一个 @ 987654325@ 数据类型。

float32x2x2_t vzip_f32 (float32x2_t, float32x2_t)

【问题讨论】:

【参考方案1】:

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

您至少需要两个操作来进行转换。首先是一个向量轮转,它可以像这样排列您的参数:

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 位实体)

还有 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]);

如果您使用 GCC,这将起作用,但 GCC 生成的代码会很糟糕而且很慢。 NEON 内在支持还很年轻。您可能会在此处使用直接的 C 代码获得更好的性能..

【讨论】:

您好 Nils,我在为 NEON 编译时遇到问题,在使用代码源编译器编译我的代码时遇到了一些奇怪的错误,我无法理解它是什么错误。你能看看我的问题并建议我怎么做吗?***.com/questions/3811148/… 目前,使用 vcombine 和 vget_high/low 效果很好。至少 LLVM 仍然不使用 SIMD 指令的并行性,并且手卷内在代码明显更好。

以上是关于如何使用 NEON SIMD 合并 2 行的元素?的主要内容,如果未能解决你的问题,请参考以下文章

Neon 在 Intrinsics 中的校验和代码实现

ARM Cortex A53上的NEON SIMD dotproduct速度不快

如何在 ARM NEON SIMD 内在函数上编写“a[i]=b[c[i]]”

如何使用 SIMD 指令截断值

数字信号处理中的 SIMD

ARM NEON 优化中的建议