Why is x86 JIT smarter than x64?
I am 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 encloses the asm method Get4S
and Get4
code:
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 working under x64 we get the same asm method for a method Get4S
, 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 assumed that the x64
JIT unwraps the loop and then sees that the result can be computed at compile time, and the compile-time function will be included. But none of this happened.
Why is it x64
so stupid in this case? ..
source to share
I understood. This is because RyuJIT is used when selecting x64
build even if the target platform is selected .Net 4.5.2
. So I fixed it by adding this section to the App.Config file:
<configuration>
<runtime>
<useLegacyJit enabled="1" />
</runtime>
</configuration>
This markup allows for "legacy" x64 JITs (quoted because I think it's much better than the "shiny" RyuJIT) and the ASM result in the 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 were evaluated at compile time and within their values.
Conclusion: When installed .Net 4.6
, the old x64 jitter is replaced with RyuJIT
for all solutions under CLR4.0
. So the only way to turn it off is with a useLegacyJit
switch or COMPLUS_AltJit
an environment variable
source to share