Search code examples
c#.netassemblyil.net-4.5.2

Why x86 JIT is smarter than x64?


I'm running a very simple program

    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;
    }

when it works under x86 it inlines Get4S method and Get4 asm code is:

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 

BUT when running under x64 we get same asm for Get4S method, but Get4 asm is not optimized at all:

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

I supposed that x64 JIT unroll the loop, then see that result can be computed in compile-time, and function with compile-time result will be inlined. But nothing from it happend.

Why x64 is so stupid in this case?..


Solution

  • I got the point. It's because RyuJIT is used when x64 build is selected, even if .Net 4.5.2 target platform is selected. So i fixed it by adding this section in App.Config file:

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

    This markup enables "legacy" x64 JIT (in quotes, because I think he's much better than "shiny" RyuJIT), and result ASM in main method is:

    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 
    

    both methods was calculated in compile time and inlined by theirs values.

    Conclusion: When .Net 4.6 is installed, old x64 jitter is replaced by RyuJIT for all solutions under CLR4.0. So only way to turn it off is useLegacyJit switch or COMPLUS_AltJit environment variable