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,
[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
我认为编译器会将mul语句优化为shl语句?
我对IL的了解非常有限(如果不存在的话)。
答案 0 :(得分:7)
“优化”标志在C#到IL编译阶段并没有太大的作用。它确实有所作为,但不是出于这种情况。
我希望JIT编译器能够处理这种优化。
答案 1 :(得分:7)
这是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中抖动执行的优化类型。