什么时候编译器优化我的代码

本文关键字:代码 我的 优化 编译器 什么时候 | 更新日期: 2023-09-27 18:05:47

我试图构建一个代码示例,以显示编译器在与2数的幂相乘时对代码的优化。然而,当我打开优化代码时,IL基本保持不变。知道我哪里做错了吗?

代码:

int nr;
int result;
var stopwatch = new Stopwatch();
nr = 5;
stopwatch.Start();
    result = nr * 4;
stopwatch.Stop();
Console.WriteLine(result);
Console.WriteLine(stopwatch.Elapsed.ToString() + "ms ellapsed");
stopwatch.Reset();
stopwatch.Start();
result = nr << 2;
stopwatch.Stop();
Console.WriteLine(result);
Console.WriteLine(stopwatch.Elapsed.ToString() + "ms ellapsed");

非优化IL:

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       130 (0x82)
  .maxstack  2
  .locals init ([0] int32 nr,
           [1] int32 result,
           [2] class [System]System.Diagnostics.Stopwatch stopwatch,
           [3] valuetype [mscorlib]System.TimeSpan CS$0$0000,
           [4] valuetype [mscorlib]System.TimeSpan CS$0$0001)
  IL_0000:  newobj     instance void [System]System.Diagnostics.Stopwatch::.ctor()
  IL_0005:  stloc.2
  IL_0006:  ldc.i4.5
  IL_0007:  stloc.0
  IL_0008:  ldloc.2
  IL_0009:  callvirt   instance void [System]System.Diagnostics.Stopwatch::Start()
  IL_000e:  ldloc.0
  IL_000f:  ldc.i4.4
  IL_0010:  mul
  IL_0011:  stloc.1
  IL_0012:  ldloc.2
  IL_0013:  callvirt   instance void [System]System.Diagnostics.Stopwatch::Stop()
  IL_0018:  ldloc.1
  IL_0019:  call       void [mscorlib]System.Console::WriteLine(int32)
  IL_001e:  ldloc.2
  IL_001f:  callvirt   instance valuetype [mscorlib]System.TimeSpan [System]System.Diagnostics.Stopwatch::get_Elapsed()
  IL_0024:  stloc.3
  IL_0025:  ldloca.s   CS$0$0000
  IL_0027:  constrained. [mscorlib]System.TimeSpan
  IL_002d:  callvirt   instance string [mscorlib]System.Object::ToString()
  IL_0032:  ldstr      "ms ellapsed"
  IL_0037:  call       string [mscorlib]System.String::Concat(string,
                                                              string)
  IL_003c:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_0041:  ldloc.2
  IL_0042:  callvirt   instance void [System]System.Diagnostics.Stopwatch::Reset()
  IL_0047:  ldloc.2
  IL_0048:  callvirt   instance void [System]System.Diagnostics.Stopwatch::Start()
  IL_004d:  ldloc.0
  IL_004e:  ldc.i4.2
  IL_004f:  shl
  IL_0050:  stloc.1
  IL_0051:  ldloc.2
  IL_0052:  callvirt   instance void [System]System.Diagnostics.Stopwatch::Stop()
  IL_0057:  ldloc.1
  IL_0058:  call       void [mscorlib]System.Console::WriteLine(int32)
  IL_005d:  ldloc.2
  IL_005e:  callvirt   instance valuetype [mscorlib]System.TimeSpan [System]System.Diagnostics.Stopwatch::get_Elapsed()
  IL_0063:  stloc.s    CS$0$0001
  IL_0065:  ldloca.s   CS$0$0001
  IL_0067:  constrained. [mscorlib]System.TimeSpan
  IL_006d:  callvirt   instance string [mscorlib]System.Object::ToString()
  IL_0072:  ldstr      "ms ellapsed"
  IL_0077:  call       string [mscorlib]System.String::Concat(string,
                                                              string)
  IL_007c:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_0081:  ret
} // end of method Program::Main

