ARM NEON 汇编和浮点舍入

Posted

技术标签:

【中文标题】ARM NEON 汇编和浮点舍入【英文标题】:ARM NEON assembly and floating point rounding 【发布时间】:2013-08-01 15:26:32 【问题描述】:

我正在使用 NEON 对 ARM 处理器进行代码优化。但是我有一个问题:我的算法包含以下浮点计算:

round(x*b - y*a)

结果可以是正面的也可以是负面的。

实际上,我使用 2 个 VMUL 和 1 个 VSUB 进行并行计算(每次操作使用 Q 寄存器和 32 位浮点数 4 个值)。

有办法解决这个问题吗?如果结果都是相同的符号,我知道我可以简单地加或减 0.5

【问题讨论】:

【参考方案1】:

首先,NEON 的延迟很长,尤其是在浮点乘法之后。 因此,与 vfp 编程相比,使用两个 vmul 和一个 vsub 不会获得太多收益。

因此,您的代码应如下所示:

vmul.f32 result, x, b
vmls.f32 result, y, a

这些乘法累加/减法指令与前一个乘法指令背靠背发出,没有任何延迟。 (在这种情况下节省了 9 个周期)

不幸的是,我不明白你的实际问题。为什么有人要舍入浮点值?显然你打算提取整数部分,并且有几种方法可以做到这一点,我不能告诉你更多,因为你的问题总是太模糊。

我在这个论坛上关注你的问题已经有一段时间了,我无法摆脱你缺乏一些非常基本的东西的感觉。

我建议你先阅读 ARM 的汇编参考指南 pdf。

【讨论】:

您好,是的,我需要提取四舍五入的整数部分。感谢您的建议,我会尽快阅读参考指南,我也在关注您的博客,非常有趣。 那么你就不必以浮点格式四舍五入了。只需使用 vcvt.s32.f32 将浮点数转换为带 1 个小数位的整数,然后您可以使用 vrshr.s32 进行舍入。这就是我所说的“更具体地解决你的问题”的意思 我错过了 VCVT 指令中的 #fbits 可选值。我已经测试了您的解决方案:对于正值可以,但负值未正确舍入,-0.9 舍入为 0 而不是 -1。 哦,我明白了。那么这应该可以工作:vshr.u32 temp, result, #31; veor.32 结果,温度; vrshr.s32 结果,#1 负数还是有问题! -0.1 到 -0.9 可以(0 和 -1),-1 到 -1.4 错误(= 0),-1.5 到 -1.9 可以(= -2),-2 到 -2.4 错误(= -1),- 2.5 到 -2.9 OK (= -3) ... 等等...感谢您的耐心等待。【参考方案2】:

我对汇编一无所知,但使用 C 中的 NEON 内部函数(我提到了它们的汇编等效项以帮助您浏览文档,即使我自己无法使用它们),round 的算法函数可能是:

// Prepare 3 vectors filled with all 0.5, all -0.5, and all 0
// Corresponding assembly instruction is VDUP
float32x4_t plus  = vdupq_n_f32(0.5);
float32x4_t minus = vdupq_n_f32(-0.5);
float32x4_t zero  = vdupq_n_f32(0);

// Assuming the result of x*a-y*b is stored in the following vector:
float32x4_t xa_yb;

// Compare vector with 0
// Corresponding assembly instruction is VCGT
uint32x4_t more_than_zero = vcgtq_f32(xa_yb, zero);
// Resulting vector will be set to all 1-bits for values where the comparison
// is true, all 0-bits otherwise.

// Use bit select to choose if you have to add or substract 0.5
// Corresponding assembly instruction is VBSL, its syntax is quite alike
// `more_than_zero ? plus : minus`.
float32x4_t to_add = vbslq_f32(more_than_zero, plus, minus);

// Add this vector to the vector to round
// Corresponding assembly instruction is VADD,
// but I guess you knew this one :D
float32x4_t rounded = vaddq_f32(xa_yb, to_add);

// Then cast to integers!

我猜你可以把它转换成程序集(反正我不是)

请注意,我不知道这是否真的比标准代码、非 SIMD 代码更有效!

【讨论】:

以上是关于ARM NEON 汇编和浮点舍入的主要内容,如果未能解决你的问题,请参考以下文章

ARM Neon iOS 浮点转换

带有溢出的 ARM Neon 浮点整数转换的行为

linuxARM板子开启浮点和neon加速

使用 NEON 在 ARM 汇编中对四字向量中的所有元素求和

Linux下VFP NEON浮点编译

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