【发布时间】:2016-08-29 22:35:58
【问题描述】:
__declspec(dllexport)
float foo(float x) {
return (x < 0) ? x * -1 : x;
}
这是一个非常简单的计算abs(x) 的实现,其中x 是float。我在发布模式下编译了它并启用了我能找到的所有优化。生成的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