Basic Blocks and Traces
为了解决上述的中间代码的问题,我们需要将其进一步处理:
- 重写原来的 IR 树,使其不包含 SEQ 和 ESEQ
- 将 list 分组为基本块,其中不会包含
jump
和label
- 基本块会被重新排序为一个 trace 的集合,其中的每一个
CJUMP
后面跟的都是它的 false label
Canonical Trees 定义
规范书定义如下
- 不包含 SEQ 和 ESEQ
- 每个 CALL 的父节点一定是 EXP 或 MOVE(TEMP, ...)
基于此有三条性质
- 一个规范树至多一个 statement,且一定是根节点,其它结点一定是表达式结点
- CALL 的孩子一定不是 CALL
- CALL 的父节点一定是根节点
- 一个规范树最多一个 CALL
- 因为 EXP 或 MOVE(TEMP, ...)最多只能挂一个 CALL
转化方式
liminate ESEQs
我们先尝试将 ESEQ 往上提:
但是对于下面这种情况,假设 s = MOVE(MEM(x), y),e1 = MEM(x),直接像上面就会出错,我们就需要改写 MOVE 语句,让前提条件一起提上去,用临时变量存储,将临时变量放在其原本的位置
我们在编译时是无法确定一个 statement 是否能与一个 expression 进行交换 commute 的,只能进行保守的粗略判断:
- 如果 expression 是一个常量,那么它可以和任何 statement 进行交换
- 如果一个 statement 是空的,那么它可以和任何 expression 进行交换
此外的任何情况都不能进行交换
于是我们得到了最终的规则:
move CALLs to top level
each function returns its result in the same dedicated return-value register TEMP(RV)
对于 BINOP(PLUS, CALL(...), CALL(...))
The second call will overwrite the RV register before the PLUS can be execute
用临时变量存储第一个返回值即可
CALL(f, args)-> ESEQ(MOVE(TEMP t, CALL(f, args)), TEMP t)
eliminate SEQ
经过上面的处理后,我们的 IR 树形如 SEQ(SEQ(SEQ(..., sx), sy), sz)
我们重复使用这条规则:SEQ(SEQ(a, b), c) = SEQ(a, seq(b, c)),将左子树上的 SEQ 移动到右子树,变成 SEQ(s1, SEQ(s2, ..., SEQ(sn-1, sn)...))
这完全就没有结构信息,就是线性执行,且每个 s 都是一个规范树,由此我们得到了规范树组成的列表
Taming Conditional Branches
Control flow is the sequencing of instructions in a program
Basic Blocks
A basic block is a sequence of statements that is always entered at the beginning and exited at the end
注意如果一个 block 没有 label 或 jump,我们也要手动加,因为后面会打乱 block 的顺序
Traces
The basic blocks can be arranged in any order, and the result of executing the program will be the same.
A trace is a sequence of statements that could be consecutively executed during the execution of the program and can include conditional branches
一个程序可以有多条不同的、重叠的 trace
我们希望构建出一组 traces,每个 block 只会出现在一条 trace 上,且每个 trace 都不会有循环
我们希望这一组 traces 刚好覆盖整个程序,且 trace 越少越好
处理流程
我们通过 DFS 搜索出所有的 trace
得到 traces 后,对其进行处理:
Any frequently executed sequence of instructions (such as the body of a loop) should occupy its own trace
This helps to minimize the number of unconditional jumps