【问题标题】:Why can't the VS 2015 compiler optimise a branch in an abs() implementation on float numbers?为什么 VS 2015 编译器不能优化浮点数的 abs() 实现中的分支?
【发布时间】:2016-08-29 22:35:58
【问题描述】:
__declspec(dllexport)
float foo(float x) {
    return (x < 0) ? x * -1 : x;
}

这是一个非常简单的计算abs(x) 的实现,其中xfloat。我在发布模式下编译了它并启用了我能找到的所有优化。生成的asm 是:

; 4    :    return (x < 0) ? x * -1 : x;

    movss   xmm1, DWORD PTR _x$[ebp]
    xorps   xmm0, xmm0
    comiss  xmm0, xmm1
    jbe SHORT $LN3@foo
    xorps   xmm1, DWORD PTR __xmm@80000000800000008000000080000000
$LN3@foo:
    movss   DWORD PTR tv66[ebp], xmm1
    fld DWORD PTR tv66[ebp]

如您所见,它仍然包含分支和条件跳转。然而,float 是由 IEEE754 定义的,因此我可以更改实现以简单地将符号位设置为 0:

__declspec(dllexport)
float foo(float x) {
    void* bar = &x;
    __int32 y = ((*(__int32*)bar) & ~(1 << 31));
    return  *(float*)&y;
}

不跳转且需要较少命令:

; 3    :        void* bar = &x;
; 4    :        __int32 y = ((*(__int32*)bar) & ~(1 << 31));

    mov eax, DWORD PTR _x$[ebp]
    and eax, 2147483647             ; 7fffffffH
    mov DWORD PTR _y$[ebp], eax

; 5    :        return  *(float*)&y;

    fld DWORD PTR _y$[ebp]

我本以为甚至存在用于此操作的特定命令,但也许这仅适用于非常特殊的架构?

那么编译器无法捕捉到这种优化的原因是什么?还是我这样做有误?

【问题讨论】:

  • 您是否使用明显的极端情况对其进行了测试? NaN, INF, -INF, denorms, max, min, epsilon?证明并测试它。
  • @Yakk 你对 epsilon 是什么意思?我只知道机器精度,我不确定这会如何干扰我将符号位设置为 0。
  • 考虑改用copysign 函数。
  • @firefoz 我只是列出了一堆有些特殊的浮点值。有很多,有些很古怪。测试它们检查它们的 ieee 强制位模式似乎是这里的第一步。我不是浮点专家。

标签: c++ assembly optimization


【解决方案1】:

因为这会产生负零的错误结果!

负零不小于零,所以它的符号保持负数,使得条件分支的消除无效。

考虑使用类似的东西

copysign(x, 0.0);

改为。

【讨论】:

  • 呸,我从我的古怪花车列表中错过了-0。坏牦牛没有饼干。
猜你喜欢
  • 2020-09-19
  • 2012-10-06
  • 2020-11-30
  • 1970-01-01
  • 1970-01-01
  • 2011-04-17
  • 2012-03-04
  • 2019-02-18
  • 2015-09-15
相关资源
最近更新 更多