ARM64 固有的 x86_64 点向量积

Posted

技术标签:

【中文标题】ARM64 固有的 x86_64 点向量积【英文标题】:x86_64 Dot Vector Product Intrinsic to ARM64 【发布时间】:2018-08-02 14:30:05 【问题描述】:

我正在将一个包含 x86_64 内部函数的小型 C 例程移植到 ARM64 平台。我找不到 _mm_dp_pd 的等效 ARM64 内在函数。

我确实可以访问 arm neon 内在函数。

我不确定如何将 x86_64 内部函数替换为 ARM64 等效项。

任何帮助将不胜感激。

#ifdef ARM64
    float32x4_t a, b;
#else
    __m128d a, b;
#endif

#ifdef ARM64
    ????
#else
    res = _mm_dp_pd(a, b, mask);
#endif

【问题讨论】:

正确格式化您的代码 "我假设 float32x4_t a; 可以替换 __m128d a;"糟糕的开始。 【参考方案1】:

dppd 并不比垂直乘法/随机播放/加法快,实际上在英特尔 CPU (https://agner.org/optimize/) 上解码为 3 微指令,这可能正是这样做的(可能还有一些额外的掩码奖励) .

例如在 Skylake 上,延迟为 9c,p01(FMA 单元所在的位置)为 2 uop,p5(随机播放单元所在的位置)为 1 uop。

在 Ryzen 之前的 AMD 上它甚至更慢(例如 Steamroller 上的 7 微指令),但 Ryzen 将其解码为 3 微指令。 (不过,dpps 仍然很慢,如果您实际上想要四个 32 位 float 元素 (float32x4_t) 而不是两个 64 位 double 元素 (__m128d))。


无论如何,假设您希望将点积结果广播到 double 向量的两个元素,请进行垂直乘法,然后交换一个向量并进行垂直加法。

将其移植到 ARM 应该很容易

__m128d prods = _mm_mul_pd(a,b);
__m128d swap  = _mm_shuffle_pd(prods,prods, 0b01);
__m128d dot   = _mm_add_pd(prods, swap);

或者,如果您只关心低元素,那么您可以使用更简单的 shuffle,例如 movhlps (Fastest way to do horizontal float vector sum on x86)。

如果您需要将上面的元素归零,就像 dppd 可以做的那样,那么它可能需要在 AArch64 上执行额外的指令。


顺便说一句,如果您正在执行大量 DPPD,您可能希望将数据布局更改为数组结构,这样您就可以并行执行两个点积而无需任何改组,使用mul 和一个 FMA。请参阅https://deplinenoise.wordpress.com/2015/03/06/slides-simd-at-insomniac-games-gdc-2015/,了解有关设计数据布局/整体方法以实现 SIMD 友好的良好说明

但内部循环之外的横向内容并不总是坏事。

【讨论】:

以上是关于ARM64 固有的 x86_64 点向量积的主要内容,如果未能解决你的问题,请参考以下文章

文件是为 arm64 构建的,它不是被链接的架构 (x86_64)

反应原生模块中的“arm64-v8a”、“x86_64”上的应用程序崩溃

目标 'arm64-apple-ios' 在 iOS 'Heimdall' 中出现错误;找到:x86_64“

i386 x86_64 armv7 arm64

无法为架构 arm64 和 x86_64 构建 opencv ios 框架

iOS中的armv7,armv7s,arm64,i386,x86_64