[swarthmore cs75] Compiler 7 – Hundred Pacer
课程回顾
Swarthmore学院16年开的编译系统课,总共10次大作业。本随笔记录了相关的课堂笔记以及第10次大作业。
- mutable/immutable variables
- types
- optimization
- register allocation
opam install ocamlgraph
编程作业
dep_graph函数实现:
dep_graph_ae (ALet("b", CImmExpr(ImmNumber(4)),
ALet("x", CImmExpr(ImmNumber(10)),
ALet("i", CIf(ImmBool(true), ALet("z", CImmExpr(ImmNumber(11)),
ACExpr(CPrim2(Plus, ImmId("z"), ImmId("b")))),
ALet("y", CImmExpr(ImmNumber(9)), (ACExpr(CPrim2(Plus, ImmId("y"), ImmNumber(1)))))),
ALet("a", CPrim2(Plus, ImmNumber(5), ImmId("i")),
ACExpr(CPrim2(Plus, ImmId("a"), ImmId("x")))))))) []
返回结果
([],
[("x", "b"); ("i", "x"); ("i", "b"); ("z", "x"); ("z", "b"); ("y", "x");
("a", "x"); ("a", "i")])
这里actives参数指的是从外部传入的变量,比如let的赋值嵌套了if语句,需要把body中的active的变量传入到if中。
let diff xs ys = List.filter (fun x -> not (List.mem x ys)) xs
let cons_uniq xs x = if List.mem x xs then xs else x :: xs
let remove_from_left xs = List.rev (List.fold_left cons_uniq [] xs)
let zipwith id xs = List.map (fun x -> id, x) xs
let dep_graph_imm (imm : immexpr) : string list =
match imm with
| ImmId(id) -> [id]
| _ -> []
let rec dep_graph_ce (ce : cexpr) (actives : string list) : (string list * (string * string) list) =
match ce with
| CPrim1(_, imm) -> remove_from_left (actives @ dep_graph_imm imm), []
| CPrim2(_, left, right) -> remove_from_left (actives @ dep_graph_imm left @ dep_graph_imm right), []
| CIf(_, thn, els) ->
let thn_branch = dep_graph_ae thn actives in
let els_branch = dep_graph_ae els actives in
remove_from_left (fst thn_branch @ fst els_branch), snd thn_branch @ snd els_branch
| CImmExpr(imm) -> actives @ dep_graph_imm imm, []
| CApp(f, iargs) ->
let postlude = List.flatten (List.map (fun iarg -> dep_graph_imm iarg) iargs) in
remove_from_left (actives @ postlude), []
and dep_graph_ae (ae : aexpr) (actives : string list) : (string list * (string * string) list) =
match ae with
| ALet(id, ce, body) ->
let postlude = dep_graph_ae body actives in
let new_actives = diff (fst postlude) [id] in
let prelude = dep_graph_ce ce (new_actives) in
fst prelude, zipwith id (fst prelude) @ snd prelude @ snd postlude
| ACExpr(ce) -> dep_graph_ce ce actives
let dep_graph (ae : aexpr) : (string * string) list =
snd (dep_graph_ae ae [])
getvars函数实现:返回所有let绑定的变量(图的顶点)
let rec getvars (ae : aexpr) : string list =
match ae with
| ALet(id, e, body) ->
let prelude = getvars (ACExpr(e)) in
let postlude = getvars body in
id::(prelude @ postlude)
| ACExpr(s) ->
begin match s with
| CIf(_, thn, els) -> getvars thn @ getvars els
| _ -> []
end
get_colors函数实现:如果图着色后的颜色数量小于传入的寄存器数量,则变量都可以分配到寄存器中;否则,需要把一部分变量分配到栈中。
如下例程序:
let b = 4 in
let x = 10 in
let i = if true:
let z = 11 in z + b
else:
let y = 9 in y + 1 in
let a = 5 + i in
a + x
着色后:
a: 1 (green)
b: 1 (green)
i: 2 (red)
z: 2 (red)
y: 2 (red)
x: 3 (blue)
如果只允许使用两个寄存器,那么一个可行的分配方案如下:
a: LReg(R1)
b: LReg(R1)
i: LReg(R2)
z: LReg(R2)
y: LReg(R2)
x: LStack(1)
这里用loop来检测需最少需要多少种颜色可以将图找色:
let get_colors (registers : reg list) (varlist : string list) (edgelist : (string * string) list) : (location envt) =
if varlist = [] || edgelist = [] then []
else
let rec loop i =
begin match color_graph i varlist edgelist with
| None -> loop (i+1)
| Some(pairs) ->
let number_of_colors = i in
let number_of_registers = List.length registers in
if number_of_colors <= number_of_registers then
List.map (fun (var, color_no) -> var, LReg(List.nth registers (color_no-1))) pairs
else
let reg_pairs = List.find_all (fun (_, color_no) -> color_no <= number_of_registers) pairs in
let stack_pairs = List.find_all (fun (_, color_no) -> color_no > number_of_registers) pairs in
List.map (fun (var, color_no) -> var, LReg(List.nth registers (color_no-1))) reg_pairs
@
let reg_pairs_len = List.length reg_pairs in
List.map (fun (var, color_no) -> var, LStack(
if reg_pairs_len == 0 then color_no
else color_no - number_of_registers
)) stack_pairs
end in
loop 0
colorful_env函数实现:整合上述代码
let colorful_env (ae : aexpr) (args : string list) : location envt =
let deps = dep_graph ae in
get_colors !spare_regs ((getvars ae)@args) deps
测试用例
def f(x, t):
if x < 1: t
else: f(x - 1, x + t)
f(888888888, 0)
ANF形式:这里需要注意,再进行图着色的时候,需要把函数f的形参也加入到顶点中。
def f(x, t)
let t1 = x < 1 in x, t => (t1, x) (t1, t)
if t1: x, t (取t和x,t的并集)
t t
else:
let t2 = x - 1 in x, t => (t2, x) (t2, t)
let t3 = x + t in t2, x, t => (t3, t2) (t3, x) (t3, t)
f(t2, t3) t2, t3
..调用略
使用NUMREGS参数指定寄存器个数,经过测试,程序设置参数为(NUMREGS=3)的执行效率要好于(NUMREGS=0)。
make output/longloop.run NUMREGS=3
时间计算脚本:
start=$(date +%s)
./output/longloop.run
end=$(date +%s)
time=$(( $end - $start ))
echo $time