2011-08-16 3 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 

Я думал, что компилятор будет оптимизировать мула заявление на ШЛ заявление?
Мои знания об ИЛ очень ограничены (если не несуществующие).

+2

Если 'mul' действительно оптимизирован в' shl' - и я понятия не имею, делает оно это или нет, это почти наверняка будет сделано, когда IL превратится в код платформы. – LukeH

ответ

7

Это код, сгенерированный джиттер в сборке Release:

0000003e mov   ecx,14h 

Оптимизатор слишком умен, чтобы сгенерировать код для умножения, когда он знает значение операндов. Если вы замените nr = 5; с пгом = int.Parse («5»), так что джиттер не может знать значение операндов, то он генерирует этот код для умножения:

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

который использует мультипликатор встроенного в логику генерации адреса на cpu, позволяя команде перекрываться другой инструкцией, которая использует ALU. Это делает размножение по существу бесплатным. Это выход для 64-битного джиттера, 32-битный джиттера генерирует это:

0000004d shl   edi,2 

Что то, что вы надеялись. Я задокументировал вид оптимизации, выполненный дрожанием в this post.

+0

Awesome, thx allot! –

7

Флаг «optimize» не делает очень много на этапе компиляции 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

Смежные вопросы