ima*_*ett 7 floating-point assembly
我处于需要计算类似事物的情况size_t s=(size_t)floorf(f);.也就是说,参数是一个浮点数,但它有一个整数值(假设floorf(f)它足够小,可以准确表示).在优化这一点的同时,我发现了一些有趣
以下是从float整数转换(GCC 5.2.0 -O3).为清楚起见,给出的转换是测试函数的返回值.
这是int32_t x=(int32_t)f:
cvttss2si eax, xmm0
ret
Run Code Online (Sandbox Code Playgroud)
这是uint32_t x=(uint32_t)f:
cvttss2si rax, xmm0
ret
Run Code Online (Sandbox Code Playgroud)
这是int64_t x=(int64_t)f:
cvttss2si rax, xmm0
ret
Run Code Online (Sandbox Code Playgroud)
最后,这是uint64_t x=(uint64_t)f;:
ucomiss xmm0, DWORD PTR .LC2[rip]
jnb .L4
cvttss2si rax, xmm0
ret
.L4:
subss xmm0, DWORD PTR .LC2[rip]
movabs rdx, -9223372036854775808
cvttss2si rax, xmm0
xor rax, rdx
ret
.LC2:
.long 1593835520
Run Code Online (Sandbox Code Playgroud)
最后一个比其他的复杂得多.此外,Clang和MSVC表现相似.为方便起见,我将其翻译成伪C:
float lc2 = (float)(/* 2^63 - 1 */);
if (f<lc2) {
return (uint64_t)f;
} else {
f -= lc2;
uint64_t temp = (uint64_t)f;
temp ^= /* 2^63 */; //Toggle highest bit
return temp;
}
Run Code Online (Sandbox Code Playgroud)
这看起来好像正在尝试正确计算第一个溢出模64.这看起来很虚伪,因为cvttss2si的文档告诉我如果发生溢出(在2 ^ 32,而不是2 ^ 64),"返回不定的整数值(80000000H)".
我的问题:
由于cvttss2si签名转换,它会认为区间中的数字[2^63, 2^64)超出范围,而实际上它们在无符号范围内.因此,检测到这种情况并将其映射到浮点中的低半部分,并且在转换之后应用校正.
至于其他情况,请注意uint32_t转换仍使用64位目标,该目标将适用于整个范围,uint32_t并且根据调用约定使用结果的低32位隐式进一步截断.
在避免额外代码方面,这取决于您的输入是否可能属于上述范围.如果可以的话,就无法绕过它.否则,首先签署的双重演员然后签名到无签名可以工作,即.(uint64_t)(int64_t)f.
| 归档时间: |
|
| 查看次数: |
187 次 |
| 最近记录: |