Reputation: 203
I used to be a C++ programer on Windows. I know that the compiler will optimizes the ternary operator in C++.
C++ code:
#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[])
{
int result = argc > 3 ? 1 : 5;
printf("%d", result);
return 0;
}
Because of the pipeline stuff, the generated native code is shown as below (of course Release model):
int result = argc > 3 ? 1 : 5;
00B21003 xor eax,eax
00B21005 cmp dword ptr [argc],3
00B21009 setle al
00B2100C lea eax,[eax*4+1]
C# code:
namespace TernaryOperatorCSharp
{
static void Main(string[] args)
{
int argc = args.Length;
int result = argc > 1 ? 2 : 5;
System.Console.WriteLine(result);
}
}
I looked up the native code JIT generated, but there is no optimization at all (still two jump instructions).
int result = argc > 1 ? 2 : 5;
0000002f cmp dword ptr [ebp-4],1
00000033 jg 0000003F
00000035 nop
00000036 mov dword ptr [ebp-0Ch],5
0000003d jmp 00000046
0000003f mov dword ptr [ebp-0Ch],2
00000046 mov eax,dword ptr [ebp-0Ch]
00000049 mov dword ptr [ebp-8],eax
System.Console.WriteLine(result);
0000004c mov ecx,dword ptr [ebp-8]
0000004f call 6A423CBC
Why doesn't the C# JIT compiler make the same optimization as C++ compiler does?
What's the story behind this?
Any information will be appreciated.
Hi there, I have modified the C# program and run it with release model.
Before
int result = args.Length > 1 ? 2 : 5;
Now
int argc = args.Length;
int result = argc > 1 ? 2 : 5;
But the result is still the same. There still two jump instruction exist. I will appreciate it if there is any further more information.
Upvotes: 13
Views: 628
Reputation: 12407
You're not compiling with optimizations - the nop
instruction is indicative of this (the compiler inserts these to use as anchors, so that you can put a breakpoint on a brace).
Visual Studio won't always produce optimized code, even if you have the 'optimize code' checkbox checked. Often when you launch in the debugger, it will disable optimizations anyway so that the debugging session behaves moreso as you would expect.
Furthermore, you're not comparing apples to apples, which accounts for a lot more of the cruft.
string[].Length
is a property in C#, not a public variable, and furthermore, not a local variable. Properties are often treated like public variables by consuming code, but in reality can exist as full-blown get/set methods. The compiler has to emit code to handle this, especially when the Property is defined in a separate assembly.
Try the example with a local int
variable, and with compiler optimizations turned on (build with optimizations, launch the program, attach the debugger after launching, view disassembly).
Upvotes: 11
Reputation: 941218
You are looking at the Debug build of the program. Switch to the Release build.
And you'll have to change an option so the optimizer doesn't get disabled when you use the debugger to look at the disassembly. Tools + Options, Debugging, General, untick the "Suppress JIT optimization on module load" option.
You'll now see more compact code. The x86 jitter does perform branch elimination and uses the AGU for math, you can see it being done in this answer, just not here. You are going to be disappointed if you expect exact parity with the optimizer of a C or C++ compiler, the jitter optimizer operates under pretty strict time constraints since it operates at runtime. You'll find an outline of optimizations it performs in this answer.
Upvotes: 4