IL optimization for JIT compilers
我正在开发一个发出IL代码的编译器。使用Mono和Microsoft.NET JIT编译器将生成的IL实时转换为尽可能快的机器代码是很重要的。
我的问题是:
优化模式是否有意义,比如:
1 2
| 'stloc.0; ldloc.0; ret' => 'ret'
'ldc.i4.0; conv.r8' => 'ldc.r8.0' |
这样,或者JIT足够聪明来处理这些问题?
是否有包含由Microsoft/Mono JIT编译器执行的优化列表的规范?
是否有任何良好的阅读和实际建议/最佳实践来优化IL,以便JIT编译器能够反过来生成最佳的机器代码(性能方面)?
- 据我所知,JIT在消除stloc.0; ldloc.0;方面相当不错。对于IronScheme,我尝试将输出IL调整为与C非常相似,因为我感觉JIT可能会更加努力地优化已知的模式。但这只是一种感觉:你可以创造一些微基准来测量它。
- .NET抖动并不特别聪明(毕竟,它们没有太多时间)。你为什么关心"最快的可能"?
- @Luaan,我关心"最快的可能",因为这是需要为密集计算生成代码的编译器。理想情况下,它应该生成本机代码,但我正在考虑使用IL实现更好的可移植性和可维护性。然而,性能仍然是首要任务。
- @你可以创建一些微基准来分析结果…
- 在性能不那么重要的地方我会选择IL,在性能不重要的地方选择本机代码。可移植性很难,但-雅格尼。确保它是安全的:)
冗余的转换和这样的加载/存储是一个非常不可避免的副作用递归体面的解析器。从技术上讲,你可以用窥视孔优化器来消除它们。但这没什么好担心的,C和VB.NET编译器也会生成它们。
现有的.NET/Mono抖动非常擅长优化它们。他们专注于优化对执行速度至关重要的代码,即机器代码。有一个非常好的优势,即任何编写生成IL的编译器的人都可以自动从这些优化中获益,而无需做任何特殊的事情。
本文将介绍抖动优化。
你所描述的两个模式是JIT实际上正确的简单的东西(非原始结构除外)。在SSA形式中,常数传播和消除死区值非常容易。
不,您必须测试JIT可以做什么。查看编译器文献以了解期望的标准优化。然后,测试它们。我们现在拥有的两个JIT优化得很少,有时也不能得到最基本的东西。例如,Ryujit不优化MyStruct s; s.x = 1; s.x = 1;。s = s;也不是。s.x + s.x从内存中加载x两次。期望渺茫。
您需要了解基本操作映射到什么机器代码。这并不太复杂。尝试一些事情,看看反汇编列表。你很快就会知道输出是什么样子的。
- 为什么SSA相关?JIT编译器是否在内部使用它?
- @斯威克,我很肯定他们会的。这似乎非常重要。"corecrl中的ssabuilder.cpp"似乎做了类似的事情。en.wikipedia.org/wiki/…看看它有多普遍。