Intel x86_64 程序集,如何从 xmm 寄存器到 int 加倍?
Intel x86_64 assembly, how to floor double from xmm register to int?
我该怎么做?如果结果将在 e*x 寄存器中,那将是最好的。
地板双打使用CVTTPD2DQ—Convert with Truncation Packed Double-Precision FP Values to Packed Dword Integers。
CVTTPD2DQ
在 XMM 寄存器中执行 floor/trunctate 两个 double
到两个 int
。
对应的Intel C/C++ Compiler Intrinsic是
____m128i _mm_cvttpd_epi32(__m128d a)
要像EAX
一样把结果放到GPR(General Purpose Register)中,可以使用下面的指令:
CVTTPD2DQ xmm0, xmm1 ; XMM1 is the source of doubles
movd eax, xmm0 ; extracts int(0) from XMM0 to EAX
pextrd ecx, xmm0, 1 ; extracts int(1) from XMM0 to ECX
您问了几个微不足道的问题,只需查看 C 编译器的工作原理即可回答这些问题。从那里,您可以查看它使用的说明,并决定您要实际使用哪些。 (libm 中大约有无数种不同的舍入函数,因此首先选择正确的函数并不总是那么容易)。
使用 -O3 -ffast-math
获取内联的最简单的 libm 函数(因为它不必潜在地在 NaN 上设置 errno
,或类似的废话)。
无论如何,编译器输入输出,来自gcc 5.3 on the Godbolt Compiler Explorer:
#include <math.h>
int floor_double(double x) { return (int) floor(x); }
roundsd xmm0, xmm0, 9
cvttsd2si eax, xmm0
ret
int truncate_double(double x) { return (int)x; }
cvttsd2si eax, xmm0
ret
查看从 PDF 生成的 x86 tag wiki for links to Intel's instruction set reference manual pdf. There's also an unofficial HTML version。
cvttsd2si
truncates towards zero, like trunc()
, instead of rounding towards -Infinity like the floor()
function.
这就是为什么 floor()
在该指令集可用时编译为 SSE4.1 roundsd
的原因。 (否则它必须 fiddle 使用舍入模式,正如您通过删除或更改 godbolt 上的 -march
选项所看到的那样)。
还有压缩版本的转换指令,例如 CVTTPD2DQ` 一次执行 2 个。 (或 4 个带 AVX)。
我该怎么做?如果结果将在 e*x 寄存器中,那将是最好的。
地板双打使用CVTTPD2DQ—Convert with Truncation Packed Double-Precision FP Values to Packed Dword Integers。
CVTTPD2DQ
在 XMM 寄存器中执行 floor/trunctate 两个 double
到两个 int
。
对应的Intel C/C++ Compiler Intrinsic是
____m128i _mm_cvttpd_epi32(__m128d a)
要像EAX
一样把结果放到GPR(General Purpose Register)中,可以使用下面的指令:
CVTTPD2DQ xmm0, xmm1 ; XMM1 is the source of doubles
movd eax, xmm0 ; extracts int(0) from XMM0 to EAX
pextrd ecx, xmm0, 1 ; extracts int(1) from XMM0 to ECX
您问了几个微不足道的问题,只需查看 C 编译器的工作原理即可回答这些问题。从那里,您可以查看它使用的说明,并决定您要实际使用哪些。 (libm 中大约有无数种不同的舍入函数,因此首先选择正确的函数并不总是那么容易)。
使用 -O3 -ffast-math
获取内联的最简单的 libm 函数(因为它不必潜在地在 NaN 上设置 errno
,或类似的废话)。
无论如何,编译器输入输出,来自gcc 5.3 on the Godbolt Compiler Explorer:
#include <math.h>
int floor_double(double x) { return (int) floor(x); }
roundsd xmm0, xmm0, 9
cvttsd2si eax, xmm0
ret
int truncate_double(double x) { return (int)x; }
cvttsd2si eax, xmm0
ret
查看从 PDF 生成的 x86 tag wiki for links to Intel's instruction set reference manual pdf. There's also an unofficial HTML version。
cvttsd2si
truncates towards zero, like trunc()
, instead of rounding towards -Infinity like the floor()
function.
这就是为什么 floor()
在该指令集可用时编译为 SSE4.1 roundsd
的原因。 (否则它必须 fiddle 使用舍入模式,正如您通过删除或更改 godbolt 上的 -march
选项所看到的那样)。
还有压缩版本的转换指令,例如 CVTTPD2DQ` 一次执行 2 个。 (或 4 个带 AVX)。