了解编译器优化

Understanding Compiler Optimizations

我试图了解编译器对非常简单的代码做了什么:

if (group.ImageHeight > 1 && group.ImageWidth > 1)
{ //No code exists between the braces
}

Debug 配置中编译后,然后反编译我看到了这个:

if (group.ImageHeight <= 1 || group.ImageWidth <= 1);

反编译 Release 配置结果

if (group.ImageHeight > 1)
{
  int imageWidth = group.ImageWidth;
}

更完整(原)代码:

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)
    { 
    }
}

到目前为止,这是我的猜测和观察:

现在,对于我的具体问题:

对于第一个具体问题。当你在 sharplab.io 上查看 IL 时 简单的赋值是 1 条比较指令。谁的 "then" 和 "else" 将指向相同的指令(在本例中为 IL_0012),因此比较不需要调用函数,两次 pop 就足够了。奇怪的是只加载 Int32 常量 1,它将被立即丢弃。

如果 (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

第二个具体问题。如果您在调试模式下查看同一页面上的 IL,您会发现代码仅与一些额外的调试指令和比较本身相同,因此您可以在调试器中查看结果。

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