I'm trying to understand what the compiler is doing to very simple piece of code:
if (group.ImageHeight > 1 && group.ImageWidth > 1)
{ //No code exists between the braces
}
After compiling in Debug configuration, then decompiling I see this:
if (group.ImageHeight <= 1 || group.ImageWidth <= 1);
Decompiling a Release configuration results in
if (group.ImageHeight > 1)
{
int imageWidth = group.ImageWidth;
}
More complete (original) code:
public class Group
{
public int ImageHeight { get; set; }
public int ImageWidth { get; set; }
}
//The following belongs to a different project than `Group`
static void Main(string[] args)
{
Group group = new Group();
MyMethod(group);
}
static void MyMethod(Group group)
{
if (group.ImageHeight > 1 && group.ImageWidth > 1)
{
}
}
Here are my guesses and observations so far:
group type belongs to another project in my solution. I say this because the compiler probably can't "know" what the side effects of evaluating the properties could be in the future. For instance, I could, after compiling, replace the DLL that contains the definition for group.Release config the possible side effects appear to be the same as my code: ImageHeight is evaluated and if meets the > 1 condition will evaluate ImageWidth (although through assignment rather than comparison)Now, for my specific questions:
Release config use an assignment (int imageWidth = group.ImageWidth) rather than my original comparison? Is it faster to run an assignment?Debug configuration completely change the possibility of side effects? In this configuration both ImageHeight and ImageWidth will always be evaluated. For the first specific question. When you look at IL on sharplab.io The simple assignment is 1 compare instruction short. Whose "then" and "else" would point to the same instruction (in this case IL_0012) so compare there is not needed for calling function and two pops are enough. Weird is only loading the Int32 constant 1 which will be discarded immidiately.
if (group.ImageHeight > 1)
IL_0000: ldarg.0
IL_0001: callvirt instance int32 Group::get_ImageHeight()
IL_0006: ldc.i4.1
IL_0007: ble.s IL_0012
int imageWidth = group.ImageWidth;
IL_0009: ldarg.0
IL_000a: callvirt instance int32 Group::get_ImageWidth()
IL_000f: ldc.i4.1
IL_0010: pop
IL_0011: pop
IL_0012: ret
For second specific question. If you look at IL on the same page with Debug mode, you'll see, that the code is identical only with some additional instructions for debuging and the compare itself so you can watch the result of it in debuger.
IL_0000: nop
IL_0001: ldarg.0
IL_0002: callvirt instance int32 Group::get_ImageHeight()
IL_0007: ldc.i4.1
IL_0008: ble.s IL_0015
IL_000a: ldarg.0
IL_000b: callvirt instance int32 Group::get_ImageWidth()
IL_0010: ldc.i4.1
IL_0011: cgt
IL_0013: br.s IL_0016
IL_0015: ldc.i4.0
IL_0016: stloc.0
// sequence point: hidden
IL_0017: ldloc.0
IL_0018: brfalse.s IL_001c
IL_001a: nop
IL_001b: nop
IL_001c: ret
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With