ARM NEON 数组类型有什么好处(除了方便之外)吗?

Is there a benefit (other than convenience) to ARM NEON array types?

ARM NEON C 内在函数定义数组类型 (per docs here),它们是包含矢量数据类型数组的 C 结构。例如,int16x4x2_t 是两个 int16x4_t

我的问题很简单:这些为什么存在?与直接使用矢量类型相比,它们是否具有一些性能优势?例如,如果我 vld1q_f64 来自双指针的 float64x2_t 并使用 vaddq_f64vmulq_f64vfmaq_f64、...等,我会期望任何性能差异到 vld1q_f64_x4-ing a float64x2x4_t 并在数组元素上使用相同的函数。我想我只是很困惑为什么他们创建这些固定长度的数组类型,而直接操作它们的唯一内在函数是加载和存储。

它们不仅用于装载和存储;当有多个 128 位输出向量时使用它们。参见,例如,vuzp_* / vuzpq_*.

这是一种结束需要多个向量的操作的好方法,无需求助于指针,指针很容易搞砸。这包括在单个操作中加载和存储 load/store 多个向量。例如,可能可以将 vld4_s8 函数实现为:

void vld4_s8(int8x8_t* a, int8x8_t* b, int8x8_t* c, int8x8_t* d, int8_t* data);

如果我看到那个签名,我将不得不找到一些文档来弄清楚 WTF 是如何处理前四个参数的。它们是输入还是输出?它们是指向向量数组的指针,还是只是一个向量?是不是都需要设置,还是can/should我不需要这个值就传NULL?

另一方面,当前函数很难出错。有一个输入是一个 8 位整数数组,它 returns 是一个包含四个向量的数组。我唯一会做的不同的事情是对输入数据使用 a conformant array parameter 这样你就知道它需要多少元素,但这在 C++ 或 MSVC 中不起作用(可能直到几个月前他们添加了 C99/C11 支持)无论如何。

would I expect any performance difference to vld1q_f64_x4-ing a float64x2x4_t and using the same functions on elements of the array.

可能,但不是来自相乘。优势在于使用一条指令来加载所有四个向量;例如,参见 https://godbolt.org/z/aY8a95。在这种情况下,您有一次加载和四次乘法,而不是四次加载和四次乘法。

在实践中,我怀疑大多数优秀的编译器都能够将其优化为相同的代码(尽管我想检查一下),但内在函数通常会映射 1:1 与指令,所以你没有相信编译器是聪明的。在这种情况下,有一个 ld4 指令,所以有一个 vld4_* 函数族,这些类型在那些 API 中使用。