.NET JIT 是否会内联一个调用另一个小函数的小函数?

发布于 2024-09-12 02:48:31 字数 352 浏览 7 评论 0原文

我想知道 - .NET JITter 是否会递归内联从其他小函数调用的小函数?

举个例子:

public static float Square(float value)
{
    return value * value;
}

public static float Cube(float value)
{
    return Square(value) * value;
}

如果我从某个地方调用 Cube ,它会一直内联,还是最终会调用 Square 的函数?

如果是这样,它会递归多深来进行内联? (假设我疯狂地以同样的方式实现了 Quartic 或 Quintic 函数。)

I would like to know - will the .NET JITter recursively inline small functions called from other small functions?

Just for example:

public static float Square(float value)
{
    return value * value;
}

public static float Cube(float value)
{
    return Square(value) * value;
}

If I call Cube from somewhere, will it inline all the way, or will I end up with a function call to Square?

And, if so, how deep will it recurse to do the inlining? (Say I were crazy enough to implement a Quartic or Quintic function in the same way.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

余生一个溪 2024-09-19 02:48:31

不幸的是你选了一个不好的例子。 x86 JIT 编译器不内联返回浮点型的方法。不是 100% 确定原因,我认为它确实可以避免在 FPU 中将浮点数转换为 80 位浮点值时出现一致的问题。内部精度为 80 位,但当 80 位值刷新回内存时被截断回 32 位值时,这些额外的位将被切掉。将值保留在 FPU 中的时间过长可以防止发生这种截断并更改计算结果。

如果将 float 替换为 double 并编译此代码:

static void Main(string[] args) {
    Console.WriteLine(Cube(2.0));
}

那么启用 JIT 优化器时会生成此机器代码:

00000000  push        ebp                             ; setup stack frame
00000001  mov         ebp,esp 
00000003  call        6DA2BEF0                        ; Console.get_Out() 
00000008  fld         qword ptr ds:[010914B0h]        ; ST0 = 8.0
0000000e  sub         esp,8                           ; setup argument for WriteLine
00000011  fstp        qword ptr [esp] 
00000014  mov         ecx,eax                         ; call Console.Out.WriteLine
00000016  mov         eax,dword ptr [ecx] 
00000018  call        dword ptr [eax+000000D0h] 
0000001e  pop         ebp                             ; done
0000001f  ret

它不仅内联函数,还能够在编译时计算表达式。并通过调用Console.WriteLine(8.0)直接传递结果。相当不错吧?

使用双精度,而不是浮动。

Unfortunately you picked a bad example. The x86 JIT compiler doesn't inline methods that return float. Not 100% sure why, I think it does to avoid consistently problems when the float is converted to an 80-bit floating point value in the FPU. Internal precision is 80-bits but those extra bits are sliced off when the 80-bit value is truncated back to a 32-bit value when it is flushed back to memory. Keeping the value in the FPU too long prevents this truncation from happening and changes the calculation result.

If you replace float by double and compile this code:

static void Main(string[] args) {
    Console.WriteLine(Cube(2.0));
}

Then this machine code is generated when the JIT optimizer is enabled:

00000000  push        ebp                             ; setup stack frame
00000001  mov         ebp,esp 
00000003  call        6DA2BEF0                        ; Console.get_Out() 
00000008  fld         qword ptr ds:[010914B0h]        ; ST0 = 8.0
0000000e  sub         esp,8                           ; setup argument for WriteLine
00000011  fstp        qword ptr [esp] 
00000014  mov         ecx,eax                         ; call Console.Out.WriteLine
00000016  mov         eax,dword ptr [ecx] 
00000018  call        dword ptr [eax+000000D0h] 
0000001e  pop         ebp                             ; done
0000001f  ret

Not only did it inline the functions, it was able to evaluate the expressions at compile time. And directly passes the result by calling Console.WriteLine(8.0). Pretty good huh?

Use double, not float.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文