正如 Charles Fiterman 在 comp.compilers 上关于人类与计算机生成的汇编代码所说
人类应该总是胜出,原因如下。
首先,人类用高级语言编写整个程序。
其次,他对其进行性能分析,以找出程序花费时间的热点。
第三,他让编译器为那些小段代码生成汇编代码。
第四,他对它们进行手工调整,以寻找相对于机器的微小改进
生成的代码。
人类获胜是因为他可以使用机器。
像 ObjectiveCAML、SML、CommonLISP、Scheme、ADA、Pascal、C、C++ 等语言,都拥有免费的优化编译器,这些编译器将优化你的大部分程序,并且通常比手工编写的汇编代码(即使对于紧凑的循环)做得更好,同时让你专注于更高层次的细节,并且一旦你达到了稳定的设计,也不会禁止你以上述方式获得百分之几的额外性能。当然,对于这些语言中的大多数,也有商业优化编译器!
一些语言的编译器可以生成 C 代码,这些代码可以被 C 编译器进一步优化:LISP、Scheme、Perl 和许多其他语言。速度相当不错。
至于加速代码,你应该只对程序中被性能分析工具持续识别为性能瓶颈的部分进行加速。
因此,如果你确定某个代码部分太慢,你应该
首先尝试使用更好的算法;
然后尝试编译它而不是解释它;
然后尝试启用和调整编译器的优化;
然后给编译器关于如何优化的提示(LISP 中的类型信息;GCC 中的寄存器使用;大多数编译器中的许多选项等等)。
然后可能退回到汇编编程
最后,在你最终编写汇编代码之前,你应该检查生成的代码,以确认问题是否真的是代码生成不良,因为情况可能并非如此:编译器生成的代码可能比你编写的代码更好,特别是在现代多流水线架构上!程序中速度慢的部分可能本质上就是如此。现代架构中快速处理器面临的最大问题是内存访问、缓存未命中、TLB 未命中和页错误造成的延迟;寄存器优化变得无用,你将更有利地重新思考数据结构和线程,以实现更好的内存访问局部性。也许完全不同的问题解决方法可能会有所帮助。
检查编译器生成的汇编代码有很多原因。以下是你将对这些代码执行的操作
检查生成的代码是否可以通过手工编写的汇编代码(或通过调整编译器开关)明显增强
如果是这种情况,从生成的代码开始修改它,而不是从头开始
更一般地,使用生成的代码作为存根进行修改,这至少能正确地处理你的汇编例程与外部世界交互的方式
追踪编译器中的错误(希望这种情况较少见)
生成汇编代码的标准方法是使用以下命令调用编译器-S标志。这适用于大多数 Unix 编译器,包括 GNU C 编译器 (GCC),但 YMMV。至于 GCC,它将使用以下命令生成更易于理解的汇编代码-fverbose-asm命令行选项。当然,如果你想获得良好的汇编代码,不要忘记你常用的优化选项和提示!