Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why such a difference in IL between IF and the conditional operator?

Tags:

c#

il

C# has a conditional operator and IF statements and I suspected that the conditional operator would be just syntactic sugar. So at compile time it would have a the same as an IF operation.

However they do not (see below), they do have different IL. Trying to wrap my head around it and the assumption I have is that this is a performance optimisation that the conditional operator gets because it's limited scope.

Would like to know if my assumption is correct or not and maybe if there is more to this?

Also in the IF's IL there is some checks (L_000c, L_000d, L_000f) around int values which I can't figure out the meaning. This is what has lead me to think this is a more robust solution, at the cost of performance because of IF greater scope.


Code for IF
var result = "";
if (Environment.Is64BitOperatingSystem)
{
    result = "Yes";
}
else
{
    result = "No";
}
Console.WriteLine(result);

Code for conditional operator (I realise differences, but no matter how I change it - assign to variable etc... it makes very little difference)

Console.WriteLine("Is the OS x64? {0}", Environment.Is64BitOperatingSystem ? "Yes" : "No");

IL for IF

L_0001: ldstr ""
L_0006: stloc.0 
L_0007: call bool [mscorlib]System.Environment::get_Is64BitOperatingSystem()
L_000c: ldc.i4.0 
L_000d: ceq 
L_000f: stloc.2 
L_0010: ldloc.2 
L_0011: brtrue.s L_001d
L_0013: nop 
L_0014: ldstr "Yes"
L_0019: stloc.0 
L_001a: nop 
L_001b: br.s L_0025
L_001d: nop 
L_001e: ldstr "No"
L_0023: stloc.0 
L_0024: nop 
L_0025: ldloc.0 
L_0026: call void [mscorlib]System.Console::WriteLine(string)

IL for Conditional

L_002c: ldstr "Is the OS x64? {0}"
L_0031: call bool [mscorlib]System.Environment::get_Is64BitOperatingSystem()
L_0036: brtrue.s L_003f
L_0038: ldstr "No"
L_003d: br.s L_0044
L_003f: ldstr "Yes"
L_0044: call void [mscorlib]System.Console::WriteLine(string, object)
like image 873
Robert MacLean Avatar asked Sep 05 '11 13:09

Robert MacLean


1 Answers

if

IL_0000:  call       bool [mscorlib]System.Environment::get_Is64BitOperatingSystem()
IL_0005:  brfalse.s  IL_000f
IL_0007:  ldstr      "Yes"
IL_000c:  stloc.0                  // <------ Difference 1
IL_000d:  br.s       IL_0015
IL_000f:  ldstr      "No"
IL_0014:  stloc.0
IL_0015:  ldloc.0
IL_0016:  call       void [mscorlib]System.Console::WriteLine(string)

? (ternary operator)

IL_001b:  call       bool [mscorlib]System.Environment::get_Is64BitOperatingSystem()
IL_0020:  brtrue.s   IL_0029
IL_0022:  ldstr      "No"          // <------ Difference 2
IL_0027:  br.s       IL_002e
IL_0029:  ldstr      "Yes"
IL_002e:  stloc.0
IL_002f:  ldloc.0
IL_0030:  call       void [mscorlib]System.Console::WriteLine(string)

(nearly)same code for both in release mode. The if adds a second stdloc.0 that isn't optimized away by the compiler. And the other difference is that the true and false are inverted.

(so I learn that I should ALWAYS fire up WinMerge!)

And THIS would be an interesting question. Why are they inverted? Is there any logic?

like image 65
xanatos Avatar answered Oct 20 '22 07:10

xanatos