main.mli
val limit : int ref val string : string -> unit val file : string -> unit
main.ml
let limit = ref 1000 let rec iter n e = (* 最適化処理をくりかえす *) Format.eprintf "iteration %d@." n; if n = 0 then e else let e' = Elim.f (ConstFold.f (Inline.f (Assoc.f (Beta.f e)))) in if e = e' then e else iter (n - 1) e' let lexbuf outchan l = (* バッファをコンパイルしてチャンネルへ出力する *) Id.counter := 0; Typing.extenv := M.empty; Emit.f outchan (RegAlloc.f (Simm.f (Virtual.f (Closure.f (iter !limit (Alpha.f (KNormal.f (Typing.f (Parser.exp Lexer.token l))))))))) let string s = lexbuf stdout (Lexing.from_string s) (* 文字列をコンパイルして標準出力に表示する *) let file f = (* ファイルをコンパイルしてファイルに出力する *) let inchan = open_in (f ^ ".ml") in let outchan = open_out (f ^ ".s") in try lexbuf outchan (Lexing.from_channel inchan); close_in inchan; close_out outchan; with e -> (close_in inchan; close_out outchan; raise e) let () = (* ここからコンパイラの実行が開始される *) let files = ref [] in Arg.parse [("-inline", Arg.Int(fun i -> Inline.threshold := i), "maximum size of functions inlined"); ("-iter", Arg.Int(fun i -> limit := i), "maximum number of optimizations iterated")] (fun s -> files := !files @ [s]) ("Mitou Min-Caml Compiler (C) Eijiro Sumii\n" ^ Printf.sprintf "usage: %s [-inline m] [-iter n] ...filenames without \".ml\"..." Sys.argv.(0)); List.iter (fun f -> ignore (file f)) !files
id.ml
type t = string (* 変数の名前 *) type l = L of string (* トップレベル関数やグローバル配列のラベル *) let rec pp_list = function [] -> "" [x] -> x x :: xs -> x ^ " " ^ pp_list xs let counter = ref 0 let genid s = incr counter; Printf.sprintf "%s.%d" s !counter let rec id_of_typ = function Type.Unit -> "u" Type.Bool -> "b" Type.Int -> "i" Type.Float -> "d" Type.Fun _ -> "f" Type.Tuple _ -> "t" Type.Array _ -> "a" Type.Var _ -> assert false let gentmp typ = incr counter; Printf.sprintf "T%s%d" (id_of_typ typ) !counter
m.ml
(* customized version of Map *) module M = Map.Make (struct type t = Id.t let compare = compare end) include M let add_list xys env = List.fold_left (fun env (x, y) -> add x y env) env xys let add_list2 xs ys env = List.fold_left2 (fun env x y -> add x y env) env xs ys
s.ml
(* customized version of Set *) module S = Set.Make (struct type t = Id.t let compare = compare end) include S let of_list l = List.fold_left (fun s e -> add e s) empty l
syntax.ml
type t = (* MinCamlの構文を表現するデータ型 *) Unit Bool of bool Int of int Float of float Not of t Neg of t Add of t * t Sub of t * t FNeg of t FAdd of t * t FSub of t * t FMul of t * t FDiv of t * t Eq of t * t LE of t * t If of t * t * t Let of (Id.t * Type.t) * t * t Var of Id.t LetRec of fundef * t App of t * t list Tuple of t list LetTuple of (Id.t * Type.t) list * t * t Array of t * t Get of t * t Put of t * t * t and fundef = { name : Id.t * Type.t; args : (Id.t * Type.t) list; body : t }
type.ml
type t = (* MinCamlの型を表現するデータ型 *) Unit Bool Int Float Fun of t list * t (* arguments are uncurried *) Tuple of t list Array of t Var of t option ref let gentyp () = Var(ref None) (* 新しい型変数を作る *)
parser.mly
%{ (* parserが利用する変数、関数、型などの定義 *) open Syntax let addtyp x = (x, Type.gentyp ()) %} /* (* 字句を表すデータ型の定義 *) */ %token <bool> BOOL %token <int> INT %token <float> FLOAT %token NOT %token MINUS %token PLUS %token MINUS_DOT %token PLUS_DOT %token AST_DOT %token SLASH_DOT %token EQUAL %token LESS_GREATER %token LESS_EQUAL %token GREATER_EQUAL %token LESS %token GREATER %token IF %token THEN %token ELSE %token <Id.t> IDENT %token LET %token IN %token REC %token COMMA %token ARRAY_CREATE %token DOT %token LESS_MINUS %token SEMICOLON %token LPAREN %token RPAREN %token EOF /* (* 優先順位とassociativityの定義(低い方から高い方へ) *) */ %right prec_let %right SEMICOLON %right prec_if %right LESS_MINUS %left COMMA %left EQUAL LESS_GREATER LESS GREATER LESS_EQUAL GREATER_EQUAL %left PLUS MINUS PLUS_DOT MINUS_DOT %left AST_DOT SLASH_DOT %right prec_unary_minus %left prec_app %left DOT /* (* 開始記号の定義 *) */ %type <Syntax.t> exp %start exp %% simple_exp: /* (* 括弧をつけなくても関数の引数になれる式 *) */ LPAREN exp RPAREN { $2 } LPAREN RPAREN { Unit } BOOL { Bool($1) } INT { Int($1) } FLOAT { Float($1) } IDENT { Var($1) } simple_exp DOT LPAREN exp RPAREN { Get($1, $4) } exp: /* (* 一般の式 *) */ simple_exp { $1 } NOT exp %prec prec_app { Not($2) } MINUS exp %prec prec_unary_minus { match $2 with Float(f) -> Float(-.f) (* -1.23などは型エラーではないので別扱い *) e -> Neg(e) } exp PLUS exp /* (* 足し算を構文解析するルール *) */ { Add($1, $3) } exp MINUS exp { Sub($1, $3) } exp EQUAL exp { Eq($1, $3) } exp LESS_GREATER exp { Not(Eq($1, $3)) } exp LESS exp { Not(LE($3, $1)) } exp GREATER exp { Not(LE($1, $3)) } exp LESS_EQUAL exp { LE($1, $3) } exp GREATER_EQUAL exp { LE($3, $1) } IF exp THEN exp ELSE exp %prec prec_if { If($2, $4, $6) } MINUS_DOT exp %prec prec_unary_minus { FNeg($2) } exp PLUS_DOT exp { FAdd($1, $3) } exp MINUS_DOT exp { FSub($1, $3) } exp AST_DOT exp { FMul($1, $3) } exp SLASH_DOT exp { FDiv($1, $3) } LET IDENT EQUAL exp IN exp %prec prec_let { Let(addtyp $2, $4, $6) } LET REC fundef IN exp %prec prec_let { LetRec($3, $5) } exp actual_args %prec prec_app { App($1, $2) } elems { Tuple($1) } LET LPAREN pat RPAREN EQUAL exp IN exp { LetTuple($3, $6, $8) } simple_exp DOT LPAREN exp RPAREN LESS_MINUS exp { Put($1, $4, $7) } exp SEMICOLON exp { Let((Id.gentmp Type.Unit, Type.Unit), $1, $3) } ARRAY_CREATE simple_exp simple_exp %prec prec_app { Array($2, $3) } error { failwith (Printf.sprintf "parse error near characters %d-%d" (Parsing.symbol_start ()) (Parsing.symbol_end ())) } fundef: IDENT formal_args EQUAL exp { { name = addtyp $1; args = $2; body = $4 } } formal_args: IDENT formal_args { addtyp $1 :: $2 } IDENT { [addtyp $1] } actual_args: actual_args simple_exp %prec prec_app { $1 @ [$2] } simple_exp %prec prec_app { [$1] } elems: elems COMMA exp { $1 @ [$3] } exp COMMA exp { [$1; $3] } pat: pat COMMA IDENT { $1 @ [addtyp $3] } IDENT COMMA IDENT { [addtyp $1; addtyp $3] }
lexer.mll
{ (* lexerが利用する変数、関数、型などの定義 *) open Parser open Type } (* 正規表現の略記 *) let space = [' ' '\t' '\n' '\r'] let digit = ['0'-'9'] let lower = ['a'-'z'] let upper = ['A'-'Z'] rule token = parse space+ { token lexbuf } "(*" { comment lexbuf; (* ネストしたコメントのためのトリック *) token lexbuf } '(' { LPAREN } ')' { RPAREN } "true" { BOOL(true) } "false" { BOOL(false) } "not" { NOT } digit+ (* 整数を字句解析するルール *) { INT(int_of_string (Lexing.lexeme lexbuf)) } digit+ ('.' digit*)? (['e' 'E'] ['+' '-']? digit+)? { FLOAT(float_of_string (Lexing.lexeme lexbuf)) } '-' (* -.より後回しにしなくても良い? 最長一致? *) { MINUS } '+' (* +.より後回しにしなくても良い? 最長一致? *) { PLUS } "-." { MINUS_DOT } "+." { PLUS_DOT } "*." { AST_DOT } "/." { SLASH_DOT } '=' { EQUAL } "<>" { LESS_GREATER } "<=" { LESS_EQUAL } ">=" { GREATER_EQUAL } '<' { LESS } '>' { GREATER } "if" { IF } "then" { THEN } "else" { ELSE } "let" { LET } "in" { IN } "rec" { REC } ',' { COMMA } '_' { IDENT(Id.gentmp Type.Unit) } "Array.create" (* [XX] ad hoc *) { ARRAY_CREATE } '.' { DOT } "<-" { LESS_MINUS } ';' { SEMICOLON } eof { EOF } lower (digit lower upper'_')* (* 他の「予約語」より後でないといけない *) { IDENT(Lexing.lexeme lexbuf) } _ { failwith (Printf.sprintf "unknown token %s near characters %d-%d" (Lexing.lexeme lexbuf) (Lexing.lexeme_start lexbuf) (Lexing.lexeme_end lexbuf)) } and comment = parse "*)" { () } "(*" { comment lexbuf; comment lexbuf } eof { Format.eprintf "warning: unterminated comment@." } _ { comment lexbuf }
typing.mli
exception Error of Syntax.t * Type.t * Type.t val extenv : Type.t M.t ref val f : Syntax.t -> Syntax.t
typing.ml
(* type inference/reconstruction *) open Syntax exception Unify of Type.t * Type.t exception Error of t * Type.t * Type.t let extenv = ref M.empty (* for pretty printing (and type normalization) *) let rec deref_typ = function (* 型変数を中身でおきかえる関数 *) Type.Fun(t1s, t2) -> Type.Fun(List.map deref_typ t1s, deref_typ t2) Type.Tuple(ts) -> Type.Tuple(List.map deref_typ ts) Type.Array(t) -> Type.Array(deref_typ t) Type.Var({ contents = None } as r) -> Format.eprintf "uninstantiated type variable detected; assuming int@."; r := Some(Type.Int); Type.Int Type.Var({ contents = Some(t) } as r) -> let t' = deref_typ t in r := Some(t'); t' t -> t let rec deref_id_typ (x, t) = (x, deref_typ t) let rec deref_term = function Not(e) -> Not(deref_term e) Neg(e) -> Neg(deref_term e) Add(e1, e2) -> Add(deref_term e1, deref_term e2) Sub(e1, e2) -> Sub(deref_term e1, deref_term e2) Eq(e1, e2) -> Eq(deref_term e1, deref_term e2) LE(e1, e2) -> LE(deref_term e1, deref_term e2) FNeg(e) -> FNeg(deref_term e) FAdd(e1, e2) -> FAdd(deref_term e1, deref_term e2) FSub(e1, e2) -> FSub(deref_term e1, deref_term e2) FMul(e1, e2) -> FMul(deref_term e1, deref_term e2) FDiv(e1, e2) -> FDiv(deref_term e1, deref_term e2) If(e1, e2, e3) -> If(deref_term e1, deref_term e2, deref_term e3) Let(xt, e1, e2) -> Let(deref_id_typ xt, deref_term e1, deref_term e2) LetRec({ name = xt; args = yts; body = e1 }, e2) -> LetRec({ name = deref_id_typ xt; args = List.map deref_id_typ yts; body = deref_term e1 }, deref_term e2) App(e, es) -> App(deref_term e, List.map deref_term es) Tuple(es) -> Tuple(List.map deref_term es) LetTuple(xts, e1, e2) -> LetTuple(List.map deref_id_typ xts, deref_term e1, deref_term e2) Array(e1, e2) -> Array(deref_term e1, deref_term e2) Get(e1, e2) -> Get(deref_term e1, deref_term e2) Put(e1, e2, e3) -> Put(deref_term e1, deref_term e2, deref_term e3) e -> e let rec occur r1 = function (* occur check *) Type.Fun(t2s, t2) -> List.exists (occur r1) t2s || occur r1 t2 Type.Tuple(t2s) -> List.exists (occur r1) t2s Type.Array(t2) -> occur r1 t2 Type.Var(r2) when r1 == r2 -> true Type.Var({ contents = None }) -> false Type.Var({ contents = Some(t2) }) -> occur r1 t2 _ -> false let rec unify t1 t2 = (* 型が合うように、型変数への代入をする *) match t1, t2 with Type.Unit, Type.Unit Type.Bool, Type.Bool Type.Int, Type.Int Type.Float, Type.Float -> () Type.Fun(t1s, t1'), Type.Fun(t2s, t2') -> (try List.iter2 unify t1s t2s with Invalid_argument("List.iter2") -> raise (Unify(t1, t2))); unify t1' t2' Type.Tuple(t1s), Type.Tuple(t2s) -> (try List.iter2 unify t1s t2s with Invalid_argument("List.iter2") -> raise (Unify(t1, t2))) Type.Array(t1), Type.Array(t2) -> unify t1 t2 Type.Var(r1), Type.Var(r2) when r1 == r2 -> () Type.Var({ contents = Some(t1') }), _ -> unify t1' t2 _, Type.Var({ contents = Some(t2') }) -> unify t1 t2' Type.Var({ contents = None } as r1), _ -> (* 一方が未定義の型変数の場合 *) if occur r1 t2 then raise (Unify(t1, t2)); r1 := Some(t2) _, Type.Var({ contents = None } as r2) -> if occur r2 t1 then raise (Unify(t1, t2)); r2 := Some(t1) _, _ -> raise (Unify(t1, t2)) let rec g env e = (* 型推論ルーチン *) try match e with Unit -> Type.Unit Bool(_) -> Type.Bool Int(_) -> Type.Int Float(_) -> Type.Float Not(e) -> unify Type.Bool (g env e); Type.Bool Neg(e) -> unify Type.Int (g env e); Type.Int Add(e1, e2) Sub(e1, e2) -> (* 足し算(と引き算)の型推論 *) unify Type.Int (g env e1); unify Type.Int (g env e2); Type.Int FNeg(e) -> unify Type.Float (g env e); Type.Float FAdd(e1, e2) FSub(e1, e2) FMul(e1, e2) FDiv(e1, e2) -> unify Type.Float (g env e1); unify Type.Float (g env e2); Type.Float Eq(e1, e2) LE(e1, e2) -> unify (g env e1) (g env e2); Type.Bool If(e1, e2, e3) -> unify (g env e1) Type.Bool; let t2 = g env e2 in let t3 = g env e3 in unify t2 t3; t2 Let((x, t), e1, e2) -> (* letの型推論 *) unify t (g env e1); g (M.add x t env) e2 Var(x) when M.mem x env -> M.find x env (* 変数の型推論 *) Var(x) when M.mem x !extenv -> M.find x !extenv Var(x) -> (* 外部変数の型推論 *) Format.eprintf "free variable %s assumed as external@." x; let t = Type.gentyp () in extenv := M.add x t !extenv; t LetRec({ name = (x, t); args = yts; body = e1 }, e2) -> (* let recの型推論 *) let env = M.add x t env in unify t (Type.Fun(List.map snd yts, g (M.add_list yts env) e1)); g env e2 App(e, es) -> (* 関数適用の型推論 *) let t = Type.gentyp () in unify (g env e) (Type.Fun(List.map (g env) es, t)); t Tuple(es) -> Type.Tuple(List.map (g env) es) LetTuple(xts, e1, e2) -> unify (Type.Tuple(List.map snd xts)) (g env e1); g (M.add_list xts env) e2 Array(e1, e2) -> (* must be a primitive for "polymorphic" typing *) unify (g env e1) Type.Int; Type.Array(g env e2) Get(e1, e2) -> let t = Type.gentyp () in unify (Type.Array(t)) (g env e1); unify Type.Int (g env e2); t Put(e1, e2, e3) -> let t = g env e3 in unify (Type.Array(t)) (g env e1); unify Type.Int (g env e2); Type.Unit with Unify(t1, t2) -> raise (Error(deref_term e, deref_typ t1, deref_typ t2)) let f e = extenv := M.empty; (* (match deref_typ (g M.empty e) with | Type.Unit -> () | _ -> Format.eprintf "warning: final result does not have type unit@."); *) (try unify Type.Unit (g M.empty e) with Unify _ -> failwith "top level does not have type unit"); extenv := M.map deref_typ !extenv; deref_term e
kNormal.mli
type t = Unit Int of int Float of float Neg of Id.t Add of Id.t * Id.t Sub of Id.t * Id.t FNeg of Id.t FAdd of Id.t * Id.t FSub of Id.t * Id.t FMul of Id.t * Id.t FDiv of Id.t * Id.t IfEq of Id.t * Id.t * t * t IfLE of Id.t * Id.t * t * t Let of (Id.t * Type.t) * t * t Var of Id.t LetRec of fundef * t App of Id.t * Id.t list Tuple of Id.t list LetTuple of (Id.t * Type.t) list * Id.t * t Get of Id.t * Id.t Put of Id.t * Id.t * Id.t ExtArray of Id.t ExtFunApp of Id.t * Id.t list and fundef = { name : Id.t * Type.t; args : (Id.t * Type.t) list; body : t } val fv : t -> S.t val f : Syntax.t -> t
kNormal.ml
(* give names to intermediate values (K-normalization) *) type t = (* K正規化後の式 *) Unit Int of int Float of float Neg of Id.t Add of Id.t * Id.t Sub of Id.t * Id.t FNeg of Id.t FAdd of Id.t * Id.t FSub of Id.t * Id.t FMul of Id.t * Id.t FDiv of Id.t * Id.t IfEq of Id.t * Id.t * t * t (* 比較 + 分岐 *) IfLE of Id.t * Id.t * t * t (* 比較 + 分岐 *) Let of (Id.t * Type.t) * t * t Var of Id.t LetRec of fundef * t App of Id.t * Id.t list Tuple of Id.t list LetTuple of (Id.t * Type.t) list * Id.t * t Get of Id.t * Id.t Put of Id.t * Id.t * Id.t ExtArray of Id.t ExtFunApp of Id.t * Id.t list and fundef = { name : Id.t * Type.t; args : (Id.t * Type.t) list; body : t } let rec fv = function (* 式に出現する(自由な)変数 *) Unit Int(_) Float(_) ExtArray(_) -> S.empty Neg(x) FNeg(x) -> S.singleton x Add(x, y) Sub(x, y) FAdd(x, y) FSub(x, y) FMul(x, y) FDiv(x, y) Get(x, y) -> S.of_list [x; y] IfEq(x, y, e1, e2) IfLE(x, y, e1, e2) -> S.add x (S.add y (S.union (fv e1) (fv e2))) Let((x, t), e1, e2) -> S.union (fv e1) (S.remove x (fv e2)) Var(x) -> S.singleton x LetRec({ name = (x, t); args = yts; body = e1 }, e2) -> let zs = S.diff (fv e1) (S.of_list (List.map fst yts)) in S.diff (S.union zs (fv e2)) (S.singleton x) App(x, ys) -> S.of_list (x :: ys) Tuple(xs) ExtFunApp(_, xs) -> S.of_list xs Put(x, y, z) -> S.of_list [x; y; z] LetTuple(xs, y, e) -> S.add y (S.diff (fv e) (S.of_list (List.map fst xs))) let insert_let (e, t) k = (* letを挿入する補助関数 *) match e with Var(x) -> k x _ -> let x = Id.gentmp t in let e', t' = k x in Let((x, t), e, e'), t' let rec g env = function (* K正規化ルーチン本体 *) Syntax.Unit -> Unit, Type.Unit Syntax.Bool(b) -> Int(if b then 1 else 0), Type.Int (* 論理値true, falseを整数1, 0に変換 *) Syntax.Int(i) -> Int(i), Type.Int Syntax.Float(d) -> Float(d), Type.Float Syntax.Not(e) -> g env (Syntax.If(e, Syntax.Bool(false), Syntax.Bool(true))) Syntax.Neg(e) -> insert_let (g env e) (fun x -> Neg(x), Type.Int) Syntax.Add(e1, e2) -> (* 足し算のK正規化 *) insert_let (g env e1) (fun x -> insert_let (g env e2) (fun y -> Add(x, y), Type.Int)) Syntax.Sub(e1, e2) -> insert_let (g env e1) (fun x -> insert_let (g env e2) (fun y -> Sub(x, y), Type.Int)) Syntax.FNeg(e) -> insert_let (g env e) (fun x -> FNeg(x), Type.Float) Syntax.FAdd(e1, e2) -> insert_let (g env e1) (fun x -> insert_let (g env e2) (fun y -> FAdd(x, y), Type.Float)) Syntax.FSub(e1, e2) -> insert_let (g env e1) (fun x -> insert_let (g env e2) (fun y -> FSub(x, y), Type.Float)) Syntax.FMul(e1, e2) -> insert_let (g env e1) (fun x -> insert_let (g env e2) (fun y -> FMul(x, y), Type.Float)) Syntax.FDiv(e1, e2) -> insert_let (g env e1) (fun x -> insert_let (g env e2) (fun y -> FDiv(x, y), Type.Float)) Syntax.Eq _ Syntax.LE _ as cmp -> g env (Syntax.If(cmp, Syntax.Bool(true), Syntax.Bool(false))) Syntax.If(Syntax.Not(e1), e2, e3) -> g env (Syntax.If(e1, e3, e2)) (* notによる分岐を変換 *) Syntax.If(Syntax.Eq(e1, e2), e3, e4) -> insert_let (g env e1) (fun x -> insert_let (g env e2) (fun y -> let e3', t3 = g env e3 in let e4', t4 = g env e4 in IfEq(x, y, e3', e4'), t3)) Syntax.If(Syntax.LE(e1, e2), e3, e4) -> insert_let (g env e1) (fun x -> insert_let (g env e2) (fun y -> let e3', t3 = g env e3 in let e4', t4 = g env e4 in IfLE(x, y, e3', e4'), t3)) Syntax.If(e1, e2, e3) -> g env (Syntax.If(Syntax.Eq(e1, Syntax.Bool(false)), e3, e2)) (* 比較のない分岐を変換 *) Syntax.Let((x, t), e1, e2) -> let e1', t1 = g env e1 in let e2', t2 = g (M.add x t env) e2 in Let((x, t), e1', e2'), t2 Syntax.Var(x) when M.mem x env -> Var(x), M.find x env Syntax.Var(x) -> (* 外部配列の参照 *) (match M.find x !Typing.extenv with Type.Array(_) as t -> ExtArray x, t _ -> failwith (Printf.sprintf "external variable %s does not have an array type" x)) Syntax.LetRec({ Syntax.name = (x, t); Syntax.args = yts; Syntax.body = e1 }, e2) -> let env' = M.add x t env in let e2', t2 = g env' e2 in let e1', t1 = g (M.add_list yts env') e1 in LetRec({ name = (x, t); args = yts; body = e1' }, e2'), t2 Syntax.App(Syntax.Var(f), e2s) when not (M.mem f env) -> (* 外部関数の呼び出し *) (match M.find f !Typing.extenv with Type.Fun(_, t) -> let rec bind xs = function (* "xs" are identifiers for the arguments *) [] -> ExtFunApp(f, xs), t e2 :: e2s -> insert_let (g env e2) (fun x -> bind (xs @ [x]) e2s) in bind [] e2s (* left-to-right evaluation *) _ -> assert false) Syntax.App(e1, e2s) -> (match g env e1 with _, Type.Fun(_, t) as g_e1 -> insert_let g_e1 (fun f -> let rec bind xs = function (* "xs" are identifiers for the arguments *) [] -> App(f, xs), t e2 :: e2s -> insert_let (g env e2) (fun x -> bind (xs @ [x]) e2s) in bind [] e2s) (* left-to-right evaluation *) _ -> assert false) Syntax.Tuple(es) -> let rec bind xs ts = function (* "xs" and "ts" are identifiers and types for the elements *) [] -> Tuple(xs), Type.Tuple(ts) e :: es -> let _, t as g_e = g env e in insert_let g_e (fun x -> bind (xs @ [x]) (ts @ [t]) es) in bind [] [] es Syntax.LetTuple(xts, e1, e2) -> insert_let (g env e1) (fun y -> let e2', t2 = g (M.add_list xts env) e2 in LetTuple(xts, y, e2'), t2) Syntax.Array(e1, e2) -> insert_let (g env e1) (fun x -> let _, t2 as g_e2 = g env e2 in insert_let g_e2 (fun y -> let l = match t2 with Type.Float -> "create_float_array" _ -> "create_array" in ExtFunApp(l, [x; y]), Type.Array(t2))) Syntax.Get(e1, e2) -> (match g env e1 with _, Type.Array(t) as g_e1 -> insert_let g_e1 (fun x -> insert_let (g env e2) (fun y -> Get(x, y), t)) _ -> assert false) Syntax.Put(e1, e2, e3) -> insert_let (g env e1) (fun x -> insert_let (g env e2) (fun y -> insert_let (g env e3) (fun z -> Put(x, y, z), Type.Unit))) let f e = fst (g M.empty e)
alpha.mli
val f : KNormal.t -> KNormal.t val g : Id.t M.t -> KNormal.t -> KNormal.t (* for Inline.g *)
alpha.ml
(* rename identifiers to make them unique (alpha-conversion) *) open KNormal let find x env = try M.find x env with Not_found -> x let rec g env = function (* α変換ルーチン本体 *) Unit -> Unit Int(i) -> Int(i) Float(d) -> Float(d) Neg(x) -> Neg(find x env) Add(x, y) -> Add(find x env, find y env) Sub(x, y) -> Sub(find x env, find y env) FNeg(x) -> FNeg(find x env) FAdd(x, y) -> FAdd(find x env, find y env) FSub(x, y) -> FSub(find x env, find y env) FMul(x, y) -> FMul(find x env, find y env) FDiv(x, y) -> FDiv(find x env, find y env) IfEq(x, y, e1, e2) -> IfEq(find x env, find y env, g env e1, g env e2) IfLE(x, y, e1, e2) -> IfLE(find x env, find y env, g env e1, g env e2) Let((x, t), e1, e2) -> (* letのα変換 *) let x' = Id.genid x in Let((x', t), g env e1, g (M.add x x' env) e2) Var(x) -> Var(find x env) LetRec({ name = (x, t); args = yts; body = e1 }, e2) -> (* let recのα変換 *) let env = M.add x (Id.genid x) env in let ys = List.map fst yts in let env' = M.add_list2 ys (List.map Id.genid ys) env in LetRec({ name = (find x env, t); args = List.map (fun (y, t) -> (find y env', t)) yts; body = g env' e1 }, g env e2) App(x, ys) -> App(find x env, List.map (fun y -> find y env) ys) Tuple(xs) -> Tuple(List.map (fun x -> find x env) xs) LetTuple(xts, y, e) -> (* LetTupleのα変換 *) let xs = List.map fst xts in let env' = M.add_list2 xs (List.map Id.genid xs) env in LetTuple(List.map (fun (x, t) -> (find x env', t)) xts, find y env, g env' e) Get(x, y) -> Get(find x env, find y env) Put(x, y, z) -> Put(find x env, find y env, find z env) ExtArray(x) -> ExtArray(x) ExtFunApp(x, ys) -> ExtFunApp(x, List.map (fun y -> find y env) ys) let f = g M.empty
beta.mli
val f : KNormal.t -> KNormal.t
beta.ml
open KNormal let find x env = try M.find x env with Not_found -> x (* 置換のための関数 *) let rec g env = function (* β簡約ルーチン本体 *) Unit -> Unit Int(i) -> Int(i) Float(d) -> Float(d) Neg(x) -> Neg(find x env) Add(x, y) -> Add(find x env, find y env) Sub(x, y) -> Sub(find x env, find y env) FNeg(x) -> FNeg(find x env) FAdd(x, y) -> FAdd(find x env, find y env) FSub(x, y) -> FSub(find x env, find y env) FMul(x, y) -> FMul(find x env, find y env) FDiv(x, y) -> FDiv(find x env, find y env) IfEq(x, y, e1, e2) -> IfEq(find x env, find y env, g env e1, g env e2) IfLE(x, y, e1, e2) -> IfLE(find x env, find y env, g env e1, g env e2) Let((x, t), e1, e2) -> (* letのβ簡約 *) (match g env e1 with Var(y) -> Format.eprintf "beta-reducing %s = %s@." x y; g (M.add x y env) e2 e1' -> let e2' = g env e2 in Let((x, t), e1', e2')) LetRec({ name = xt; args = yts; body = e1 }, e2) -> LetRec({ name = xt; args = yts; body = g env e1 }, g env e2) Var(x) -> Var(find x env) (* 変数を置換 *) Tuple(xs) -> Tuple(List.map (fun x -> find x env) xs) LetTuple(xts, y, e) -> LetTuple(xts, find y env, g env e) Get(x, y) -> Get(find x env, find y env) Put(x, y, z) -> Put(find x env, find y env, find z env) App(g, xs) -> App(find g env, List.map (fun x -> find x env) xs) ExtArray(x) -> ExtArray(x) ExtFunApp(x, ys) -> ExtFunApp(x, List.map (fun y -> find y env) ys) let f = g M.empty
assoc.mli
val f : KNormal.t -> KNormal.t
assoc.ml
(* flatten let-bindings (just for prettier printing) *) open KNormal let rec f = function (* ネストしたletの簡約 *) IfEq(x, y, e1, e2) -> IfEq(x, y, f e1, f e2) IfLE(x, y, e1, e2) -> IfLE(x, y, f e1, f e2) Let(xt, e1, e2) -> (* letの場合 *) let rec insert = function Let(yt, e3, e4) -> Let(yt, e3, insert e4) LetRec(fundefs, e) -> LetRec(fundefs, insert e) LetTuple(yts, z, e) -> LetTuple(yts, z, insert e) e -> Let(xt, e, f e2) in insert (f e1) LetRec({ name = xt; args = yts; body = e1 }, e2) -> LetRec({ name = xt; args = yts; body = f e1 }, f e2) LetTuple(xts, y, e) -> LetTuple(xts, y, f e) e -> e
inline.mli
val threshold : int ref val f : KNormal.t -> KNormal.t
inline.ml
open KNormal (* インライン展開する関数の最大サイズ *) let threshold = ref 0 (* Mainで-inlineオプションによりセットされる *) let rec size = function IfEq(_, _, e1, e2) IfLE(_, _, e1, e2) Let(_, e1, e2) LetRec({ body = e1 }, e2) -> 1 + size e1 + size e2 LetTuple(_, _, e) -> 1 + size e _ -> 1 let rec g env = function (* インライン展開ルーチン本体 *) IfEq(x, y, e1, e2) -> IfEq(x, y, g env e1, g env e2) IfLE(x, y, e1, e2) -> IfLE(x, y, g env e1, g env e2) Let(xt, e1, e2) -> Let(xt, g env e1, g env e2) LetRec({ name = (x, t); args = yts; body = e1 }, e2) -> (* 関数定義の場合 *) let env = if size e1 > !threshold then env else M.add x (yts, e1) env in LetRec({ name = (x, t); args = yts; body = g env e1}, g env e2) App(x, ys) when M.mem x env -> (* 関数適用の場合 *) let (zs, e) = M.find x env in Format.eprintf "inlining %s@." x; let env' = List.fold_left2 (fun env' (z, t) y -> M.add z y env') M.empty zs ys in Alpha.g env' e LetTuple(xts, y, e) -> LetTuple(xts, y, g env e) e -> e let f e = g M.empty e
constFold.mli
val f : KNormal.t -> KNormal.t
constFold.ml
open KNormal let memi x env = try (match M.find x env with Int(_) -> true _ -> false) with Not_found -> false let memf x env = try (match M.find x env with Float(_) -> true _ -> false) with Not_found -> false let memt x env = try (match M.find x env with Tuple(_) -> true _ -> false) with Not_found -> false let findi x env = (match M.find x env with Int(i) -> i _ -> raise Not_found) let findf x env = (match M.find x env with Float(d) -> d _ -> raise Not_found) let findt x env = (match M.find x env with Tuple(ys) -> ys _ -> raise Not_found) let rec g env = function (* 定数畳み込みルーチン本体 *) Var(x) when memi x env -> Int(findi x env) (* | Var(x) when memf x env -> Float(findf x env) *) (* | Var(x) when memt x env -> Tuple(findt x env) *) Neg(x) when memi x env -> Int(-(findi x env)) Add(x, y) when memi x env && memi y env -> Int(findi x env + findi y env) (* 足し算のケース *) Sub(x, y) when memi x env && memi y env -> Int(findi x env - findi y env) FNeg(x) when memf x env -> Float(-.(findf x env)) FAdd(x, y) when memf x env && memf y env -> Float(findf x env +. findf y env) FSub(x, y) when memf x env && memf y env -> Float(findf x env -. findf y env) FMul(x, y) when memf x env && memf y env -> Float(findf x env *. findf y env) FDiv(x, y) when memf x env && memf y env -> Float(findf x env /. findf y env) IfEq(x, y, e1, e2) when memi x env && memi y env -> if findi x env = findi y env then g env e1 else g env e2 IfEq(x, y, e1, e2) when memf x env && memf y env -> if findf x env = findf y env then g env e1 else g env e2 IfEq(x, y, e1, e2) -> IfEq(x, y, g env e1, g env e2) IfLE(x, y, e1, e2) when memi x env && memi y env -> if findi x env <= findi y env then g env e1 else g env e2 IfLE(x, y, e1, e2) when memf x env && memf y env -> if findf x env <= findf y env then g env e1 else g env e2 IfLE(x, y, e1, e2) -> IfLE(x, y, g env e1, g env e2) Let((x, t), e1, e2) -> (* letのケース *) let e1' = g env e1 in let e2' = g (M.add x e1' env) e2 in Let((x, t), e1', e2') LetRec({ name = x; args = ys; body = e1 }, e2) -> LetRec({ name = x; args = ys; body = g env e1 }, g env e2) LetTuple(xts, y, e) when memt y env -> List.fold_left2 (fun e' xt z -> Let(xt, Var(z), e')) (g env e) xts (findt y env) LetTuple(xts, y, e) -> LetTuple(xts, y, g env e) e -> e let f = g M.empty
elim.mli
val f : KNormal.t -> KNormal.t
elim.ml
open KNormal let rec effect = function (* 副作用の有無 *) Let(_, e1, e2) IfEq(_, _, e1, e2) IfLE(_, _, e1, e2) -> effect e1 || effect e2 LetRec(_, e) LetTuple(_, _, e) -> effect e App _ Put _ ExtFunApp _ -> true _ -> false let rec f = function (* 不要定義削除ルーチン本体 *) IfEq(x, y, e1, e2) -> IfEq(x, y, f e1, f e2) IfLE(x, y, e1, e2) -> IfLE(x, y, f e1, f e2) Let((x, t), e1, e2) -> (* letの場合 *) let e1' = f e1 in let e2' = f e2 in if effect e1' || S.mem x (fv e2') then Let((x, t), e1', e2') else (Format.eprintf "eliminating variable %s@." x; e2') LetRec({ name = (x, t); args = yts; body = e1 }, e2) -> (* let recの場合 *) let e2' = f e2 in if S.mem x (fv e2') then LetRec({ name = (x, t); args = yts; body = f e1 }, e2') else (Format.eprintf "eliminating function %s@." x; e2') LetTuple(xts, y, e) -> let xs = List.map fst xts in let e' = f e in let live = fv e' in if List.exists (fun x -> S.mem x live) xs then LetTuple(xts, y, e') else (Format.eprintf "eliminating variables %s@." (Id.pp_list xs); e') e -> e
closure.mli
type closure = { entry : Id.l; actual_fv : Id.t list } type t = Unit Int of int Float of float Neg of Id.t Add of Id.t * Id.t Sub of Id.t * Id.t FNeg of Id.t FAdd of Id.t * Id.t FSub of Id.t * Id.t FMul of Id.t * Id.t FDiv of Id.t * Id.t IfEq of Id.t * Id.t * t * t IfLE of Id.t * Id.t * t * t Let of (Id.t * Type.t) * t * t Var of Id.t MakeCls of (Id.t * Type.t) * closure * t AppCls of Id.t * Id.t list AppDir of Id.l * Id.t list Tuple of Id.t list LetTuple of (Id.t * Type.t) list * Id.t * t Get of Id.t * Id.t Put of Id.t * Id.t * Id.t ExtArray of Id.l type fundef = { name : Id.l * Type.t; args : (Id.t * Type.t) list; formal_fv : (Id.t * Type.t) list; body : t } type prog = Prog of fundef list * t val fv : t -> S.t val f : KNormal.t -> prog
closure.ml
type closure = { entry : Id.l; actual_fv : Id.t list } type t = (* クロージャ変換後の式 *) Unit Int of int Float of float Neg of Id.t Add of Id.t * Id.t Sub of Id.t * Id.t FNeg of Id.t FAdd of Id.t * Id.t FSub of Id.t * Id.t FMul of Id.t * Id.t FDiv of Id.t * Id.t IfEq of Id.t * Id.t * t * t IfLE of Id.t * Id.t * t * t Let of (Id.t * Type.t) * t * t Var of Id.t MakeCls of (Id.t * Type.t) * closure * t AppCls of Id.t * Id.t list AppDir of Id.l * Id.t list Tuple of Id.t list LetTuple of (Id.t * Type.t) list * Id.t * t Get of Id.t * Id.t Put of Id.t * Id.t * Id.t ExtArray of Id.l type fundef = { name : Id.l * Type.t; args : (Id.t * Type.t) list; formal_fv : (Id.t * Type.t) list; body : t } type prog = Prog of fundef list * t let rec fv = function Unit Int(_) Float(_) ExtArray(_) -> S.empty Neg(x) FNeg(x) -> S.singleton x Add(x, y) Sub(x, y) FAdd(x, y) FSub(x, y) FMul(x, y) FDiv(x, y) Get(x, y) -> S.of_list [x; y] IfEq(x, y, e1, e2) IfLE(x, y, e1, e2) -> S.add x (S.add y (S.union (fv e1) (fv e2))) Let((x, t), e1, e2) -> S.union (fv e1) (S.remove x (fv e2)) Var(x) -> S.singleton x MakeCls((x, t), { entry = l; actual_fv = ys }, e) -> S.remove x (S.union (S.of_list ys) (fv e)) AppCls(x, ys) -> S.of_list (x :: ys) AppDir(_, xs) Tuple(xs) -> S.of_list xs LetTuple(xts, y, e) -> S.add y (S.diff (fv e) (S.of_list (List.map fst xts))) Put(x, y, z) -> S.of_list [x; y; z] let toplevel : fundef list ref = ref [] let rec g env known = function (* クロージャ変換ルーチン本体 *) KNormal.Unit -> Unit KNormal.Int(i) -> Int(i) KNormal.Float(d) -> Float(d) KNormal.Neg(x) -> Neg(x) KNormal.Add(x, y) -> Add(x, y) KNormal.Sub(x, y) -> Sub(x, y) KNormal.FNeg(x) -> FNeg(x) KNormal.FAdd(x, y) -> FAdd(x, y) KNormal.FSub(x, y) -> FSub(x, y) KNormal.FMul(x, y) -> FMul(x, y) KNormal.FDiv(x, y) -> FDiv(x, y) KNormal.IfEq(x, y, e1, e2) -> IfEq(x, y, g env known e1, g env known e2) KNormal.IfLE(x, y, e1, e2) -> IfLE(x, y, g env known e1, g env known e2) KNormal.Let((x, t), e1, e2) -> Let((x, t), g env known e1, g (M.add x t env) known e2) KNormal.Var(x) -> Var(x) KNormal.LetRec({ KNormal.name = (x, t); KNormal.args = yts; KNormal.body = e1 }, e2) -> (* 関数定義の場合 *) (* 関数定義let rec x y1 ... yn = e1 in e2の場合は、 xに自由変数がない(closureを介さずdirectに呼び出せる) と仮定し、knownに追加してe1をクロージャ変換してみる *) let toplevel_backup = !toplevel in let env' = M.add x t env in let known' = S.add x known in let e1' = g (M.add_list yts env') known' e1 in (* 本当に自由変数がなかったか、変換結果e1'を確認する *) (* 注意: e1'にx自身が変数として出現する場合はclosureが必要! (thanks to nuevo-namasute and azounoman; test/cls-bug2.ml参照) *) let zs = S.diff (fv e1') (S.of_list (List.map fst yts)) in let known', e1' = if S.is_empty zs then known', e1' else (* 駄目だったら状態(toplevelの値)を戻して、クロージャ変換をやり直す *) (Format.eprintf "free variable(s) %s found in function %s@." (Id.pp_list (S.elements zs)) x; Format.eprintf "function %s cannot be directly applied in fact@." x; toplevel := toplevel_backup; let e1' = g (M.add_list yts env') known e1 in known, e1') in let zs = S.elements (S.diff (fv e1') (S.add x (S.of_list (List.map fst yts)))) in (* 自由変数のリスト *) let zts = List.map (fun z -> (z, M.find z env')) zs in (* ここで自由変数zの型を引くために引数envが必要 *) toplevel := { name = (Id.L(x), t); args = yts; formal_fv = zts; body = e1' } :: !toplevel; (* トップレベル関数を追加 *) let e2' = g env' known' e2 in if S.mem x (fv e2') then (* xが変数としてe2'に出現するか *) MakeCls((x, t), { entry = Id.L(x); actual_fv = zs }, e2') (* 出現していたら削除しない *) else (Format.eprintf "eliminating closure(s) %s@." x; e2') (* 出現しなければMakeClsを削除 *) KNormal.App(x, ys) when S.mem x known -> (* 関数適用の場合 *) Format.eprintf "directly applying %s@." x; AppDir(Id.L(x), ys) KNormal.App(f, xs) -> AppCls(f, xs) KNormal.Tuple(xs) -> Tuple(xs) KNormal.LetTuple(xts, y, e) -> LetTuple(xts, y, g (M.add_list xts env) known e) KNormal.Get(x, y) -> Get(x, y) KNormal.Put(x, y, z) -> Put(x, y, z) KNormal.ExtArray(x) -> ExtArray(Id.L(x)) KNormal.ExtFunApp(x, ys) -> AppDir(Id.L("min_caml_" ^ x), ys) let f e = toplevel := []; let e' = g M.empty S.empty e in Prog(List.rev !toplevel, e')
asm.mli
type id_or_imm = V of Id.t C of int type t = Ans of exp Let of (Id.t * Type.t) * exp * t and exp = Nop Set of int SetL of Id.l Mov of Id.t Neg of Id.t Add of Id.t * id_or_imm Sub of Id.t * id_or_imm SLL of Id.t * id_or_imm Ld of Id.t * id_or_imm St of Id.t * Id.t * id_or_imm FMovD of Id.t FNegD of Id.t FAddD of Id.t * Id.t FSubD of Id.t * Id.t FMulD of Id.t * Id.t FDivD of Id.t * Id.t LdDF of Id.t * id_or_imm StDF of Id.t * Id.t * id_or_imm Comment of string (* virtual instructions *) IfEq of Id.t * id_or_imm * t * t IfLE of Id.t * id_or_imm * t * t IfGE of Id.t * id_or_imm * t * t IfFEq of Id.t * Id.t * t * t IfFLE of Id.t * Id.t * t * t (* closure address, integer arguments, and float arguments *) CallCls of Id.t * Id.t list * Id.t list CallDir of Id.l * Id.t list * Id.t list Save of Id.t * Id.t (* レジスタ変数の値をスタック変数へ保存 *) Restore of Id.t (* スタック変数から値を復元 *) type fundef = { name : Id.l; args : Id.t list; fargs : Id.t list; body : t; ret : Type.t } type prog = Prog of (Id.l * float) list * fundef list * t val fletd : Id.t * exp * t -> t (* shorthand of Let for float *) val seq : exp * t -> t (* shorthand of Let for unit *) val regs : Id.t array val fregs : Id.t array val allregs : Id.t list val allfregs : Id.t list val reg_cl : Id.t val reg_sw : Id.t val reg_fsw : Id.t val reg_ra : Id.t val reg_hp : Id.t val reg_sp : Id.t val is_reg : Id.t -> bool val co_freg : Id.t -> Id.t val fv : t -> Id.t list val concat : t -> Id.t * Type.t -> t -> t val align : int -> int
asm.ml
(* SPARC assembly with a few virtual instructions *) type id_or_imm = V of Id.t C of int type t = (* 命令の列 *) Ans of exp Let of (Id.t * Type.t) * exp * t and exp = (* 一つ一つの命令に対応する式 *) Nop Set of int SetL of Id.l Mov of Id.t Neg of Id.t Add of Id.t * id_or_imm Sub of Id.t * id_or_imm SLL of Id.t * id_or_imm Ld of Id.t * id_or_imm St of Id.t * Id.t * id_or_imm FMovD of Id.t FNegD of Id.t FAddD of Id.t * Id.t FSubD of Id.t * Id.t FMulD of Id.t * Id.t FDivD of Id.t * Id.t LdDF of Id.t * id_or_imm StDF of Id.t * Id.t * id_or_imm Comment of string (* virtual instructions *) IfEq of Id.t * id_or_imm * t * t IfLE of Id.t * id_or_imm * t * t IfGE of Id.t * id_or_imm * t * t (* 左右対称ではないので必要 *) IfFEq of Id.t * Id.t * t * t IfFLE of Id.t * Id.t * t * t (* closure address, integer arguments, and float arguments *) CallCls of Id.t * Id.t list * Id.t list CallDir of Id.l * Id.t list * Id.t list Save of Id.t * Id.t (* レジスタ変数の値をスタック変数へ保存 *) Restore of Id.t (* スタック変数から値を復元 *) type fundef = { name : Id.l; args : Id.t list; fargs : Id.t list; body : t; ret : Type.t } (* プログラム全体 = 浮動小数点数テーブル + トップレベル関数 + メインの式 *) type prog = Prog of (Id.l * float) list * fundef list * t let fletd(x, e1, e2) = Let((x, Type.Float), e1, e2) let seq(e1, e2) = Let((Id.gentmp Type.Unit, Type.Unit), e1, e2) let regs = (* Array.init 16 (fun i -> Printf.sprintf "%%r%d" i) *) [| "%i2"; "%i3"; "%i4"; "%i5"; "%l0"; "%l1"; "%l2"; "%l3"; "%l4"; "%l5"; "%l6"; "%l7"; "%o0"; "%o1"; "%o2"; "%o3"; "%o4"; "%o5" |] let fregs = Array.init 16 (fun i -> Printf.sprintf "%%f%d" (i * 2)) let allregs = Array.to_list regs let allfregs = Array.to_list fregs let reg_cl = regs.(Array.length regs - 1) (* closure address *) let reg_sw = regs.(Array.length regs - 2) (* temporary for swap *) let reg_fsw = fregs.(Array.length fregs - 1) (* temporary for swap *) let reg_sp = "%i0" (* stack pointer *) let reg_hp = "%i1" (* heap pointer *) let reg_ra = "%o7" (* return address *) let is_reg x = (x.[0] = '%') let co_freg_table = let ht = Hashtbl.create 16 in for i = 0 to 15 do Hashtbl.add ht (Printf.sprintf "%%f%d" (i * 2)) (Printf.sprintf "%%f%d" (i * 2 + 1)) done; ht let co_freg freg = Hashtbl.find co_freg_table freg (* "companion" freg *) (* super-tenuki *) let rec remove_and_uniq xs = function [] -> [] x :: ys when S.mem x xs -> remove_and_uniq xs ys x :: ys -> x :: remove_and_uniq (S.add x xs) ys (* free variables in the order of use (for spilling) *) let fv_id_or_imm = function V(x) -> [x] _ -> [] let rec fv_exp = function Nop Set(_) SetL(_) Comment(_) Restore(_) -> [] Mov(x) Neg(x) FMovD(x) FNegD(x) Save(x, _) -> [x] Add(x, y') Sub(x, y') SLL(x, y') Ld(x, y') LdDF(x, y') -> x :: fv_id_or_imm y' St(x, y, z') StDF(x, y, z') -> x :: y :: fv_id_or_imm z' FAddD(x, y) FSubD(x, y) FMulD(x, y) FDivD(x, y) -> [x; y] IfEq(x, y', e1, e2) IfLE(x, y', e1, e2) IfGE(x, y', e1, e2) -> x :: fv_id_or_imm y' @ remove_and_uniq S.empty (fv e1 @ fv e2) (* uniq here just for efficiency *) IfFEq(x, y, e1, e2) IfFLE(x, y, e1, e2) -> x :: y :: remove_and_uniq S.empty (fv e1 @ fv e2) (* uniq here just for efficiency *) CallCls(x, ys, zs) -> x :: ys @ zs CallDir(_, ys, zs) -> ys @ zs and fv = function Ans(exp) -> fv_exp exp Let((x, t), exp, e) -> fv_exp exp @ remove_and_uniq (S.singleton x) (fv e) let fv e = remove_and_uniq S.empty (fv e) let rec concat e1 xt e2 = match e1 with Ans(exp) -> Let(xt, exp, e2) Let(yt, exp, e1') -> Let(yt, exp, concat e1' xt e2) let align i = (if i mod 8 = 0 then i else i + 4)
virtual.mli
val f : Closure.prog -> Asm.prog
virtual.ml
(* translation into SPARC assembly with infinite number of virtual registers *) open Asm let data = ref [] (* 浮動小数点数の定数テーブル *) let classify xts ini addf addi = List.fold_left (fun acc (x, t) -> match t with Type.Unit -> acc Type.Float -> addf acc x _ -> addi acc x t) ini xts let separate xts = classify xts ([], []) (fun (int, float) x -> (int, float @ [x])) (fun (int, float) x _ -> (int @ [x], float)) let expand xts ini addf addi = classify xts ini (fun (offset, acc) x -> let offset = align offset in (offset + 8, addf x offset acc)) (fun (offset, acc) x t -> (offset + 4, addi x t offset acc)) let rec g env = function (* 式の仮想マシンコード生成 *) Closure.Unit -> Ans(Nop) Closure.Int(i) -> Ans(Set(i)) Closure.Float(d) -> let l = try (* すでに定数テーブルにあったら再利用 *) let (l, _) = List.find (fun (_, d') -> d = d') !data in l with Not_found -> let l = Id.L(Id.genid "l") in data := (l, d) :: !data; l in let x = Id.genid "l" in Let((x, Type.Int), SetL(l), Ans(LdDF(x, C(0)))) Closure.Neg(x) -> Ans(Neg(x)) Closure.Add(x, y) -> Ans(Add(x, V(y))) Closure.Sub(x, y) -> Ans(Sub(x, V(y))) Closure.FNeg(x) -> Ans(FNegD(x)) Closure.FAdd(x, y) -> Ans(FAddD(x, y)) Closure.FSub(x, y) -> Ans(FSubD(x, y)) Closure.FMul(x, y) -> Ans(FMulD(x, y)) Closure.FDiv(x, y) -> Ans(FDivD(x, y)) Closure.IfEq(x, y, e1, e2) -> (match M.find x env with Type.Bool Type.Int -> Ans(IfEq(x, V(y), g env e1, g env e2)) Type.Float -> Ans(IfFEq(x, y, g env e1, g env e2)) _ -> failwith "equality supported only for bool, int, and float") Closure.IfLE(x, y, e1, e2) -> (match M.find x env with Type.Bool Type.Int -> Ans(IfLE(x, V(y), g env e1, g env e2)) Type.Float -> Ans(IfFLE(x, y, g env e1, g env e2)) _ -> failwith "inequality supported only for bool, int, and float") Closure.Let((x, t1), e1, e2) -> let e1' = g env e1 in let e2' = g (M.add x t1 env) e2 in concat e1' (x, t1) e2' Closure.Var(x) -> (match M.find x env with Type.Unit -> Ans(Nop) Type.Float -> Ans(FMovD(x)) _ -> Ans(Mov(x))) Closure.MakeCls((x, t), { Closure.entry = l; Closure.actual_fv = ys }, e2) -> (* クロージャの生成 *) (* Closureのアドレスをセットしてから、自由変数の値をストア *) let e2' = g (M.add x t env) e2 in let offset, store_fv = expand (List.map (fun y -> (y, M.find y env)) ys) (4, e2') (fun y offset store_fv -> seq(StDF(y, x, C(offset)), store_fv)) (fun y _ offset store_fv -> seq(St(y, x, C(offset)), store_fv)) in Let((x, t), Mov(reg_hp), Let((reg_hp, Type.Int), Add(reg_hp, C(align offset)), let z = Id.genid "l" in Let((z, Type.Int), SetL(l), seq(St(z, x, C(0)), store_fv)))) Closure.AppCls(x, ys) -> let (int, float) = separate (List.map (fun y -> (y, M.find y env)) ys) in Ans(CallCls(x, int, float)) Closure.AppDir(Id.L(x), ys) -> let (int, float) = separate (List.map (fun y -> (y, M.find y env)) ys) in Ans(CallDir(Id.L(x), int, float)) Closure.Tuple(xs) -> (* 組の生成 *) let y = Id.genid "t" in let (offset, store) = expand (List.map (fun x -> (x, M.find x env)) xs) (0, Ans(Mov(y))) (fun x offset store -> seq(StDF(x, y, C(offset)), store)) (fun x _ offset store -> seq(St(x, y, C(offset)), store)) in Let((y, Type.Tuple(List.map (fun x -> M.find x env) xs)), Mov(reg_hp), Let((reg_hp, Type.Int), Add(reg_hp, C(align offset)), store)) Closure.LetTuple(xts, y, e2) -> let s = Closure.fv e2 in let (offset, load) = expand xts (0, g (M.add_list xts env) e2) (fun x offset load -> if not (S.mem x s) then load else (* [XX] a little ad hoc optimization *) fletd(x, LdDF(y, C(offset)), load)) (fun x t offset load -> if not (S.mem x s) then load else (* [XX] a little ad hoc optimization *) Let((x, t), Ld(y, C(offset)), load)) in load Closure.Get(x, y) -> (* 配列の読み出し *) let offset = Id.genid "o" in (match M.find x env with Type.Array(Type.Unit) -> Ans(Nop) Type.Array(Type.Float) -> Let((offset, Type.Int), SLL(y, C(3)), Ans(LdDF(x, V(offset)))) Type.Array(_) -> Let((offset, Type.Int), SLL(y, C(2)), Ans(Ld(x, V(offset)))) _ -> assert false) Closure.Put(x, y, z) -> let offset = Id.genid "o" in (match M.find x env with Type.Array(Type.Unit) -> Ans(Nop) Type.Array(Type.Float) -> Let((offset, Type.Int), SLL(y, C(3)), Ans(StDF(z, x, V(offset)))) Type.Array(_) -> Let((offset, Type.Int), SLL(y, C(2)), Ans(St(z, x, V(offset)))) _ -> assert false) Closure.ExtArray(Id.L(x)) -> Ans(SetL(Id.L("min_caml_" ^ x))) (* 関数の仮想マシンコード生成 *) let h { Closure.name = (Id.L(x), t); Closure.args = yts; Closure.formal_fv = zts; Closure.body = e } = let (int, float) = separate yts in let (offset, load) = expand zts (4, g (M.add x t (M.add_list yts (M.add_list zts M.empty))) e) (fun z offset load -> fletd(z, LdDF(reg_cl, C(offset)), load)) (fun z t offset load -> Let((z, t), Ld(reg_cl, C(offset)), load)) in match t with Type.Fun(_, t2) -> { name = Id.L(x); args = int; fargs = float; body = load; ret = t2 } _ -> assert false (* プログラム全体の仮想マシンコード生成 *) let f (Closure.Prog(fundefs, e)) = data := []; let fundefs = List.map h fundefs in let e = g M.empty e in Prog(!data, fundefs, e)
simm.mli
val f : Asm.prog -> Asm.prog
simm.ml
open Asm let rec g env = function (* 命令列の13bit即値最適化 *) Ans(exp) -> Ans(g' env exp) Let((x, t), Set(i), e) when (-4096 <= i) && (i < 4096) -> (* Format.eprintf "found simm13 %s = %d@." x i; *) let e' = g (M.add x i env) e in if List.mem x (fv e') then Let((x, t), Set(i), e') else ((* Format.eprintf "erased redundant Set to %s@." x; *) e') Let(xt, SLL(y, C(i)), e) when M.mem y env -> (* for array access *) (* Format.eprintf "erased redundant SLL on %s@." x; *) g env (Let(xt, Set((M.find y env) lsl i), e)) Let(xt, exp, e) -> Let(xt, g' env exp, g env e) and g' env = function (* 各命令の13bit即値最適化 *) Add(x, V(y)) when M.mem y env -> Add(x, C(M.find y env)) Add(x, V(y)) when M.mem x env -> Add(y, C(M.find x env)) Sub(x, V(y)) when M.mem y env -> Sub(x, C(M.find y env)) SLL(x, V(y)) when M.mem y env -> SLL(x, C(M.find y env)) Ld(x, V(y)) when M.mem y env -> Ld(x, C(M.find y env)) St(x, y, V(z)) when M.mem z env -> St(x, y, C(M.find z env)) LdDF(x, V(y)) when M.mem y env -> LdDF(x, C(M.find y env)) StDF(x, y, V(z)) when M.mem z env -> StDF(x, y, C(M.find z env)) IfEq(x, V(y), e1, e2) when M.mem y env -> IfEq(x, C(M.find y env), g env e1, g env e2) IfLE(x, V(y), e1, e2) when M.mem y env -> IfLE(x, C(M.find y env), g env e1, g env e2) IfGE(x, V(y), e1, e2) when M.mem y env -> IfGE(x, C(M.find y env), g env e1, g env e2) IfEq(x, V(y), e1, e2) when M.mem x env -> IfEq(y, C(M.find x env), g env e1, g env e2) IfLE(x, V(y), e1, e2) when M.mem x env -> IfGE(y, C(M.find x env), g env e1, g env e2) IfGE(x, V(y), e1, e2) when M.mem x env -> IfLE(y, C(M.find x env), g env e1, g env e2) IfEq(x, y', e1, e2) -> IfEq(x, y', g env e1, g env e2) IfLE(x, y', e1, e2) -> IfLE(x, y', g env e1, g env e2) IfGE(x, y', e1, e2) -> IfGE(x, y', g env e1, g env e2) IfFEq(x, y, e1, e2) -> IfFEq(x, y, g env e1, g env e2) IfFLE(x, y, e1, e2) -> IfFLE(x, y, g env e1, g env e2) e -> e let h { name = l; args = xs; fargs = ys; body = e; ret = t } = (* トップレベル関数の13bit即値最適化 *) { name = l; args = xs; fargs = ys; body = g M.empty e; ret = t } let f (Prog(data, fundefs, e)) = (* プログラム全体の13bit即値最適化 *) Prog(data, List.map h fundefs, g M.empty e)
regAlloc.mli
val f : Asm.prog -> Asm.prog
regAlloc.ml
open Asm (* for register coalescing *) (* [XXX] Callがあったら、そこから先は無意味というか逆効果なので追わない。 そのために「Callがあったかどうか」を返り値の第1要素に含める。 *) let rec target' src (dest, t) = function Mov(x) when x = src && is_reg dest -> assert (t <> Type.Unit); assert (t <> Type.Float); false, [dest] FMovD(x) when x = src && is_reg dest -> assert (t = Type.Float); false, [dest] IfEq(_, _, e1, e2) IfLE(_, _, e1, e2) IfGE(_, _, e1, e2) IfFEq(_, _, e1, e2) IfFLE(_, _, e1, e2) -> let c1, rs1 = target src (dest, t) e1 in let c2, rs2 = target src (dest, t) e2 in c1 && c2, rs1 @ rs2 CallCls(x, ys, zs) -> true, (target_args src regs 0 ys @ target_args src fregs 0 zs @ if x = src then [reg_cl] else []) CallDir(_, ys, zs) -> true, (target_args src regs 0 ys @ target_args src fregs 0 zs) _ -> false, [] and target src dest = function (* register targeting *) Ans(exp) -> target' src dest exp Let(xt, exp, e) -> let c1, rs1 = target' src xt exp in if c1 then true, rs1 else let c2, rs2 = target src dest e in c2, rs1 @ rs2 and target_args src all n = function (* auxiliary function for Call *) [] -> [] y :: ys when src = y -> all.(n) :: target_args src all (n + 1) ys _ :: ys -> target_args src all (n + 1) ys type alloc_result = (* allocにおいてspillingがあったかどうかを表すデータ型 *) Alloc of Id.t (* allocated register *) Spill of Id.t (* spilled variable *) let rec alloc dest cont regenv x t = (* allocate a register or spill a variable *) assert (not (M.mem x regenv)); let all = match t with Type.Unit -> ["%g0"] (* dummy *) Type.Float -> allfregs _ -> allregs in if all = ["%g0"] then Alloc("%g0") else (* [XX] ad hoc optimization *) if is_reg x then Alloc(x) else let free = fv cont in try let (c, prefer) = target x dest cont in let live = (* 生きているレジスタ *) List.fold_left (fun live y -> if is_reg y then S.add y live else try S.add (M.find y regenv) live with Not_found -> live) S.empty free in let r = (* そうでないレジスタを探す *) List.find (fun r -> not (S.mem r live)) (prefer @ all) in (* Format.eprintf "allocated %s to %s@." x r; *) Alloc(r) with Not_found -> Format.eprintf "register allocation failed for %s@." x; let y = (* 型の合うレジスタ変数を探す *) List.find (fun y -> not (is_reg y) && try List.mem (M.find y regenv) all with Not_found -> false) (List.rev free) in Format.eprintf "spilling %s from %s@." y (M.find y regenv); Spill(y) (* auxiliary function for g and g'_and_restore *) let add x r regenv = if is_reg x then (assert (x = r); regenv) else M.add x r regenv (* auxiliary functions for g' *) exception NoReg of Id.t * Type.t let find x t regenv = if is_reg x then x else try M.find x regenv with Not_found -> raise (NoReg(x, t)) let find' x' regenv = match x' with V(x) -> V(find x Type.Int regenv) c -> c let rec g dest cont regenv = function (* 命令列のレジスタ割り当て *) Ans(exp) -> g'_and_restore dest cont regenv exp Let((x, t) as xt, exp, e) -> assert (not (M.mem x regenv)); let cont' = concat e dest cont in let (e1', regenv1) = g'_and_restore xt cont' regenv exp in (match alloc dest cont' regenv1 x t with Spill(y) -> let r = M.find y regenv1 in let (e2', regenv2) = g dest cont (add x r (M.remove y regenv1)) e in let save = try Save(M.find y regenv, y) with Not_found -> Nop in (seq(save, concat e1' (r, t) e2'), regenv2) Alloc(r) -> let (e2', regenv2) = g dest cont (add x r regenv1) e in (concat e1' (r, t) e2', regenv2)) and g'_and_restore dest cont regenv exp = (* 使用される変数をスタックからレジスタへRestore *) try g' dest cont regenv exp with NoReg(x, t) -> ((* Format.eprintf "restoring %s@." x; *) g dest cont regenv (Let((x, t), Restore(x), Ans(exp)))) and g' dest cont regenv = function (* 各命令のレジスタ割り当て *) Nop Set _ SetL _ Comment _ Restore _ as exp -> (Ans(exp), regenv) Mov(x) -> (Ans(Mov(find x Type.Int regenv)), regenv) Neg(x) -> (Ans(Neg(find x Type.Int regenv)), regenv) Add(x, y') -> (Ans(Add(find x Type.Int regenv, find' y' regenv)), regenv) Sub(x, y') -> (Ans(Sub(find x Type.Int regenv, find' y' regenv)), regenv) SLL(x, y') -> (Ans(SLL(find x Type.Int regenv, find' y' regenv)), regenv) Ld(x, y') -> (Ans(Ld(find x Type.Int regenv, find' y' regenv)), regenv) St(x, y, z') -> (Ans(St(find x Type.Int regenv, find y Type.Int regenv, find' z' regenv)), regenv) FMovD(x) -> (Ans(FMovD(find x Type.Float regenv)), regenv) FNegD(x) -> (Ans(FNegD(find x Type.Float regenv)), regenv) FAddD(x, y) -> (Ans(FAddD(find x Type.Float regenv, find y Type.Float regenv)), regenv) FSubD(x, y) -> (Ans(FSubD(find x Type.Float regenv, find y Type.Float regenv)), regenv) FMulD(x, y) -> (Ans(FMulD(find x Type.Float regenv, find y Type.Float regenv)), regenv) FDivD(x, y) -> (Ans(FDivD(find x Type.Float regenv, find y Type.Float regenv)), regenv) LdDF(x, y') -> (Ans(LdDF(find x Type.Int regenv, find' y' regenv)), regenv) StDF(x, y, z') -> (Ans(StDF(find x Type.Float regenv, find y Type.Int regenv, find' z' regenv)), regenv) IfEq(x, y', e1, e2) as exp -> g'_if dest cont regenv exp (fun e1' e2' -> IfEq(find x Type.Int regenv, find' y' regenv, e1', e2')) e1 e2 IfLE(x, y', e1, e2) as exp -> g'_if dest cont regenv exp (fun e1' e2' -> IfLE(find x Type.Int regenv, find' y' regenv, e1', e2')) e1 e2 IfGE(x, y', e1, e2) as exp -> g'_if dest cont regenv exp (fun e1' e2' -> IfGE(find x Type.Int regenv, find' y' regenv, e1', e2')) e1 e2 IfFEq(x, y, e1, e2) as exp -> g'_if dest cont regenv exp (fun e1' e2' -> IfFEq(find x Type.Float regenv, find y Type.Float regenv, e1', e2')) e1 e2 IfFLE(x, y, e1, e2) as exp -> g'_if dest cont regenv exp (fun e1' e2' -> IfFLE(find x Type.Float regenv, find y Type.Float regenv, e1', e2')) e1 e2 CallCls(x, ys, zs) as exp -> g'_call dest cont regenv exp (fun ys zs -> CallCls(find x Type.Int regenv, ys, zs)) ys zs CallDir(l, ys, zs) as exp -> g'_call dest cont regenv exp (fun ys zs -> CallDir(l, ys, zs)) ys zs Save(x, y) -> assert false and g'_if dest cont regenv exp constr e1 e2 = (* ifのレジスタ割り当て *) let (e1', regenv1) = g dest cont regenv e1 in let (e2', regenv2) = g dest cont regenv e2 in let regenv' = (* 両方に共通のレジスタ変数だけ利用 *) List.fold_left (fun regenv' x -> try if is_reg x then regenv' else let r1 = M.find x regenv1 in let r2 = M.find x regenv2 in if r1 <> r2 then regenv' else M.add x r1 regenv' with Not_found -> regenv') M.empty (fv cont) in (List.fold_left (fun e x -> if x = fst dest || not (M.mem x regenv) || M.mem x regenv' then e else seq(Save(M.find x regenv, x), e)) (* そうでない変数は分岐直前にセーブ *) (Ans(constr e1' e2')) (fv cont), regenv') and g'_call dest cont regenv exp constr ys zs = (* 関数呼び出しのレジスタ割り当て *) (List.fold_left (fun e x -> if x = fst dest || not (M.mem x regenv) then e else seq(Save(M.find x regenv, x), e)) (Ans(constr (List.map (fun y -> find y Type.Int regenv) ys) (List.map (fun z -> find z Type.Float regenv) zs))) (fv cont), M.empty) let h { name = Id.L(x); args = ys; fargs = zs; body = e; ret = t } = (* 関数のレジスタ割り当て *) let regenv = M.add x reg_cl M.empty in let (i, arg_regs, regenv) = List.fold_left (fun (i, arg_regs, regenv) y -> let r = regs.(i) in (i + 1, arg_regs @ [r], (assert (not (is_reg y)); M.add y r regenv))) (0, [], regenv) ys in let (d, farg_regs, regenv) = List.fold_left (fun (d, farg_regs, regenv) z -> let fr = fregs.(d) in (d + 1, farg_regs @ [fr], (assert (not (is_reg z)); M.add z fr regenv))) (0, [], regenv) zs in let a = match t with Type.Unit -> Id.gentmp Type.Unit Type.Float -> fregs.(0) _ -> regs.(0) in let (e', regenv') = g (a, t) (Ans(Mov(a))) regenv e in { name = Id.L(x); args = arg_regs; fargs = farg_regs; body = e'; ret = t } let f (Prog(data, fundefs, e)) = (* プログラム全体のレジスタ割り当て *) Format.eprintf "register allocation: may take some time (up to a few minutes, depending on the size of functions)@."; let fundefs' = List.map h fundefs in let e', regenv' = g (Id.gentmp Type.Unit, Type.Unit) (Ans(Nop)) M.empty e in Prog(data, fundefs', e')
emit.mli
val f : out_channel -> Asm.prog -> unit
emit.ml
open Asm external gethi : float -> int32 = "gethi" external getlo : float -> int32 = "getlo" let stackset = ref S.empty (* すでにSaveされた変数の集合 *) let stackmap = ref [] (* Saveされた変数の、スタックにおける位置 *) let save x = stackset := S.add x !stackset; if not (List.mem x !stackmap) then stackmap := !stackmap @ [x] let savef x = stackset := S.add x !stackset; if not (List.mem x !stackmap) then (let pad = if List.length !stackmap mod 2 = 0 then [] else [Id.gentmp Type.Int] in stackmap := !stackmap @ pad @ [x; x]) let locate x = let rec loc = function [] -> [] y :: zs when x = y -> 0 :: List.map succ (loc zs) y :: zs -> List.map succ (loc zs) in loc !stackmap let offset x = 4 * List.hd (locate x) let stacksize () = align ((List.length !stackmap + 1) * 4) let pp_id_or_imm = function V(x) -> x C(i) -> string_of_int i (* 関数呼び出しのために引数を並べ替える(register shuffling) *) let rec shuffle sw xys = (* remove identical moves *) let _, xys = List.partition (fun (x, y) -> x = y) xys in (* find acyclic moves *) match List.partition (fun (_, y) -> List.mem_assoc y xys) xys with [], [] -> [] (x, y) :: xys, [] -> (* no acyclic moves; resolve a cyclic move *) (y, sw) :: (x, y) :: shuffle sw (List.map (function (y', z) when y = y' -> (sw, z) yz -> yz) xys) xys, acyc -> acyc @ shuffle sw xys type dest = Tail NonTail of Id.t (* 末尾かどうかを表すデータ型 *) let rec g oc = function (* 命令列のアセンブリ生成 *) dest, Ans(exp) -> g' oc (dest, exp) dest, Let((x, t), exp, e) -> g' oc (NonTail(x), exp); g oc (dest, e) and g' oc = function (* 各命令のアセンブリ生成 *) (* 末尾でなかったら計算結果をdestにセット *) NonTail(_), Nop -> () NonTail(x), Set(i) -> Printf.fprintf oc "\tset\t%d, %s\n" i x NonTail(x), SetL(Id.L(y)) -> Printf.fprintf oc "\tset\t%s, %s\n" y x NonTail(x), Mov(y) when x = y -> () NonTail(x), Mov(y) -> Printf.fprintf oc "\tmov\t%s, %s\n" y x NonTail(x), Neg(y) -> Printf.fprintf oc "\tneg\t%s, %s\n" y x NonTail(x), Add(y, z') -> Printf.fprintf oc "\tadd\t%s, %s, %s\n" y (pp_id_or_imm z') x NonTail(x), Sub(y, z') -> Printf.fprintf oc "\tsub\t%s, %s, %s\n" y (pp_id_or_imm z') x NonTail(x), SLL(y, z') -> Printf.fprintf oc "\tsll\t%s, %s, %s\n" y (pp_id_or_imm z') x NonTail(x), Ld(y, z') -> Printf.fprintf oc "\tld\t[%s + %s], %s\n" y (pp_id_or_imm z') x NonTail(_), St(x, y, z') -> Printf.fprintf oc "\tst\t%s, [%s + %s]\n" x y (pp_id_or_imm z') NonTail(x), FMovD(y) when x = y -> () NonTail(x), FMovD(y) -> Printf.fprintf oc "\tfmovs\t%s, %s\n" y x; Printf.fprintf oc "\tfmovs\t%s, %s\n" (co_freg y) (co_freg x) NonTail(x), FNegD(y) -> Printf.fprintf oc "\tfnegs\t%s, %s\n" y x; if x <> y then Printf.fprintf oc "\tfmovs\t%s, %s\n" (co_freg y) (co_freg x) NonTail(x), FAddD(y, z) -> Printf.fprintf oc "\tfaddd\t%s, %s, %s\n" y z x NonTail(x), FSubD(y, z) -> Printf.fprintf oc "\tfsubd\t%s, %s, %s\n" y z x NonTail(x), FMulD(y, z) -> Printf.fprintf oc "\tfmuld\t%s, %s, %s\n" y z x NonTail(x), FDivD(y, z) -> Printf.fprintf oc "\tfdivd\t%s, %s, %s\n" y z x NonTail(x), LdDF(y, z') -> Printf.fprintf oc "\tldd\t[%s + %s], %s\n" y (pp_id_or_imm z') x NonTail(_), StDF(x, y, z') -> Printf.fprintf oc "\tstd\t%s, [%s + %s]\n" x y (pp_id_or_imm z') NonTail(_), Comment(s) -> Printf.fprintf oc "\t! %s\n" s (* 退避の仮想命令の実装 *) NonTail(_), Save(x, y) when List.mem x allregs && not (S.mem y !stackset) -> save y; Printf.fprintf oc "\tst\t%s, [%s + %d]\n" x reg_sp (offset y) NonTail(_), Save(x, y) when List.mem x allfregs && not (S.mem y !stackset) -> savef y; Printf.fprintf oc "\tstd\t%s, [%s + %d]\n" x reg_sp (offset y) NonTail(_), Save(x, y) -> assert (S.mem y !stackset); () (* 復帰の仮想命令の実装 *) NonTail(x), Restore(y) when List.mem x allregs -> Printf.fprintf oc "\tld\t[%s + %d], %s\n" reg_sp (offset y) x NonTail(x), Restore(y) -> assert (List.mem x allfregs); Printf.fprintf oc "\tldd\t[%s + %d], %s\n" reg_sp (offset y) x (* 末尾だったら計算結果を第一レジスタにセットしてret *) Tail, (Nop St _ StDF _ Comment _ Save _ as exp) -> g' oc (NonTail(Id.gentmp Type.Unit), exp); Printf.fprintf oc "\tretl\n"; Printf.fprintf oc "\tnop\n" Tail, (Set _ SetL _ Mov _ Neg _ Add _ Sub _ SLL _ Ld _ as exp) -> g' oc (NonTail(regs.(0)), exp); Printf.fprintf oc "\tretl\n"; Printf.fprintf oc "\tnop\n" Tail, (FMovD _ FNegD _ FAddD _ FSubD _ FMulD _ FDivD _ LdDF _ as exp) -> g' oc (NonTail(fregs.(0)), exp); Printf.fprintf oc "\tretl\n"; Printf.fprintf oc "\tnop\n" Tail, (Restore(x) as exp) -> (match locate x with [i] -> g' oc (NonTail(regs.(0)), exp) [i; j] when i + 1 = j -> g' oc (NonTail(fregs.(0)), exp) _ -> assert false); Printf.fprintf oc "\tretl\n"; Printf.fprintf oc "\tnop\n" Tail, IfEq(x, y', e1, e2) -> Printf.fprintf oc "\tcmp\t%s, %s\n" x (pp_id_or_imm y'); g'_tail_if oc e1 e2 "be" "bne" Tail, IfLE(x, y', e1, e2) -> Printf.fprintf oc "\tcmp\t%s, %s\n" x (pp_id_or_imm y'); g'_tail_if oc e1 e2 "ble" "bg" Tail, IfGE(x, y', e1, e2) -> Printf.fprintf oc "\tcmp\t%s, %s\n" x (pp_id_or_imm y'); g'_tail_if oc e1 e2 "bge" "bl" Tail, IfFEq(x, y, e1, e2) -> Printf.fprintf oc "\tfcmpd\t%s, %s\n" x y; Printf.fprintf oc "\tnop\n"; g'_tail_if oc e1 e2 "fbe" "fbne" Tail, IfFLE(x, y, e1, e2) -> Printf.fprintf oc "\tfcmpd\t%s, %s\n" x y; Printf.fprintf oc "\tnop\n"; g'_tail_if oc e1 e2 "fble" "fbg" NonTail(z), IfEq(x, y', e1, e2) -> Printf.fprintf oc "\tcmp\t%s, %s\n" x (pp_id_or_imm y'); g'_non_tail_if oc (NonTail(z)) e1 e2 "be" "bne" NonTail(z), IfLE(x, y', e1, e2) -> Printf.fprintf oc "\tcmp\t%s, %s\n" x (pp_id_or_imm y'); g'_non_tail_if oc (NonTail(z)) e1 e2 "ble" "bg" NonTail(z), IfGE(x, y', e1, e2) -> Printf.fprintf oc "\tcmp\t%s, %s\n" x (pp_id_or_imm y'); g'_non_tail_if oc (NonTail(z)) e1 e2 "bge" "bl" NonTail(z), IfFEq(x, y, e1, e2) -> Printf.fprintf oc "\tfcmpd\t%s, %s\n" x y; Printf.fprintf oc "\tnop\n"; g'_non_tail_if oc (NonTail(z)) e1 e2 "fbe" "fbne" NonTail(z), IfFLE(x, y, e1, e2) -> Printf.fprintf oc "\tfcmpd\t%s, %s\n" x y; Printf.fprintf oc "\tnop\n"; g'_non_tail_if oc (NonTail(z)) e1 e2 "fble" "fbg" (* 関数呼び出しの仮想命令の実装 *) Tail, CallCls(x, ys, zs) -> (* 末尾呼び出し *) g'_args oc [(x, reg_cl)] ys zs; Printf.fprintf oc "\tld\t[%s + 0], %s\n" reg_cl reg_sw; Printf.fprintf oc "\tjmp\t%s\n" reg_sw; Printf.fprintf oc "\tnop\n" Tail, CallDir(Id.L(x), ys, zs) -> (* 末尾呼び出し *) g'_args oc [] ys zs; Printf.fprintf oc "\tb\t%s\n" x; Printf.fprintf oc "\tnop\n" NonTail(a), CallCls(x, ys, zs) -> g'_args oc [(x, reg_cl)] ys zs; let ss = stacksize () in Printf.fprintf oc "\tst\t%s, [%s + %d]\n" reg_ra reg_sp (ss - 4); Printf.fprintf oc "\tld\t[%s + 0], %s\n" reg_cl reg_sw; Printf.fprintf oc "\tcall\t%s\n" reg_sw; Printf.fprintf oc "\tadd\t%s, %d, %s\t! delay slot\n" reg_sp ss reg_sp; Printf.fprintf oc "\tsub\t%s, %d, %s\n" reg_sp ss reg_sp; Printf.fprintf oc "\tld\t[%s + %d], %s\n" reg_sp (ss - 4) reg_ra; if List.mem a allregs && a <> regs.(0) then Printf.fprintf oc "\tmov\t%s, %s\n" regs.(0) a else if List.mem a allfregs && a <> fregs.(0) then (Printf.fprintf oc "\tfmovs\t%s, %s\n" fregs.(0) a; Printf.fprintf oc "\tfmovs\t%s, %s\n" (co_freg fregs.(0)) (co_freg a)) NonTail(a), CallDir(Id.L(x), ys, zs) -> g'_args oc [] ys zs; let ss = stacksize () in Printf.fprintf oc "\tst\t%s, [%s + %d]\n" reg_ra reg_sp (ss - 4); Printf.fprintf oc "\tcall\t%s\n" x; Printf.fprintf oc "\tadd\t%s, %d, %s\t! delay slot\n" reg_sp ss reg_sp; Printf.fprintf oc "\tsub\t%s, %d, %s\n" reg_sp ss reg_sp; Printf.fprintf oc "\tld\t[%s + %d], %s\n" reg_sp (ss - 4) reg_ra; if List.mem a allregs && a <> regs.(0) then Printf.fprintf oc "\tmov\t%s, %s\n" regs.(0) a else if List.mem a allfregs && a <> fregs.(0) then (Printf.fprintf oc "\tfmovs\t%s, %s\n" fregs.(0) a; Printf.fprintf oc "\tfmovs\t%s, %s\n" (co_freg fregs.(0)) (co_freg a)) and g'_tail_if oc e1 e2 b bn = let b_else = Id.genid (b ^ "_else") in Printf.fprintf oc "\t%s\t%s\n" bn b_else; Printf.fprintf oc "\tnop\n"; let stackset_back = !stackset in g oc (Tail, e1); Printf.fprintf oc "%s:\n" b_else; stackset := stackset_back; g oc (Tail, e2) and g'_non_tail_if oc dest e1 e2 b bn = let b_else = Id.genid (b ^ "_else") in let b_cont = Id.genid (b ^ "_cont") in Printf.fprintf oc "\t%s\t%s\n" bn b_else; Printf.fprintf oc "\tnop\n"; let stackset_back = !stackset in g oc (dest, e1); let stackset1 = !stackset in Printf.fprintf oc "\tb\t%s\n" b_cont; Printf.fprintf oc "\tnop\n"; Printf.fprintf oc "%s:\n" b_else; stackset := stackset_back; g oc (dest, e2); Printf.fprintf oc "%s:\n" b_cont; let stackset2 = !stackset in stackset := S.inter stackset1 stackset2 and g'_args oc x_reg_cl ys zs = let (i, yrs) = List.fold_left (fun (i, yrs) y -> (i + 1, (y, regs.(i)) :: yrs)) (0, x_reg_cl) ys in List.iter (fun (y, r) -> Printf.fprintf oc "\tmov\t%s, %s\n" y r) (shuffle reg_sw yrs); let (d, zfrs) = List.fold_left (fun (d, zfrs) z -> (d + 1, (z, fregs.(d)) :: zfrs)) (0, []) zs in List.iter (fun (z, fr) -> Printf.fprintf oc "\tfmovs\t%s, %s\n" z fr; Printf.fprintf oc "\tfmovs\t%s, %s\n" (co_freg z) (co_freg fr)) (shuffle reg_fsw zfrs) let h oc { name = Id.L(x); args = _; fargs = _; body = e; ret = _ } = Printf.fprintf oc "%s:\n" x; stackset := S.empty; stackmap := []; g oc (Tail, e) let f oc (Prog(data, fundefs, e)) = Format.eprintf "generating assembly...@."; Printf.fprintf oc ".section\t\".rodata\"\n"; Printf.fprintf oc ".align\t8\n"; List.iter (fun (Id.L(x), d) -> Printf.fprintf oc "%s:\t! %f\n" x d; Printf.fprintf oc "\t.long\t0x%lx\n" (gethi d); Printf.fprintf oc "\t.long\t0x%lx\n" (getlo d)) data; Printf.fprintf oc ".section\t\".text\"\n"; List.iter (fun fundef -> h oc fundef) fundefs; Printf.fprintf oc ".global\tmin_caml_start\n"; Printf.fprintf oc "min_caml_start:\n"; Printf.fprintf oc "\tsave\t%%sp, -112, %%sp\n"; (* from gcc; why 112? *) stackset := S.empty; stackmap := []; g oc (NonTail("%g0"), e); Printf.fprintf oc "\tret\n"; Printf.fprintf oc "\trestore\n"
This document was generated using caml2html