【问题标题】:IL optimization for JIT compilersJIT 编译器的 IL 优化
【发布时间】:2015-09-03 19:15:18
【问题描述】:

我正在开发一个能发出 IL 代码的编译器。重要的是,生成的 IL 由 Mono 和 Microsoft .NET JIT 编译器 JIT 到最快的机器代码。

我的问题是:

  1. 优化以下模式是否有意义:

    'stloc.0; ldloc.0; ret' => 'ret' 
    'ldc.i4.0; conv.r8' => 'ldc.r8.0'
    

    等等,还是 JIT 足够聪明来处理这些?

  2. 是否有包含 Microsoft/Mono JIT 编译器执行的优化列表的规范?

  3. 是否有任何关于优化 IL 的实用建议/最佳实践的好读物,以便 JIT 编译器反过来生成最佳机器代码(性能方面)?

【问题讨论】:

  • 据我所知,JIT 在消除stloc.0; ldloc.0; 方面做得很好。对于 IronScheme,我尝试将输出 IL 调整为与 C# 非常相似,因为 JIT 可能会更加努力地优化已知模式。但这只是一种感觉:D 你总是可以创建一些微基准来衡量它。
  • .NET JITters 并不是特别聪明(毕竟,他们没有太多时间)。你为什么关心“尽可能快”?
  • @Luaan,我关心“尽可能快”,因为这是需要为密集计算生成代码的编译器。理想情况下,它应该生成本机机器代码,但我正在考虑使用 IL 以获得更好的可移植性和可维护性。但是,性能仍然是重中之重。
  • @DenisYarkovoy 你可以创建一些微基准来分析结果......
  • 我会选择性能不那么重要的 IL,并且选择本地代码。可移植性很棘手,但是 - YAGNI。只要确保它实际上是安全的:)

标签: c# .net jit il


【解决方案1】:
  1. 您所描述的两种模式是 JIT 实际上得到正确的简单内容(非原始结构除外)。在 SSA 形式中,不断传播和消除死值非常容易。
  2. 不,您必须测试 JIT 可以做什么。查看编译器文献以了解预期的标准优化。然后,测试它们。我们现在拥有的两个 JIT 优化很少,有时无法正确处理最基本的内容。例如,MyStruct s; s.x = 1; s.x = 1; 未经过 RyuJIT 优化。 s = s; 也不是。 s.x + s.x 从内存中加载 x 两次。期待很少。
  3. 您需要了解机器代码基本操作映射到什么。这并不太复杂。尝试一些事情并查看反汇编列表。您会很快感受到输出的样子。

【讨论】:

  • 为什么与 SSA 相关? JIT 编译器是否在内部使用它?
  • @svick 我很确定他们会这样做。这似乎非常必要。 CoreCLR 中的“ssabuilder.cpp”似乎做了类似的事情。 en.wikipedia.org/wiki/… 看看它有多普遍。
【解决方案2】:

像这样的冗余转换和加载/存储是递归体面解析器不可避免的副作用。从技术上讲,您可以使用窥视孔优化器摆脱它们。不过不用担心,C# 和 VB.NET 编译器也会生成它们。

现有的 .NET/Mono 抖动非常擅长优化它们。他们专注于优化真正对执行速度很重要的代码,即机器代码。任何编写自动生成 IL 的编译器的人都可以从这些优化中受益,而无需做任何特别的事情。

this post 中介绍了抖动优化。

【讨论】:

    猜你喜欢
    • 2010-09-21
    • 1970-01-01
    • 2017-06-09
    • 1970-01-01
    • 2019-03-06
    • 1970-01-01
    • 2013-02-26
    • 2019-09-07
    • 2017-04-21
    相关资源
    最近更新 更多