微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

c# – 编译器何时优化我的代码

I’m trying to build a code sample显示编译器与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,string)
  IL_007c:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_0081:  ret
} // end of method Program::Main

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

解决方法

这是由Release版本中的抖动生成代码
0000003e  mov         ecx,14h

当知道操作数值时,优化器太聪明,无法生成乘法代码.如果更换nr = 5;使用nr = int.Parse(“5”),使得抖动不能知道操作数值,然后生成此乘法的代码

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

这利用内置在cpu中的地址生成逻辑中的乘数,允许指令与另一个使用ALU的指令重叠.这使得乘法基本上是免费的.这是64位抖动的输出,32位抖动产生:

0000004d  shl         edi,2

这是你所希望的.我记录了this post中抖动执行的优化方式.

原文地址:https://www.jb51.cc/csharp/92711.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