Assembly 优化编译器生成的汇编代码的一些技巧是什么?

Assembly 优化编译器生成的汇编代码的一些技巧是什么?,assembly,x86,compiler-construction,Assembly,X86,Compiler Construction,我目前正在编写一个脚本,我似乎遇到了一些问题,无法将其输出到在适当的时间段内执行的代码中 编译器的简要概述: 7Basic是一种编译器,旨在将7Basic代码直接编译成目标体系结构/平台的机器代码。目前,7Basic在给定源文件的情况下生成x86程序集 问题是编译器生成的汇编代码速度慢且效率低 例如,代码(可编译为汇编代码)的执行时间几乎是汇编代码的80.47倍 部分问题在于编译器生成的代码如下所示: push eax push 5000000 pop ebx pop eax 而不是更符合逻辑

我目前正在编写一个脚本,我似乎遇到了一些问题,无法将其输出到在适当的时间段内执行的代码中

编译器的简要概述:

7Basic是一种编译器,旨在将7Basic代码直接编译成目标体系结构/平台的机器代码。目前,7Basic在给定源文件的情况下生成x86程序集

问题是编译器生成的汇编代码速度慢且效率低

例如,代码(可编译为汇编代码)的执行时间几乎是汇编代码的80.47倍

部分问题在于编译器生成的代码如下所示:

push eax
push 5000000
pop ebx
pop eax
而不是更符合逻辑的:

mov ebx,5000000
…完成同样的事情

我的问题是:有哪些技巧可以避免此类问题?解析器基本上使用递归来解析表达式,因此生成的代码反映了这一点。

称为一种技术。这需要一种迭代的方法来清理汇编代码。基本上,您可以扫描汇编代码,一次只查看两到三条指令,看看是否可以将它们简化为更简单的指令。比如说,

push eax        ; 1
push 5000000    ; 2
pop ebx         ; 3
pop eax         ; 4
第一步将查看第2行和第3行,并将其替换为:

push eax        ; 1
mov ebx,5000000 ; 2a
pop eax         ; 4

第二,你可以考虑1和4,如果在中间指令中没有触碰<代码> EAX,把它们都删除,留下你想要的:

mov ebx,5000000 ; 2a

您可能想考虑生成C代码而不是程序集,然后让C编译器(例如GCC)为您处理代码生成。试图重新发明轮子是没有意义的。

一个特定的代码生成器可能会发出您列出的指令序列,原因有很多。最有可能的情况是,您正在使用的代码生成器没有尽力发出最佳代码

这种发出代码的模式向我表明,您的代码生成器不知道x86具有直接将常量值嵌入指令流的“mov immediate”指令。对于具有立即值的操作码,x86编码可能会变得有点复杂(可变长度的R/M字节),但如果要使用许多x86指令,这已经是必需的了

发出的代码还表明代码生成器不知道EAX未被EBX指令修改。这感觉就像codegen是模板驱动的,而不是离散逻辑


当编译器对操作的内部中间表示不够详细,无法表示目标体系结构的所有方面时,就会发生这种代码生成。如果代码生成器体系结构最初是为RISC指令集设计的,但已重新调整用途以发出x86指令,则尤其如此。RISC体系结构往往只有很少且非常简单的加载、存储和操作reg/reg指令,而x86指令集经过几十年的有机发展,包括直接在内存上操作的各种操作码、指令中的内联常量以及一大堆其他内容。如果编译器的中间表示(表达式图)是针对RISC的,那么很难让它了解x86的广泛多样性和微妙之处。

我现在正在学习一门编译器课程。我在输出高效代码方面取得了很大的进步,但是你应该看看龙之书。这是一种成年礼。您应该看看Jeremy Bennett的书《编译技术介绍:使用ANSI C、LEX和YACC的第一门课程》中的代码。这本书本身很难找到,但您可以从以下网站免费下载编译器的源代码:

代码生成器文件(cg.c)具有一些生成相当优化的代码的函数。目标语言不是I86,但您应该考虑如何描述寄存器并跟踪存储符号表条目的位置。他的输出程序集可以进一步优化,但它为生成在某些方面可以与gcc-S的输出相媲美的代码提供了良好的基础

一种通用的优化方法是在输入函数时减去堆栈指针,为所有局部变量和临时变量保留空间。然后只参考偏移,而不是不断地推/弹出


例如,如果您的中间代码是一个由四个部分组成的列表,那么您应该简单地对每个函数进行迭代,并跟踪最大偏移量。然后输出行以减去堆栈上的空间量。这样就不需要打开和关闭这么多变量。要消除弹出它们的需要,只需将它们的值从堆栈上的偏移量移动到寄存器中即可。这将显著提高性能。

窥视孔优化将有所帮助,但一个明显的问题是编译器不进行寄存器分配


如果你想获得更高的绩效水平,你必须对此进行调查。如果您贪婪地“在运行中”完成,它可以在一次过程中完成。

将-O3添加到编译器命令行;-)“…一个生成本机Win32可执行文件的跨平台基本编译器。”等等,什么?@musicfreak:嗯,它也旨在生成ELF可执行文件。该编译器(非常!)介绍了一个单通道编译器中的窥视孔优化。Short version:按N条指令对输出进行缓冲,并在每次向缓冲区发出新指令时检查缓冲区中是否存在可能的优化。根据需要推出结果。要进行哪些优化?啊……这是最难的部分,不是吗?@dmckee:这似乎是个有用的建议。最终编译器将生成机器代码,所以这不是一个选项。最终C编译器也将生成机器代码。我的意思是,最终编译器将直接生成机码本身。如果你的编译器