dm1299

[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

starter-hundred-pacer

posted on 2019-05-25 22:09  dm1299  阅读(200)  评论(0编辑  收藏  举报

导航