我打算编写一个针对.NET平台的编程语言,这让我开始考虑定位这样一个平台的代码生成方面。我是编写编译器的新手,但我知道在编译(或可能存在)的过程中有一个优化。我开始怀疑花时间优化输出有什么好处(在这种情况下是CIL,但这也适用于JVM),因为JIT编译器和JVM的HotSpot之类的东西可以在运行时进行优化。由于JIT已经优化,因此在针对.NET或JVM时优化生成的代码(CIL或等效的JVM)有什么好处吗?
答案 0 :(得分:5)
这取决于。有无数的优化。任何给定的编译器(您的编译器,JIT编译器或任何其他编译器)都必须仅实现其中的一部分。这个选择取决于可用时间,典型/预期输入代码,优先级等,因此构建JIT编译器的工程师可能已经选择了适合他们期望的程序的优化,但对于您的程序类型不太好关心。
您必须确定JIT编译器错过了哪些优化。当然,这样做的方法是经验性的:实际编写程序,让JIT编译器优化它们(确保正确地执行此部分 - 禁用调试,编译以发布,选择实际的基准测试等),然后检查最终的机器代码。寻找意外的代码(当然,你需要汇编知识)并确定它是否是错过的优化,或者JIT是否比你想象的更聪明。
如果是错过优化,则还有另一个问题:您无法输出所需的机器代码,您必须生成不同的IL。 由于VM不知道的语言特性(例如JVM上的多方法),错过的优化可能是 。您在编译期间将其降低为VM的术语,但您选择的翻译与JIT的通过顺序,启发式等不相符。 由于您不能自己输出机器代码,因此您现在必须为相同的输入语言代码找到另一个IL片段。理想情况下,JIT编译器可以很好地处理它。发现这可能是一种想象力的练习,但它在技术上并不难,只是猜测与基准测试相互交织。
另一个答案指出,JIT编译器在时间限制下工作。这个可能导致可能错过的优化(例如,持续传播时间不足),但由于JIT编译器的创建者遇到同样的问题,这可能不是如果你不创建很多更大/更复杂的代码,那就太严重了。 如果你创建了这样糟糕的代码,JIT编译器无法修复它,那么你必须在AOT编译器中复制它的优化。我不相信这是一个可能的情况,即使它发生甚至非常简单的优化应该主要解决问题。
所以,总结:从一个简单的翻译开始,然后找出错过的优化,或者让它更容易为JIT编译器进行优化,或者自己动手(如果可能的话 - 自适应优化很多在AOT设置中更难)。
答案 1 :(得分:2)
我认为这个问题一般很难回答。
例如,F#编译器执行tail call optimization,因为在该语言中使用尾递归函数是常见的,在某些情况下,F#编译器可以比JIT编译器和某些版本更好地优化它们JIT编译器根本不执行优化。
因此,您的语言可能有一些常见的操作,其直接实现不会很好。在这种情况下,发出优化的IL代码是有意义的。
我认为你应该做的就像你编写一个普通程序时一样:首先以简单易读的方式编写代码。只有当某些事情表现不佳时,才能尝试优化。可能值得考虑的是,您将来可能需要进行一些优化,并使您的代码足够模块化,这样您就不必因为某些优化而重写一半。但就目前而言,这应该足够了。
编写编译器已经足够困难了(即使你的目标是IL)。先完成它,然后考虑优化。
答案 2 :(得分:1)
通常,JIT编译器具有一些阈值来控制它们将尝试执行多少优化。这些可以基于方法的大小IL和/或JIT编译该方法已经花费的时间量。所以是的,IL已经优化可能受益于进一步的JIT优化。与往常一样,需要进行权衡:您希望花多少时间将AOT优化添加到编译器(以及测试/维护它们)与编译JIT的速度以及优化程度。
改进的程度在很大程度上取决于AOT优化的IL相对于未优化的IL的简单程度(和更小),以及管理JIT编译器的阈值(至少对于Microsoft CLR来说,是并不广为人知。找出答案的唯一方法是自己做一些测试。