ASM代码生成向前看和复杂性



我有一个带有funcdef,funccall,文字等节点的AST。我正在研究编译器的代码生成器部分,为X86_64生成汇编。我的问题是,什么是"适当"(行业标准(代码下生成AST的方式:它是多次通过,例如,一个人要弄清楚需要多少本局部变量,以便使用该值来减少堆栈指针?此外,诸如Funccall之类的复杂AST是如何解决ASM的另一个Funccall的?

的。

将我的AST转换为非常简单的IR(SSA?(是明智的吗?另外,由于我对代码生成理论非常无知,有没有专注于此的好书?

谢谢!

生成机器代码的"正确"/标准方法是通过优化编译器,该编译器通过内部表示形式(通常是SSA表单(转换,并且对于各种优化而言看起来很难。/p>

解释器更容易编写,如果写得很好,可以比效率低下/天真的ASM提供更好的性能,因此没有标准的"简单"来生成ASM的方法,因为没有人想要那个。(我想是一个爱好项目,除了自学的编译器。(


自己编写A 编译器自己将是数十年的工作。看看为什么C编译器很少?尤其是Basile Starynkevitch的答案。即使对于现代X86-64的"简单" CPU而言,这也是如此。优化冗余工作,并决定何时进行内联功能,依此类推,这并不容易。

,但针对现代X86-64的优化范围从简单(不订购的执行不太在乎指令订购(到奥术(例如inc eax保存代码大小与add eax,1,但在某些情况下,在某些情况下,它是较慢;多个UOPS或部分flag档(。或者,与2个单独的LEA/添加Intel Sandybridge-Fail-Family-family CPU的指令相比,该3组分LEA具有更高的延迟(但可能更好(。另请参见Agner Fog的优化指南和X86 TAG Wiki中的其他性能优化链接。,如果您完全尝试优化,则只需担心这一点。有效地做很多冗余工作并不是那么有用。


要制作一种新语言的编译器,您只需编写生成LLVM-ir 的前端,然后将其馈送到LLVM库中,以优化和发射ASM或机器代码,以适用于ASM或机器代码。(您可以使用GCC的优化中端/后端而不是LLVM来为Gimple做同样的事情(。作为奖励,您的编译器有望在LLVM或GCC支持的大多数CPU体系结构上工作,而不仅仅是X86。

请参阅使用LLVM教程实现的语言。


天真地将每个表达式的每个部分分别转换为ASM指令将产生缓慢而肿的ASM 。也许与您从clang -O0获得的相似,但是它确实在表达式中进行了优化,因此10 + x + 4仍然与x + 14相同。clang -O0在每个语句之后还增加了将所有内容溢出到内存的负担,因此您可以在任何断点处使用调试器在内存中修改C变量。(这是-O0的一部分:保证一致的调试,以及在优化上花费最少的精力来快速编译。(

不在乎它的天真编译器可能会跟踪在需要新寄存器时登记和溢出的值。如果您不尽快需要哪些值,而是希望将这些值保持在寄存器中。


如果您不关心ASM生成的质量,那么,请肯定地做任何方便的事情。

tinycc是一个单通车的C编译器。当它发出功能序列时,尚未决定需要保留多少个字节堆栈空间。(它返回并填充一旦达到函数的末尾。(请参阅Tiny C编译器生成的代码额外发射(不必要?(NOPS和JMP,这是一个有趣的结果:nop添加其函数prologue的一个版本。

idk它在内部做什么,但大概是因为它遇到了新的变量声明,它将它们处理到要保留的堆栈框架末端(因此不会将偏移量从rbp更改为任何现有变量,因为它可能可以已经使用它们发射了(

tcc是开源的,写为小/简单(并快速编译(,不是创建良好的ASM,因此您可能想查看其源代码以查看它的内容做。

最新更新