什么时候编译器优化我的代码
本文关键字:代码 我的 优化 编译器 什么时候 | 更新日期: 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编译器可以处理这种优化。