2011-08-16 34 views
9

I'm trying to build a code sample để hiển thị tối ưu hóa mã bằng trình biên dịch khi nhân với lũy thừa là 2 số. Tuy nhiên, khi tôi bật mã Optimize trên IL vẫn chủ yếu là như nhau. Bất kỳ ý tưởng những gì tôi đang làm sai ở đây?Khi nào trình biên dịch tối ưu hóa mã của tôi

Mã:

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"); 

Non Optimized 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 

Tối ưu hóa 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 

Tôi nghĩ trình biên dịch sẽ tối ưu hóa các tuyên bố mul một tuyên bố SHL?
Kiến thức của tôi về IL rất hạn chế (nếu không phải là không tồn tại).

+2

Nếu 'mul' được tối ưu hóa thành' shl' - và tôi không biết nó có hoạt động hay không - nó gần như chắc chắn sẽ được thực hiện khi IL được đưa vào mã nền tảng cụ thể. – LukeH

Trả lời

7

Đây là mã được tạo ra bởi các jitter trong Release build:

0000003e mov   ecx,14h 

Các ưu là quá thông minh để tạo mã cho một phép nhân khi nó biết các giá trị toán hạng. Nếu bạn thay thế nr = 5; với nr = int.Parse ("5") để các jitter không thể biết giá trị toán hạng sau đó nó tạo ra mã này cho phép nhân:

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

nào tận dụng nhân xây dựng vào logic thế hệ địa chỉ trên cpu, cho phép lệnh được chồng chéo bởi lệnh khác sử dụng ALU. Mà làm cho phép nhân bản chất miễn phí. Đó là đầu ra cho các jitter 64-bit, 32-bit jitter tạo này:

0000004d shl   edi,2 

Đó là những gì bạn đã hy vọng. Tôi đã ghi lại loại tối ưu hóa được thực hiện bởi jitter trong this post.

+0

Tuyệt vời, thx allot! –

7

Cờ "tối ưu hóa" không thực hiện quá nhiều thứ trong giai đoạn biên dịch C# đến IL. Nó không tạo sự khác biệt, nhưng không phải cho loại điều này.

Tôi mong rằng loại tối ưu hóa đó sẽ được trình biên dịch JIT xử lý thay thế.

+0

Có tài liệu hoặc một số điều nói về chính xác những gì CSC tối ưu hóa không? – Zenwalker

+0

@zenwalker: Không phải là tôi biết - đó là thứ mà nhóm biên dịch phải có khả năng thay đổi giữa các bản phát hành dưới dạng chi tiết triển khai. Bạn cũng có thể tìm thấy một số bài đăng trên blog về nó ... –

+5

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

Các vấn đề liên quan