2

有没有办法在带有 SSE 扩展的 x86 中将四个打包的单精度浮点值转换为四个双字?最接近的指令是CVTPS2PI,但它不能在两个 xmm 寄存器上执行,而是应该作为CVTPS2PI MM, XMM/M64. 如果我想要类似的东西<conversion_mnemonic> XMM, XMM/M128怎么办?

谢谢。伊曼。

4

1 回答 1

0

x86 在 AVX512 之前没有对 FP<->unsigned 的原生支持,带有vcvtps2udq( https://www.felixcloutier.com/x86/vcvtps2udq )。对于标量,您通常只需转换为 64 位有符号 ( cvtss2si rax, xmm0) 并取其低 32 位(在 EAX 中),但这不是 SIMD 的选项。

如果没有 AVX-512,理想情况下您可以使用签名转换( cvtps2dq) 并获得相同的结果。即,如果您的浮点数是非负数且 <=INT_MAX ( 2147483647.0)。

请参阅如何使用 SSE/AVX 高效执行 double/int64 转换?对于相关的 double->uint64_t 转换。如果您需要,全范围的应该可以从 double->uint64_t 适应到 float->uint32_t。

另一种可能性(对于 32 位 float->uint32_t)只是范围移动到有符号的 FP,然后以整数形式返回。 INT32_MIN ^ convert(x + INT32_MIN). 但这引入了小整数的 FP 舍入,因为 INT32_MIN 在 -2 24 .. 2 24范围之外,其中 afloat可以表示每个整数。eg5将在转换期间四舍五入到最接近的 2 8倍数。所以那是不可用的;您需要尝试直接转换和范围移位转换,并且只有在直接转换给您的情况下才使用范围移位转换0x80000000。(也许使用直接转换结果作为 SSE4 的混合控制blendvps?)


对于 float->int32_t 的打包转换,有 SSE2 cvtps2dq xmm, xmm/m128 docs。(cvttps2dq用截断向 0 转换,而不是当前的默认舍入模式(最近的,如果你没有改变它)。)

任何小于 -0.5 的负浮点数将转换为整数 -1 或更低;因为uint32_t那个位模式代表了一个巨大的数字。超出 -2 31 ..2 31 -1 范围的浮点数将转换为0x80000000Intel 的“整数不定”值。


如果你没有找到,只有 cvtps2pi 签名转换为 MMX 寄存器,你需要更好的地方来搜索:

于 2020-10-29T19:07:36.780 回答