优化IL:

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       130 (0x82)
  .maxstack  2
  .locals init ([0] int32 nr,
           [1] int32 result,
           [2] class [System]System.Diagnostics.Stopwatch stopwatch,
           [3] valuetype [mscorlib]System.TimeSpan CS$0$0000,
           [4] valuetype [mscorlib]System.TimeSpan CS$0$0001)
  IL_0000:  newobj     instance void [System]System.Diagnostics.Stopwatch::.ctor()
  IL_0005:  stloc.2
  IL_0006:  ldc.i4.5
  IL_0007:  stloc.0
  IL_0008:  ldloc.2
  IL_0009:  callvirt   instance void [System]System.Diagnostics.Stopwatch::Start()
  IL_000e:  ldloc.0
  IL_000f:  ldc.i4.4
  IL_0010:  mul
  IL_0011:  stloc.1
  IL_0012:  ldloc.2
  IL_0013:  callvirt   instance void [System]System.Diagnostics.Stopwatch::Stop()
  IL_0018:  ldloc.1
  IL_0019:  call       void [mscorlib]System.Console::WriteLine(int32)
  IL_001e:  ldloc.2
  IL_001f:  callvirt   instance valuetype [mscorlib]System.TimeSpan [System]System.Diagnostics.Stopwatch::get_Elapsed()
  IL_0024:  stloc.3
  IL_0025:  ldloca.s   CS$0$0000
  IL_0027:  constrained. [mscorlib]System.TimeSpan
  IL_002d:  callvirt   instance string [mscorlib]System.Object::ToString()
  IL_0032:  ldstr      "ms ellapsed"
  IL_0037:  call       string [mscorlib]System.String::Concat(string,
                                                              string)
  IL_003c:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_0041:  ldloc.2
  IL_0042:  callvirt   instance void [System]System.Diagnostics.Stopwatch::Reset()
  IL_0047:  ldloc.2
  IL_0048:  callvirt   instance void [System]System.Diagnostics.Stopwatch::Start()
  IL_004d:  ldloc.0
  IL_004e:  ldc.i4.2
  IL_004f:  shl
  IL_0050:  stloc.1
  IL_0051:  ldloc.2
  IL_0052:  callvirt   instance void [System]System.Diagnostics.Stopwatch::Stop()
  IL_0057:  ldloc.1
  IL_0058:  call       void [mscorlib]System.Console::WriteLine(int32)
  IL_005d:  ldloc.2
  IL_005e:  callvirt   instance valuetype [mscorlib]System.TimeSpan [System]System.Diagnostics.Stopwatch::get_Elapsed()
  IL_0063:  stloc.s    CS$0$0001
  IL_0065:  ldloca.s   CS$0$0001
  IL_0067:  constrained. [mscorlib]System.TimeSpan
  IL_006d:  callvirt   instance string [mscorlib]System.Object::ToString()
  IL_0072:  ldstr      "ms ellapsed"
  IL_0077:  call       string [mscorlib]System.String::Concat(string,
                                                              string)
  IL_007c:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_0081:  ret
} // end of method Program::Main

我认为编译器会优化多语句到一个shl语句?
我对IL的了解非常有限(如果不是不存在的话)。

什么时候编译器优化我的代码

这是在发布版本中由抖动产生的代码:

0000003e  mov         ecx,14h 

优化器太聪明了,当它知道操作数的值时,不会为乘法生成代码。如果将nr = 5;与nr = int.Parse("5"),使抖动无法知道操作数的值,然后它生成以下代码的乘法:

0000005c  lea         ebx,[rdi*4+00000000h] 

它利用了cpu地址生成逻辑中的乘数,允许该指令与使用ALU的另一条指令重叠。这使得乘法本质上是自由的。这是64位抖动的输出,32位抖动产生如下内容:

0000004d  shl         edi,2 

这正是你所希望的。我在这篇文章中记录了抖动所执行的优化。

"优化"标志在c#到IL编译阶段并没有多大作用。它确实起作用,但不是用于这种事情。

我希望JIT编译器可以处理这种优化。