C++ 内联汇编程序直接双到长转换

C++ 内联汇编程序直接双到长转换,c++,visual-studio-2005,x86,inline-assembly,C++,Visual Studio 2005,X86,Inline Assembly,由于优化的原因,我考虑直接调用(使用内联汇编程序) 功能“fldl”和“fist”。可悲的是,我不知道如何运行它,因为我不是汇编程序中的上帝 我没有比这更进一步: double* input; long long output; __asm fldl input; __asm fist output; \u asm fld input将实际尝试读取指针值,就像它是浮点值一样。如果要读取指针指向的浮点值,必须经过两步过程:将地址读入寄存器,然后使用寄存器中的地址读

由于优化的原因,我考虑直接调用(使用内联汇编程序) 功能“fldl”和“fist”。可悲的是,我不知道如何运行它,因为我不是汇编程序中的上帝

我没有比这更进一步:

double* input;         
long long output;

__asm fldl input;      
__asm fist output;

\u asm fld input
将实际尝试读取指针值,就像它是浮点值一样。如果要读取指针指向的浮点值,必须经过两步过程:将地址读入寄存器,然后使用寄存器中的地址读取数据。在32位平台上,它将与

__asm {
  mov eax, input
  fld qword ptr [eax]
  fistp output
}

我刚刚在VS2005中试用过,效果不错。(请注意,正如其他人在评论中所说,
fist
不支持存储到64位
long
,而
fistp
支持。但您可能需要
fistp
,即弹出式存储。)

最简单的可能是:

double input;
long long output;

__asm fld input
__asm fisttp output
这会进行“正常”的双到长转换,向零截断,就像C转换一样。非常旧的(奔腾4之前的)CPU不支持
fistpp
,但是,在这样的机器上,您需要使用
fistp
,它使用当前的舍入模式(通常舍入到最近)。因此,如果您希望eg向-无穷大取整,则需要保存当前取整模式,将其设置为所需,执行
fistp
并恢复取整模式:

double input;
long long output;
unsigned short oldcw, cw;

__asm fld input
__asm fstcw oldcw
cw = (oldcw & ~0xc00) | 0x400; // round towards -infinity
__asm fldcw cw
__asm fistp output
__asm fldcw oldcw

除非您继续使用该值,否则您可能希望使用
fistp
而不是
fist
。有一个小问题,那就是它是x86体系结构,因此没有rax注册表所以
fist
转换为32位整数,而不是
long
,而不像
fistp
(操作码DF/7).@chill:MSVC++内联汇编程序会根据收件人变量的大小自动选择适当的操作码。因此,这里的
fist
fistp
之间的选择仅取决于OP是否希望从FPU弹出结果stack@AndreyT:x86指令编码不一致--
fist
仅支持16位和32位操作数,
fistp
fisttp
支持16位和32位操作数,如果您的汇编程序不够流利,无法调用函数,那么您可能应该让编译器进行优化。要想通过手工调优超越现代优化编译器,您必须具备非常好的汇编能力和经验。与编译器相比,我真的怀疑手动将double转换为long int会导致任何优化。这是一个非常简单的操作,很可能会导致性能下降——因为编译器通常可以“查看”每条指令之外的内容。(结果是否需要,存储在哪个寄存器中;是否最好放在xmm寄存器中等)@H2CO3:我想说,甚至可能是上帝。@AkiSuihkonen,从double到integer的转换在留给编译器时被认为是次要的,因为它不能做出任何简化的假设。尽管这可能已经过时了,但这可能是真的。例如,gcc 4.6.3允许自己做出一些假设,只需编写
cvttsd2siq%xmm0,%rax
(是的,不幸的是,附近没有x86系统,只有x64)