2011-08-16 4 views
9

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 

私は、コンパイラがSHLステートメントにMUL文を最適化するだろうと思いましたか?
私のILの知識は非常に限られています(存在しない場合)。

+2

もし 'mul'が' shl'に最適化されていて、それがそうであってもいなくてもわからないのですが、ILがプラットフォーム固有のコードに組み込まれているときにほぼ確実に実行されます。 – LukeH

答えて

7

これはリリースビルドでのジッタによって生成されたコードです:

0000003e mov   ecx,14h 

オプティマイザは、それはオペランド値を知っているとき、乗算のためのコードを生成するにはあまりにもスマートです。 nr = 5を置き換えた場合。上のアドレス生成ロジックに組み込まれた乗数を利用しています

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

:ジッタは、オペランド値を知ることができないように、NR = int.Parse(「5」)、それは乗算のために、このコードを生成してALUを使用する別の命令によって命令がオーバーラップされることを可能にする。乗算は基本的に自由になります。これは、64ビット・ジッタのための出力ですが、32ビットのジッタは、この生成します:あなたが望んでいたものです

0000004d shl   edi,2 

。私はthis postのジッタによって行われた最適化の種類を文書化しました。

+0

恐ろしい、thx割当! –

7

"最適化"フラグは、C#からILへのコンパイル段階では大したことではありません。それはですは、この種のもののために違いはありません。

私はそのような最適化がJITコンパイラによって処理されると予想します。

+0

CSCが最適化しているものが何であるかについてのドキュメンテーションや話題がありますか? – Zenwalker

+0

@zenwalker:これは私が知っていることではありません。コンパイラチームが実装の詳細としてリリース間で変更できるべきものです。あなたはそれについてのいくつかのブログ記事を見つけるかもしれません... –

+5

@zenwalker:http://blogs.msdn.com/b/ericlippert/archive/2009/06/11/what-does-the-optimize-switch-do。 aspx – LukeH

関連する問題