我正在使用MS Visual Studio(2005,但这不应该很重要)。 我有一个函数,其内部(必要)实现内联汇编:
double f(double x)
{
__asm{ ...body code... }
}
汇编代码完成,返回包含在ST0中的结果。 使用的调用约定是__cdecl,因此约定是在ST0中返回返回double值。因此,在完成__asm {... body code ...}代码之后,该函数已准备好运行并返回其返回的堆栈清理代码。但是,上面的代码当然不会编译,因为没有“返回dblVal;”声明。可以通过将代码更改为:
来更正double f(double x)
{
double dRet;
__asm{ ...body code... }
__asm{ fst dRet }
return dRet;
}
但这有两个缺点: (1)dRet的商店紧接着是fld dRet,这是完全浪费和不必要的(这在monte-carlo例程中被无数次使用,因此每个循环都很重要) (2)更重要的是,ST0中的值已经在体内精确计算到64位尾数精度,我需要保留,fst后跟fld完全杀死它。
如何告诉VisualStudio编译器要返回的double已经在ST0中? 我可以明确地写出退出代码:
double f(double x)
{
__asm{ ...body code... }
__asm{ __asm leave
__asm ret
}
return 0.0; //dummy code that is never executed, to make the compiler happy
}
然后必须知道编译器生成的入口代码(事实上,上面的退出代码是错误的)。所以我们可以更进一步,并写入条目代码和退出代码:
__declspec ( naked ) double f(double x)
{
__asm{ ...entry code...}
__asm{ ...body code... }
__asm{ ...exit code... }
return 0.0; //dummy code that is never executed, to make the compiler happy
}
但这一切都非常难看。那么,如何让编译器查看入口代码并退出代码,并告诉它返回值已经在ST0中?
答案 0 :(得分:2)
实际上,我的问题的答案是我在上述问题的陈述中有一件事是错的:
double f(double x)
{
__asm{ ...body code... }
}
没有任何return语句,在正文中使用__asm语句,编译得很好,没有任何错误或警告。编译器(正确地)假定我已经安排适当地传递/返回返回值。编译器正确地生成了入口和退出代码,并且很高兴将其余部分留给我。去图 - 为什么我认为我测试过并发现了编译错误?叹。对不起打扰每个人。
答案 1 :(得分:0)
你唯一的选择是裸函数,但它们不需要C return语句,也不需要堆栈帧。但是,除非你有充分的理由使用asm,否则你更喜欢在C语言中使用asm,主要是可移植性,另一种是特定于目标的优化,比如SIMD。