CS153/lec06/code/ir2.ml

173 lines
3.9 KiB
OCaml
Raw Normal View History

(* source language ---------------------------------------------------------- *)
(* This variant of the language treats variables as mutable.
Their interpretation in ML has type "int64 ref"
*)
type var = string
module SRC = struct
(* Abstract syntax of arithmetic expressions *)
type exp =
| Var of var
| Add of exp * exp
| Mul of exp * exp
| Neg of exp
| Const of int64
(* Abstract syntax of commands *)
type cmd =
| Skip (* skip *)
| Assn of var * exp (* X := e *)
| Seq of cmd * cmd (* c1 ; c2 *)
(* The global context of available variables and their initial values. *)
let globals : (var * int64) list =
[
"X1", 1L
; "X2", 2L
; "X3", 3L
; "X4", 4L
; "X5", 5L
; "X6", 6L
; "X7", 7L
; "X8", 8L
]
(*
(1 + X4) + (3 + (X1 * 5) )
*)
let example : exp =
Add(Add(Const 1L, Var "X4"),
Add(Const 3L, Mul(Var "X1",
Const 5L)))
(*
X1 := (1 + X4) + (3 + (X1 * 5) ) ;
Skip ;
X2 := X1 * X1 ;
*)
let example_cmd : cmd =
Seq(Assn("X1", example),
Seq(Skip,
Assn("X2", Mul(Var "X1", Var "X1"))))
end
module IR = struct
(* Unique identifiers for temporaries. *)
type uid = int
(* "gensym" -- generate a new unique identifier *)
let mk_uid : unit -> uid =
let ctr = ref 0 in
fun () ->
ctr := !ctr + 1;
!ctr
(* operands *)
type opn =
| Id of uid
| Const of int64
(* binary operations *)
type bop =
| Add
| Mul
(* instructions *)
(* note that there is no nesting of operations! *)
type insn =
| Let of uid * bop * opn * opn
| Load of uid * var
| Store of var * opn
type program = {
globals: (var * int64) list;
insns: insn list
}
(* pretty printing *)
let pp_uid u = Printf.sprintf "tmp%d" u
let pp_var x = Printf.sprintf "var%s" x
let pp_int64 c = (Int64.to_string c)^"L"
let pp_opn = function
| Id u -> pp_uid u
| Const c -> pp_int64 c
let pp_bop = function
| Add -> "add"
| Mul -> "mul"
let pp_insn = function
| Let (u, bop, op1, op2) ->
Printf.sprintf "let %s = %s %s %s"
(pp_uid u) (pp_bop bop) (pp_opn op1) (pp_opn op2)
| Load (u, x) ->
Printf.sprintf "let %s = load %s"
(pp_uid u) (pp_var x)
| Store (x, op) ->
Printf.sprintf "let _ = store %s %s"
(pp_opn op) (pp_var x)
let pp_global = function (x,c) ->
Printf.sprintf "let %s = ref %s" (pp_var x) (pp_int64 c)
let pp_program {globals; insns} =
Printf.sprintf "%s\n;;\n%s in\n ()"
(String.concat "\n" (List.map pp_global globals))
(String.concat " in\n" (List.map pp_insn insns))
module MLMeaning = struct
let add = Int64.add
let mul = Int64.mul
let load x = x.contents
let store o x = x.contents <- o
end
end
module Compile = struct
open SRC
let rec compile_exp (e:exp) : (IR.insn list) * IR.opn =
let compile_bop bop e1 e2 =
let ins1, ret1 = compile_exp e1 in
let ins2, ret2 = compile_exp e2 in
let ret = IR.mk_uid () in
ins1 @ ins2 @ IR.[Let (ret, bop, ret1, ret2)], IR.Id ret
in
begin match e with
| Var x ->
let ret = IR.mk_uid () in
IR.[Load(ret, x)], IR.Id ret
| Const c -> [], IR.Const c
| Add(e1, e2) -> compile_bop IR.Add e1 e2
| Mul(e1, e2) -> compile_bop IR.Mul e1 e2
| Neg(e1) -> compile_bop IR.Mul e1 (Const(-1L))
end
let rec compile_cmd (c:cmd) : (IR.insn list) =
begin match c with
| Skip -> []
| Assn(x, e) ->
let ins1, ret1 = compile_exp e in
ins1 @ IR.[Store(x, ret1)]
| Seq(c1, c2) ->
(compile_cmd c1) @ (compile_cmd c2)
end
let compile (c:cmd) : IR.program =
let globals = SRC.globals in
let insns = compile_cmd c in
IR.{ globals; insns }
end