将 64 位整数加载到双精度 SSE2 寄存器的最佳方法?
Posted
技术标签:
【中文标题】将 64 位整数加载到双精度 SSE2 寄存器的最佳方法?【英文标题】:Best way to load a 64-bit integer to a double precision SSE2 register? 【发布时间】:2013-03-22 11:16:56 【问题描述】:在 32 位模式下将 64 位整数值加载到 xmm
SSE2 寄存器中的最佳/最快方法是什么?
在 64 位模式下,cvtsi2sd
可以使用,但在 32 位模式下,它只支持 32 位整数。
到目前为止,我还没有找到更多的东西:
使用fild
、fstp
堆叠然后movsd
到xmm
寄存器
加载高 32 位部分,乘以 2^32,加上低 32 位
第一个解决方案很慢,第二个解决方案可能会引入精度损失(edit:无论如何它很慢,因为必须将低 32 位转换为无符号...)
有更好的方法吗?
【问题讨论】:
在浮点数中将前 32 位乘以 2**32 不会截断/舍入它们。只有当您将低 32 位添加到它们时,总和才会被舍入/截断,这就是您使用第一种方法得到的结果。除非我遗漏了什么,否则这两种方法是等效的(性能除外)。 FWIW gcc 似乎使用第一种方法(fild、fst、movsd)。 第二个选项其实很慢,我错误地将cvtsi2sd用于低32位,但这是不正确的,它需要转换为无符号,没有CPU指令存在,所以它很慢。 .. IEEE doubles 和魔术常数的内部表示有一个技巧,例如:software.intel.com/en-us/forums/topic/301988,但不知道速度 这里有更好的解释(对于未签名):***.com/questions/13734191/… 【参考方案1】:你的第二个选项可以工作,虽然它有点笨拙。我假设您的 64 位数字最初位于 edx:eax 中。
cvtsi2sd xmm0, edx // high part * 2**-32
mulsd xmm0, [2**32 from mem] // high part
movsd xmm2, [2**52 from mem]
movd xmm1, eax
orpd xmm1, xmm2 // (double)(2*52 + low part as unsigned)
subsd xmm1, xmm2 // (double)(low part as unsigned)
addsd xmm0, xmm1 // (double)(high part + low part as unsigned)
除了可能的最后一个之外的所有操作都是精确的,所以这是正确的四舍五入。应该注意的是,当输入为0
并且mxcsr
设置为round-to-minus-infinity 时,此转换会产生-0.0
。如果它被用于旨在提供 IEEE-754 一致性的编译器的运行时库中,则需要解决此问题,但对于大多数使用而言这不是问题。
【讨论】:
以上是关于将 64 位整数加载到双精度 SSE2 寄存器的最佳方法?的主要内容,如果未能解决你的问题,请参考以下文章
用于灰度到 ARGB 转换的 C++ SSE2 或 AVX2 内在函数
如何在 x86(32 位)程序集中将无符号整数转换为浮点数?