简体   繁体   English

C#中质量差的编译器优化

[英]Poor quality compiler optimization in c#

I don't know why but I watched the IL generated from the standard c# compiler (VS2015) and it's dramatically non optimized in release mode. 我不知道为什么,但是我看到了从标准c#编译器(VS2015)生成的IL,并且在发布模式下它没有经过优化。

The code that I tested is very simple: 我测试的代码非常简单:

static void Main(string[] args)
    {
        int count = 25 + 7/3;
        count += 100;
        Console.WriteLine("{0}", count);
    }

The IL output in debug mode is: 调试模式下的IL输出为:

// [12 9 - 12 10]
IL_0000: nop          

// [34 13 - 34 34]
IL_0001: ldc.i4.s     27 // 0x1b
IL_0003: stloc.0      // count

// [35 13 - 35 26]
IL_0004: ldloc.0      // count
IL_0005: ldc.i4.s     100 // 0x64
IL_0007: add          
IL_0008: stloc.0      // count

// [36 13 - 36 45]
IL_0009: ldstr        "{0}"
IL_000e: ldloc.0      // count
IL_000f: box          [mscorlib]System.Int32
IL_0014: call         void [mscorlib]System.Console::WriteLine(string, object)
IL_0019: nop          

// [37 9 - 37 10]
IL_001a: ret          

and the code in Release mode is: 释放模式下的代码是:

 IL_0000: ldc.i4.s     27 // 0x1b
IL_0002: stloc.0      // V_0
IL_0003: ldloc.0      // V_0
IL_0004: ldc.i4.s     100 // 0x64
IL_0006: add          
IL_0007: stloc.0      // V_0
IL_0008: ldstr        "{0}"
IL_000d: ldloc.0      // V_0
IL_000e: box          [mscorlib]System.Int32
IL_0013: call         void [mscorlib]System.Console::WriteLine(string, object)
IL_0018: ret  

Now, Why the compiler are not perform the sum (27 + 100) and direct call WriteLine with 127 ? 现在,为什么编译器不执行总和(27 + 100)并直接用127调用WriteLine?

I tried the same sample in c++ and it works as expected. 我在c ++中尝试了相同的示例,并且按预期工作。

There's some special flag to perform this kind optimization? 有一些特殊的标志可以执行这种优化吗?

UPDATE: I try the same code on MONO 4.6.20 and the result in release mode is the following 更新:我在MONO 4.6.20上尝试相同的代码,发布模式下的结果如下

 // method line 2
.method private static hidebysig
       default void Main (string[] args)  cil managed
{
    // Method begins at RVA 0x2058
    .entrypoint
    // Code size 18 (0x12)
    .maxstack 8
    IL_0000:  ldstr "{0}"
    IL_0005:  ldc.i4.s 0x7f
    IL_0007:  box [mscorlib]System.Int32
    IL_000c:  call void class [mscorlib]System.Console::WriteLine(string, ob                                                                                                                               ject)
    IL_0011:  ret
} // end of method Program::Main

You can't rely on the IL output of the compiler to accurately assess how optimized the code is, because the JIT is going to get its hand on the IL at runtime to generate the actual code to run. 您不能依靠编译器的IL输出来准确评估代码的优化程度,因为JIT将在运行时获得IL的帮助,以生成要运行的实际代码。 In this case the actual x64 emitted by the JIT (in Release mode for Any CPU without Prefer 32-bit) looks like this: 在这种情况下,JIT发出的实际x64(对于任何不具有首选32位的CPU处于释放模式)如下所示:

sub         rsp,28h  
mov         rcx,7FFF85323E98h  
call        00007FFF91C72530  ; I'm not sure what this call does, I assume it's allocating memory for the boxed int
mov         rcx,20CA5CB3648h  
mov         rcx,qword ptr [rcx]  ; After this rcx is actually pointing to the string "{0}"
mov         dword ptr [rax+8],7Fh ; Box the value 127 into the object that rax points at
mov         rdx,rax  
call        00007FFF85160070  ; Call Console.WriteLine with its arguments in rcx and rdx
nop  
add         rsp,28h  
ret  

So the extra edition gets elided. 因此,多余的版本被删除了。

If I turn on "Prefer 32-bit", the emitted x86 looks like this: 如果我打开“首选32位”,则发出的x86如下所示:

mov         ecx,72041638h  
call        011630F4  ; presumably allocating memory for the boxed int
mov         edx,eax  
mov         eax,dword ptr ds:[40E232Ch] ; loads a pointer to "{0}" into eax
mov         dword ptr [edx+4],7Fh  ; boxes 127 into object pointed at by edx
mov         ecx,eax  
call        71F373F4  ; calls Console.WriteLine with arguments in ecx and edx
ret  

In both cases the JIT optimized out the local variable as well as the extra addition operations. 在这两种情况下,JIT都会优化局部变量以及额外的加法运算。 Since the JIT performs so many optimizations, you'll find that the C# compiler itself doesn't go to great lengths to optimize anything. 由于JIT执行了许多优化,因此您会发现C#编译器本身并没有竭尽全力来优化任何东西。

tl;dr The emitted IL from the C# compiler is not what the machine runs and so is not generally representative of the sorts of optimizations will be applied. tl; dr从C#编译器发出的IL不是计算机运行的IL,因此通常不代表将应用的优化类型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM