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