我正在运行一个非常简单的程序

    static void Main(string[] args)
    {
        Console.WriteLine(Get4S());
        Console.WriteLine(Get4());
    }

    private static int Get4S()
    {
        return 4;
    }

    private static int Get4()
    {
        int res = 0;
        for (int i = 0; i < 4; i++)
        {
            res++;
        }
        return res;
    }


当它在x86下工作时,它会内联Get4S方法,而Get4 asm代码是:

00000000  push        ebp
00000001  mov         ebp,esp
00000003  xor         eax,eax
00000005  inc         eax
00000006  inc         eax
00000007  inc         eax
00000008  inc         eax
00000009  pop         ebp
0000000a  ret


但是在x64下运行时,我们为Get4S方法获得了相同的asm,但是Get4 asm并未完全优化:

00000000  xor         eax,eax
00000002  xor         edx,edx
00000004  inc         eax
00000006  inc         edx
00000008  cmp         edx,4
0000000b  jl          0000000000000004
0000000d  ret


我以为x64 JIT展开了循环,然后看到可以在编译时计算结果,并且将内联具有编译时结果的函数。但是什么也没发生。

为什么x64在这种情况下如此愚蠢?

最佳答案

我明白了。这是因为即使选择了x64目标平台,在选择.Net 4.5.2构建时也会使用RyuJIT。所以我通过在App.Config文件中添加此部分来修复它:

<configuration>
  <runtime>
    <useLegacyJit enabled="1" />
  </runtime>
</configuration>


此标记启用“传统” x64 JIT(用引号引起来,因为我认为他比“发光的” RyuJIT更好),结果主要方法中的ASM为:

00000000  sub         rsp,28h
00000004  mov         ecx,4
00000009  call        000000005EE75870
0000000e  mov         ecx,4
00000013  call        000000005EE75870
00000018  nop
00000019  add         rsp,28h
0000001d  ret


两种方法都是在编译时计算的,并按其值进行内联。

结论:安装.Net 4.6时,对于RyuJIT下的所有解决方案,旧的x64抖动将替换为CLR4.0。因此,将其关闭的唯一方法是useLegacyJit开关或COMPLUS_AltJit环境变量

关于c# - 为什么x86 JIT比x64更聪明?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/29509304/

10-13 08:05