JIT 编译器的 IL 优化
IL optimization for JIT compilers
我正在开发一个发出 IL 代码的编译器。重要的是,生成的 IL 由 Mono 和 Microsoft .NET JIT 编译器 JIT 为尽可能最快的机器代码。
我的问题是:
优化模式是否有意义:
'stloc.0; ldloc.0; ret' => 'ret'
'ldc.i4.0; conv.r8' => 'ldc.r8.0'
等等,或者 JIT 是否足够聪明来处理这些?
是否有包含 Microsoft/Mono JIT 编译器执行的优化列表的规范?
是否有任何关于优化 IL 的实用建议/最佳实践的好读物,以便 JIT 编译器可以反过来生成最佳机器代码(性能方面)?
- 您描述的两种模式是 JIT 实际上正确处理的简单内容(非原始结构除外)。在 SSA 形式中,持续传播和消除死值非常容易。
- 不,您必须测试 JIT 可以做什么。查看编译器文献以了解期望的标准优化。然后,为他们测试。我们现在拥有的两个 JIT 优化得很少,有时甚至无法正确处理最基本的内容。例如,
MyStruct s; s.x = 1; s.x = 1;
没有被 RyuJIT 优化。 s = s;
也不是。 s.x + s.x
从内存中加载 x 两次。期望很小。
- 您需要了解机器代码基本操作映射到什么。这并不太复杂。尝试一些事情并查看反汇编列表。您将很快了解输出的外观。
冗余转换和 load/stores 之类的是递归体面的解析器不可避免的副作用。从技术上讲,您可以使用窥孔优化器摆脱它们。但不用担心,C# 和 VB.NET 编译器也会生成它们。
现有的 .NET/Mono 抖动非常擅长优化它们。他们专注于优化 真正 对执行速度很重要的代码,即机器码。一个非常好的优势是,任何编写生成 IL 的编译器的人都可以自动从这些优化中获益,而无需执行任何特殊操作。
this post 中介绍了抖动优化。
我正在开发一个发出 IL 代码的编译器。重要的是,生成的 IL 由 Mono 和 Microsoft .NET JIT 编译器 JIT 为尽可能最快的机器代码。
我的问题是:
优化模式是否有意义:
'stloc.0; ldloc.0; ret' => 'ret' 'ldc.i4.0; conv.r8' => 'ldc.r8.0'
等等,或者 JIT 是否足够聪明来处理这些?
是否有包含 Microsoft/Mono JIT 编译器执行的优化列表的规范?
是否有任何关于优化 IL 的实用建议/最佳实践的好读物,以便 JIT 编译器可以反过来生成最佳机器代码(性能方面)?
- 您描述的两种模式是 JIT 实际上正确处理的简单内容(非原始结构除外)。在 SSA 形式中,持续传播和消除死值非常容易。
- 不,您必须测试 JIT 可以做什么。查看编译器文献以了解期望的标准优化。然后,为他们测试。我们现在拥有的两个 JIT 优化得很少,有时甚至无法正确处理最基本的内容。例如,
MyStruct s; s.x = 1; s.x = 1;
没有被 RyuJIT 优化。s = s;
也不是。s.x + s.x
从内存中加载 x 两次。期望很小。 - 您需要了解机器代码基本操作映射到什么。这并不太复杂。尝试一些事情并查看反汇编列表。您将很快了解输出的外观。
冗余转换和 load/stores 之类的是递归体面的解析器不可避免的副作用。从技术上讲,您可以使用窥孔优化器摆脱它们。但不用担心,C# 和 VB.NET 编译器也会生成它们。
现有的 .NET/Mono 抖动非常擅长优化它们。他们专注于优化 真正 对执行速度很重要的代码,即机器码。一个非常好的优势是,任何编写生成 IL 的编译器的人都可以自动从这些优化中获益,而无需执行任何特殊操作。
this post 中介绍了抖动优化。