如何访问 NEON 指令中的完整 128 位?

Posted

技术标签:

【中文标题】如何访问 NEON 指令中的完整 128 位?【英文标题】:How to access full 128 bits in NEON instructions? 【发布时间】:2021-11-04 12:15:16 【问题描述】:

我最近编写了一个在 Arm64 汇编中进行浮点计算的程序。 由于我处理的数字可能会变得非常小,所以我现在想优化代码,使其尽可能地使用精度。

我发现 NEON 引擎有 128 位浮点寄存器,而不是我目前使用的 64 位,所以我寻找了一种使用这些进行计算的方法。我看过的每个网站都告诉我这应该是可能的,但是当我尝试做类似的事情时

fmul v0, v1, v2

我只是得到“错误:指令操作数无效”。

我正在使用应该能够处理 NEON 指令的 M1 芯片,当我将其更改为

fmul v0.2d, v1.2d, v2.2d

完全没有问题。

有人知道我做错了什么吗?还是不能一次使用这些寄存器的所有 128 位?

【问题讨论】:

128 位 v 寄存器的想法是同时操作两个 64 位双精度值,这就是 fmul v0.2d, v1.2d, v2.2d 所做的。或四个 32 位值等。这就是 SIMD:单指令多数据。它与您之前的浮点类型和操作相同,只是一次操作更多。当然,您一次可以加载和存储 128 位,但算术都是在多个较小尺寸的元素上进行的。没有 128 位算术。 对于答案中的评论所指示的分形,至少对于 Mandelbrot/Julia,最好的办法是使用可以保持 4.0 或从 (xx + yy) >= 4.0 可以检测到;记住对 bignum 乘法和复数乘法都使用 Karatsuba 乘法(使用 5 个元素加法和 3 个元素明智乘法,而不是标准的 2+4)。 【参考方案1】:

你不能。

没错,NEON 寄存器是 128 位宽,但最大 数据类型 宽度是 64。

据我所知,没有任何消费者架构能够处理任何 128 位数据类型。

PS:是否有一个四元数据类型开始?我很好奇。

【讨论】:

谢谢,虽然这有点令人沮丧。并且qn 寄存器(128 位)似乎适用于加载/存储指令......但好吧,我想我必须找到另一种方法来解决这个问题。 在 AArch64 Linux 上,long double 数据类型是 128 位,但使用它的代码似乎只是在 libgcc 中生成对助手的调用。 具体来说是IEEE quad precision, aka binary128。但是,是的,它是编译器的一个特性,而不是硬件的特性——所有四精度算术都是在软件中完成的。如果 OP 需要极高的精度并且可以完全牺牲性能,那就是这样。 因为我正在尝试绘制分形,所以性能非常重要——这就是我在组装中这样做的原因。但也许我会尝试自己建立一个更精确的计算系统。无论如何,感谢您的帮助

以上是关于如何访问 NEON 指令中的完整 128 位?的主要内容,如果未能解决你的问题,请参考以下文章

NEON:如何将 128 位 ARGB 转换为具有饱和度的 32 位 ARGB?

如何使用 neon 访问超过 256 字节的查找表?

NEON:将 uint8_t 数组加载到 128 位寄存器中

NASM ctypes SIMD - 如何访问返回到ctypes的128位数组?

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

使用内在函数测试 128 位 NEON 寄存器的值为 0 的最快方法?