我正在用C#编写一些数学代码,强制它在发布时编译为x86,进行了优化,我正在查看windbg中的反汇编。它通常都很好,经常写出比我更好的装配(不是说我在组装方面都很擅长,但你去了)。
但是,我注意到了这个功能:
static void TemporaryWork()
{
double x = 4;
double y = 3;
double z = Math.Atan2(x, y);
}
正在制作这个反汇编:
001f0078 55 push ebp
001f0079 8bec mov ebp,esp
001f007b dd05a0001f00 fld qword ptr ds:[1F00A0h]
001f0081 83ec08 sub esp,8
001f0084 dd1c24 fstp qword ptr [esp]
001f0087 dd05a8001f00 fld qword ptr ds:[1F00A8h]
001f008d 83ec08 sub esp,8
001f0090 dd1c24 fstp qword ptr [esp]
001f0093 e86e9ba66f call clr!GetHashFromBlob+0x94e09 (6fc59c06) (System.Math.Atan2(Double, Double), mdToken: 06000de7)
001f0098 ddd8 fstp st(0)
001f009a 5d pop ebp
001f009b c3 ret
即使你不是x86大师,你也会注意到有些奇怪的东西:有一个对System.Math.Atan2的调用。与在函数调用中一样。
但实际上有一个x86操作码可以做到这一点:FPATAN
为什么JITer在有实际的汇编指令进行操作时调用函数?我认为System.Math基本上是本机程序集指令的包装器。其中的大多数操作都有直接的汇编操作码。但事实并非如此?
有没有人知道为什么JITer不能/不能执行这个相当明显的优化?
答案 0 :(得分:5)
您可以从this answer中追溯原因,它会显示抖动如何映射这些数学函数。
将你带到clr / src / classlibnative / float / comfloat.cpp,ComDouble :: Atan2()函数。这解释了原因:
// the intrinsic for Atan2 does not produce Nan for Atan2(+-inf,+-inf)
if (IS_DBL_INFINITY(x) && IS_DBL_INFINITY(y)) {
return(x / y); // create a NaN
}
return (double) atan2(x, y);
因此,解决不符合CLI的FPU行为是一种解决方法。