【问题标题】:Empty if-block not optimized away?没有优化的空 if 块?
【发布时间】:2021-03-17 15:54:58
【问题描述】:

下面的空 if 块会被优化掉吗?

public class C 
{
    private bool foo = false;
    
    public void M() 
    {
        if(foo) {}
    }
}

SharpLab(master 5 Dec 2020, Release)表示编译器没有优化 if-block away:

.method public hidebysig instance void M () cil managed 
{
    .maxstack 8

    IL_0000: ldarg.0
    IL_0001: ldfld bool C::foo
    IL_0006: pop
    IL_0007: ret
}

编译器应该看不到ldfld后面跟pop没有效果,三个指令(ldarg.0也是)不需要发出?

我想不出在不发出 ldfld 时可能会发生的副作用(就像在 if 块内调用方法时可能发生的那样)。


此外,SharpLab 生成的 JIT ASM 似乎也没有优化空 if 块:

C.M()
    L0000: movzx eax, byte ptr [ecx+4]
    L0004: ret

我是否认为 JIT 仍会优化空的 if 块?

  • 如果是这样,您能否解释一下为什么编译器不能这样做?
  • 如果没有,为什么没有?

提前谢谢你!

【问题讨论】:

  • 您是将此目标构建为发布版还是调试版?我认为在调试某些优化时我不会发生。

标签: c# optimization jit cil


【解决方案1】:

此外,SharpLab 生成的 JIT ASM 似乎也没有优化空 if 块:

C.M()
    L0000: movzx eax, byte ptr [ecx+4]
    L0004: ret

实际的 if 块已被优化掉,如果它存在,它看起来会与此类似:

C.M()
    L0000: movzx eax, byte ptr [ecx+4]
    L0004: test eax, eax
    L0006: je short L0008
    L0008: ret

但这并没有发生,JIT 编译器显然发现这没有用。

只有布尔字段的负载仍然存在。

【讨论】:

  • 谢谢!我不太了解汇编,并且过于关注 JIT ASM,而不仅仅是 ret,所以我得出了错误的结论……但是,您知道为什么布尔字段的负载仍然存在吗?您的(现在已编辑的)负载点怎么样,因此无法将 null 传递给该方法?
  • @ThomasFlinkow 如有必要,将在调用者中插入一个虚拟负载(例如like this,其中mov eax, [rdx] 除了触发 NRE 之外什么都不做),所以毕竟不是这样。虽然很无聊,但我不得不把它归结为 JIT 编译器有点笨。
  • 优化负载​​可能会导致行为发生明显变化。如果您在方法上使用call 而不是callvirt 并将null 作为this 传递,则原始代码仍会从加载中抛出NullReferenceException,而没有它,该方法将正常返回.看看static 字段的行为是否相同可能会很有趣。
  • @IllidanS4supportsMonica 最初是一个假设,但是在调用者中插入了一个虚拟负载,所以如果 thisnull 那么该方法甚至不会被调用,它不需要崩溃本身
  • 我猜编译器就是那么笨。
猜你喜欢
  • 1970-01-01
  • 2021-01-12
  • 2018-10-10
  • 1970-01-01
  • 2016-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多