汇编:为 copy 增加翻译规则
本节阅读量:
第一章的汇编生成器已经会做这些事:
1
2
3
4
|
给每条 IR 操作的 dst 分配栈槽
在函数开头一次性留出栈空间
把 add 翻译成 movq、addq、movq
把最终结果放进 %rax
|
第二章继续使用这套流程。汇编生成器只需要认识上一节新增的 copy 操作。
copy 怎样生成汇编
代码在:
1
|
code/02_let/src/compile/assembly.cpp
|
IR:
表示把操作数 40 保存到内部名字 x0。它只需要两条指令:
1
2
|
movq $40, %rax
movq %rax, -8(%rbp)
|
对应的新增分支是:
1
2
3
4
|
case OpKind::copy:
out_ += " movq " + operand_text(op.lhs) + ", %rax\n";
out_ += " movq %rax, " + stack_slot(op.dst) + "\n";
return;
|
这里仍然使用第一章已有的两个辅助函数:
1
2
|
operand_text(op.lhs) 把整数或 IR 名字写成汇编操作数
stack_slot(op.dst) 找到结果对应的栈槽
|
因此,如果 lhs 是另一个 IR 名字,copy 也不需要特殊处理。例如:
可以生成:
1
2
|
movq -8(%rbp), %rax
movq %rax, -16(%rbp)
|
完整例子
源码:
IR:
1
2
3
|
x0 = 40
t.0 = x0 + 2
return t.0
|
其中只有第一条使用新的 copy 分支;第二条 add 和最后的返回都沿用第一章:
1
2
3
4
5
6
|
movq $40, %rax
movq %rax, -8(%rbp)
movq -8(%rbp), %rax
addq $2, %rax
movq %rax, -16(%rbp)
movq -16(%rbp), %rax
|
加入第一章已有的函数外壳后,就是完整输出。
Shadowing 也不需要新的汇编规则。lowerer 已经把两个同名变量变成 x0 和 x1,原有的栈槽分配会自然地给它们不同的位置:
1
2
|
x0 -> -8(%rbp)
x1 -> -16(%rbp)
|
到这里,第二章新增的编译路径就接通了:
1
|
let 绑定 -> copy IR -> copy 汇编分支
|
手动验证
1
2
3
4
5
6
|
cd code/02_let
make
./mini compile examples/let.lang -o out.s
cc out.s -o out
./out
echo $?
|
退出码应该是: