汇编代码生成如何工作?

How Does Assembly Code Generation Work?

最近一直在研究编译器设计。我已经很好地掌握了解析阶段,但在理解代码生成的工作原理时遇到了一些麻烦。

根据我的阅读,代码生成阶段似乎有 3 个主要步骤:

现在,指令调度有点超出了我目前正在尝试做的事情,我认为通过更多的研究和原型设计,我可能可以围绕寄存器分配的图形着色算法来思考。

让我难过的是第一步,指令selection。据我了解,目标机器语言中的每条指令都由一个图块表示;目标是找到与树的最大部分相匹配的指令(因此昵称,贪婪平铺)。

我感到困惑的是,当它们实际上 1:1 与语法树不对应时,您如何 select 指令?

例如,基于累加器的架构,如 Z80 或 MIP 单指令架构。即使在 Z80 上执行 16 位整数运算也可能需要使用累加器或影子寄存器。

还有一些指令尽管是通用的,但只能用于某些寄存器。

我做出以下假设是否正确?

a) tile 可能包含一系列与语法树模式匹配的指令,而不仅仅是 1:1 匹配。

b) 代码生成器首先为基于堆栈的架构(或具有无限临时寄存器的架构)生成代码,并在寄存器分配阶段根据需要以某种方式扩展和替换指令。

a) 一个 tile 可以发出任意数量的指令。例如,如果你有像 %x <- %y + %z 这样的指令,但目标机器只有双地址指令,那么匹配的 tile 可能会发出汇编序列(目标是第一个操作数)

mov %x, %y
add %x, %z

b) 允许哪种寄存器(或 const,或 mem 引用)作为指令的操作数由指令本身决定,因此指令选择阶段必须使用符号寄存器名称(伪寄存器)。寄存器分配阶段确实可以发出附加指令,例如spill/load 所需 class 的寄存器不可用于分配时的代码。

检查这个 Survey on Instruction Selection: an Extensive and Modern Literature Review