[英]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.