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

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

round(x*b - y*a)

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

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

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

【问题讨论】:

    标签: optimization assembly arm neon


    【解决方案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 代码更有效!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多