-
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
395 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,394 @@ | ||
use std::collections::HashSet; | ||
|
||
use id; | ||
use id::IdGen; | ||
use std::io::Write; | ||
use syntax::Type; | ||
use x86::asm; | ||
use x86::asm::{Asm, Exp, Fundef, IdOrImm, Prog}; | ||
|
||
/* | ||
open Asm | ||
external gethi : float -> int32 = "gethi" | ||
external getlo : float -> int32 = "getlo" | ||
let stackset = ref S.empty (* すでにSaveされた変数の集合 (caml2html: emit_stackset) *) | ||
let stackmap = ref [] (* Saveされた変数の、スタックにおける位置 (caml2html: emit_stackmap) *) | ||
*/ | ||
|
||
type StackSet = HashSet<String>; | ||
type StackMap = Vec<String>; | ||
fn save(x: &str, stackset: &mut StackSet, stackmap: &mut StackMap) { | ||
stackset.insert(x.to_string()); | ||
if stackmap.iter().all(|y| x != y) { | ||
stackmap.push(x.to_string()); | ||
} | ||
} | ||
|
||
fn savef(x: &str, stackset: &mut StackSet, stackmap: &mut StackMap, id_gen: &mut IdGen) { | ||
stackset.insert(x.to_string()); | ||
if stackmap.iter().all(|y| x != y) { | ||
if stackmap.len() % 2 == 1 { | ||
stackmap.push(id_gen.gen_tmp(&Type::Int)); | ||
} | ||
stackmap.push(x.to_string()); | ||
stackmap.push(x.to_string()); | ||
} | ||
} | ||
|
||
fn offset(x: &str, stackmap: &StackMap) -> i32 { | ||
4 * stackmap.iter().position(|y| x == y).unwrap() as i32 | ||
} | ||
|
||
fn stacksize(stackmap: &StackMap) -> i32 { | ||
asm::align(4 * stackmap.len() as i32) | ||
} | ||
|
||
fn pp_id_or_imm(value: &IdOrImm) -> String { | ||
match value { | ||
IdOrImm::V(ref x) => x.clone(), | ||
IdOrImm::C(i) => format!("${}", i), | ||
} | ||
} | ||
|
||
/// 関数呼び出しのために引数を並べ替える(register shuffling) (caml2html: emit_shuffle) | ||
fn shuffle(sw: &str, xys: &[(String, String)]) -> Vec<(String, String)> { | ||
panic!(); | ||
} | ||
/* | ||
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 | ||
*/ | ||
|
||
/// 末尾かどうかを表すデータ型 (caml2html: emit_dest) | ||
enum Dest { | ||
Tail, | ||
NonTail(String), | ||
} | ||
|
||
fn g(output: &mut Write, asm: Asm) -> Result<(), std::io::Error> { | ||
panic!(); | ||
} | ||
/* | ||
let rec g oc = function (* 命令列のアセンブリ生成 (caml2html: emit_g) *) | ||
| dest, Ans(exp) -> g' oc (dest, exp) | ||
| dest, Let((x, t), exp, e) -> | ||
g' oc (NonTail(x), exp); | ||
g oc (dest, e) | ||
*/ | ||
fn g_exp(output: &mut Write, exp: Exp) -> Result<(), std::io::Error> { | ||
panic!(); | ||
} | ||
/* | ||
and g' oc = function (* 各命令のアセンブリ生成 (caml2html: emit_gprime) *) | ||
(* 末尾でなかったら計算結果をdestにセット (caml2html: emit_nontail) *) | ||
| NonTail(_), Nop -> () | ||
| NonTail(x), Set(i) -> Printf.fprintf oc "\tmovl\t$%d, %s\n" i x | ||
| NonTail(x), SetL(Id.L(y)) -> Printf.fprintf oc "\tmovl\t$%s, %s\n" y x | ||
| NonTail(x), Mov(y) -> | ||
if x <> y then Printf.fprintf oc "\tmovl\t%s, %s\n" y x | ||
| NonTail(x), Neg(y) -> | ||
if x <> y then Printf.fprintf oc "\tmovl\t%s, %s\n" y x; | ||
Printf.fprintf oc "\tnegl\t%s\n" x | ||
| NonTail(x), Add(y, z') -> | ||
if V(x) = z' then | ||
Printf.fprintf oc "\taddl\t%s, %s\n" y x | ||
else | ||
(if x <> y then Printf.fprintf oc "\tmovl\t%s, %s\n" y x; | ||
Printf.fprintf oc "\taddl\t%s, %s\n" (pp_id_or_imm z') x) | ||
| NonTail(x), Sub(y, z') -> | ||
if V(x) = z' then | ||
(Printf.fprintf oc "\tsubl\t%s, %s\n" y x; | ||
Printf.fprintf oc "\tnegl\t%s\n" x) | ||
else | ||
(if x <> y then Printf.fprintf oc "\tmovl\t%s, %s\n" y x; | ||
Printf.fprintf oc "\tsubl\t%s, %s\n" (pp_id_or_imm z') x) | ||
| NonTail(x), Ld(y, V(z), i) -> Printf.fprintf oc "\tmovl\t(%s,%s,%d), %s\n" y z i x | ||
| NonTail(x), Ld(y, C(j), i) -> Printf.fprintf oc "\tmovl\t%d(%s), %s\n" (j * i) y x | ||
| NonTail(_), St(x, y, V(z), i) -> Printf.fprintf oc "\tmovl\t%s, (%s,%s,%d)\n" x y z i | ||
| NonTail(_), St(x, y, C(j), i) -> Printf.fprintf oc "\tmovl\t%s, %d(%s)\n" x (j * i) y | ||
| NonTail(x), FMovD(y) -> | ||
if x <> y then Printf.fprintf oc "\tmovsd\t%s, %s\n" y x | ||
| NonTail(x), FNegD(y) -> | ||
if x <> y then Printf.fprintf oc "\tmovsd\t%s, %s\n" y x; | ||
Printf.fprintf oc "\txorpd\tmin_caml_fnegd, %s\n" x | ||
| NonTail(x), FAddD(y, z) -> | ||
if x = z then | ||
Printf.fprintf oc "\taddsd\t%s, %s\n" y x | ||
else | ||
(if x <> y then Printf.fprintf oc "\tmovsd\t%s, %s\n" y x; | ||
Printf.fprintf oc "\taddsd\t%s, %s\n" z x) | ||
| NonTail(x), FSubD(y, z) -> | ||
if x = z then (* [XXX] ugly *) | ||
let ss = stacksize () in | ||
Printf.fprintf oc "\tmovsd\t%s, %d(%s)\n" z ss reg_sp; | ||
if x <> y then Printf.fprintf oc "\tmovsd\t%s, %s\n" y x; | ||
Printf.fprintf oc "\tsubsd\t%d(%s), %s\n" ss reg_sp x | ||
else | ||
(if x <> y then Printf.fprintf oc "\tmovsd\t%s, %s\n" y x; | ||
Printf.fprintf oc "\tsubsd\t%s, %s\n" z x) | ||
| NonTail(x), FMulD(y, z) -> | ||
if x = z then | ||
Printf.fprintf oc "\tmulsd\t%s, %s\n" y x | ||
else | ||
(if x <> y then Printf.fprintf oc "\tmovsd\t%s, %s\n" y x; | ||
Printf.fprintf oc "\tmulsd\t%s, %s\n" z x) | ||
| NonTail(x), FDivD(y, z) -> | ||
if x = z then (* [XXX] ugly *) | ||
let ss = stacksize () in | ||
Printf.fprintf oc "\tmovsd\t%s, %d(%s)\n" z ss reg_sp; | ||
if x <> y then Printf.fprintf oc "\tmovsd\t%s, %s\n" y x; | ||
Printf.fprintf oc "\tdivsd\t%d(%s), %s\n" ss reg_sp x | ||
else | ||
(if x <> y then Printf.fprintf oc "\tmovsd\t%s, %s\n" y x; | ||
Printf.fprintf oc "\tdivsd\t%s, %s\n" z x) | ||
| NonTail(x), LdDF(y, V(z), i) -> Printf.fprintf oc "\tmovsd\t(%s,%s,%d), %s\n" y z i x | ||
| NonTail(x), LdDF(y, C(j), i) -> Printf.fprintf oc "\tmovsd\t%d(%s), %s\n" (j * i) y x | ||
| NonTail(_), StDF(x, y, V(z), i) -> Printf.fprintf oc "\tmovsd\t%s, (%s,%s,%d)\n" x y z i | ||
| NonTail(_), StDF(x, y, C(j), i) -> Printf.fprintf oc "\tmovsd\t%s, %d(%s)\n" x (j * i) y | ||
| NonTail(_), Comment(s) -> Printf.fprintf oc "\t# %s\n" s | ||
(* 退避の仮想命令の実装 (caml2html: emit_save) *) | ||
| NonTail(_), Save(x, y) when List.mem x allregs && not (S.mem y !stackset) -> | ||
save y; | ||
Printf.fprintf oc "\tmovl\t%s, %d(%s)\n" x (offset y) reg_sp | ||
| NonTail(_), Save(x, y) when List.mem x allfregs && not (S.mem y !stackset) -> | ||
savef y; | ||
Printf.fprintf oc "\tmovsd\t%s, %d(%s)\n" x (offset y) reg_sp | ||
| NonTail(_), Save(x, y) -> assert (S.mem y !stackset); () | ||
(* 復帰の仮想命令の実装 (caml2html: emit_restore) *) | ||
| NonTail(x), Restore(y) when List.mem x allregs -> | ||
Printf.fprintf oc "\tmovl\t%d(%s), %s\n" (offset y) reg_sp x | ||
| NonTail(x), Restore(y) -> | ||
assert (List.mem x allfregs); | ||
Printf.fprintf oc "\tmovsd\t%d(%s), %s\n" (offset y) reg_sp x | ||
(* 末尾だったら計算結果を第一レジスタにセットしてret (caml2html: emit_tailret) *) | ||
| Tail, (Nop | St _ | StDF _ | Comment _ | Save _ as exp) -> | ||
g' oc (NonTail(Id.gentmp Type.Unit), exp); | ||
Printf.fprintf oc "\tret\n"; | ||
| Tail, (Set _ | SetL _ | Mov _ | Neg _ | Add _ | Sub _ | Ld _ as exp) -> | ||
g' oc (NonTail(regs.(0)), exp); | ||
Printf.fprintf oc "\tret\n"; | ||
| Tail, (FMovD _ | FNegD _ | FAddD _ | FSubD _ | FMulD _ | FDivD _ | LdDF _ as exp) -> | ||
g' oc (NonTail(fregs.(0)), exp); | ||
Printf.fprintf oc "\tret\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 "\tret\n"; | ||
| Tail, IfEq(x, y', e1, e2) -> | ||
Printf.fprintf oc "\tcmpl\t%s, %s\n" (pp_id_or_imm y') x; | ||
g'_tail_if oc e1 e2 "je" "jne" | ||
| Tail, IfLE(x, y', e1, e2) -> | ||
Printf.fprintf oc "\tcmpl\t%s, %s\n" (pp_id_or_imm y') x; | ||
g'_tail_if oc e1 e2 "jle" "jg" | ||
| Tail, IfGE(x, y', e1, e2) -> | ||
Printf.fprintf oc "\tcmpl\t%s, %s\n" (pp_id_or_imm y') x; | ||
g'_tail_if oc e1 e2 "jge" "jl" | ||
| Tail, IfFEq(x, y, e1, e2) -> | ||
Printf.fprintf oc "\tcomisd\t%s, %s\n" y x; | ||
g'_tail_if oc e1 e2 "je" "jne" | ||
| Tail, IfFLE(x, y, e1, e2) -> | ||
Printf.fprintf oc "\tcomisd\t%s, %s\n" y x; | ||
g'_tail_if oc e1 e2 "jbe" "ja" | ||
| NonTail(z), IfEq(x, y', e1, e2) -> | ||
Printf.fprintf oc "\tcmpl\t%s, %s\n" (pp_id_or_imm y') x; | ||
g'_non_tail_if oc (NonTail(z)) e1 e2 "je" "jne" | ||
| NonTail(z), IfLE(x, y', e1, e2) -> | ||
Printf.fprintf oc "\tcmpl\t%s, %s\n" (pp_id_or_imm y') x; | ||
g'_non_tail_if oc (NonTail(z)) e1 e2 "jle" "jg" | ||
| NonTail(z), IfGE(x, y', e1, e2) -> | ||
Printf.fprintf oc "\tcmpl\t%s, %s\n" (pp_id_or_imm y') x; | ||
g'_non_tail_if oc (NonTail(z)) e1 e2 "jge" "jl" | ||
| NonTail(z), IfFEq(x, y, e1, e2) -> | ||
Printf.fprintf oc "\tcomisd\t%s, %s\n" y x; | ||
g'_non_tail_if oc (NonTail(z)) e1 e2 "je" "jne" | ||
| NonTail(z), IfFLE(x, y, e1, e2) -> | ||
Printf.fprintf oc "\tcomisd\t%s, %s\n" y x; | ||
g'_non_tail_if oc (NonTail(z)) e1 e2 "jbe" "ja" | ||
(* 関数呼び出しの仮想命令の実装 (caml2html: emit_call) *) | ||
| Tail, CallCls(x, ys, zs) -> (* 末尾呼び出し (caml2html: emit_tailcall) *) | ||
g'_args oc [(x, reg_cl)] ys zs; | ||
Printf.fprintf oc "\tjmp\t*(%s)\n" reg_cl; | ||
| Tail, CallDir(Id.L(x), ys, zs) -> (* 末尾呼び出し *) | ||
g'_args oc [] ys zs; | ||
Printf.fprintf oc "\tjmp\t%s\n" x; | ||
| NonTail(a), CallCls(x, ys, zs) -> | ||
g'_args oc [(x, reg_cl)] ys zs; | ||
let ss = stacksize () in | ||
if ss > 0 then Printf.fprintf oc "\taddl\t$%d, %s\n" ss reg_sp; | ||
Printf.fprintf oc "\tcall\t*(%s)\n" reg_cl; | ||
if ss > 0 then Printf.fprintf oc "\tsubl\t$%d, %s\n" ss reg_sp; | ||
if List.mem a allregs && a <> regs.(0) then | ||
Printf.fprintf oc "\tmovl\t%s, %s\n" regs.(0) a | ||
else if List.mem a allfregs && a <> fregs.(0) then | ||
Printf.fprintf oc "\tmovsd\t%s, %s\n" fregs.(0) a | ||
| NonTail(a), CallDir(Id.L(x), ys, zs) -> | ||
g'_args oc [] ys zs; | ||
let ss = stacksize () in | ||
if ss > 0 then Printf.fprintf oc "\taddl\t$%d, %s\n" ss reg_sp; | ||
Printf.fprintf oc "\tcall\t%s\n" x; | ||
if ss > 0 then Printf.fprintf oc "\tsubl\t$%d, %s\n" ss reg_sp; | ||
if List.mem a allregs && a <> regs.(0) then | ||
Printf.fprintf oc "\tmovl\t%s, %s\n" regs.(0) a | ||
else if List.mem a allfregs && a <> fregs.(0) then | ||
Printf.fprintf oc "\tmovsd\t%s, %s\n" fregs.(0) a | ||
*/ | ||
|
||
fn g_exp_tail_if( | ||
output: &mut Write, | ||
e1: Exp, | ||
e2: Exp, | ||
b: &str, | ||
bn: &str, | ||
) -> Result<(), std::io::Error> { | ||
panic!(); | ||
} | ||
/* | ||
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; | ||
let stackset_back = !stackset in | ||
g oc (Tail, e1); | ||
Printf.fprintf oc "%s:\n" b_else; | ||
stackset := stackset_back; | ||
g oc (Tail, e2) | ||
*/ | ||
fn g_exp_non_tail_if( | ||
output: &mut Write, | ||
dest: Dest, | ||
e1: Exp, | ||
e2: Exp, | ||
b: &str, | ||
bn: &str, | ||
) -> Result<(), std::io::Error> { | ||
panic!(); | ||
} | ||
/* | ||
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; | ||
let stackset_back = !stackset in | ||
g oc (dest, e1); | ||
let stackset1 = !stackset in | ||
Printf.fprintf oc "\tjmp\t%s\n" b_cont; | ||
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 | ||
*/ | ||
fn g_exp_args( | ||
output: &mut Write, | ||
x_reg_cl: String, | ||
ys: Vec<String>, | ||
zs: Vec<String>, | ||
) -> Result<(), std::io::Error> { | ||
panic!(); | ||
} | ||
/* | ||
and g'_args oc x_reg_cl ys zs = | ||
assert (List.length ys <= Array.length regs - List.length x_reg_cl); | ||
assert (List.length zs <= Array.length fregs); | ||
let sw = Printf.sprintf "%d(%s)" (stacksize ()) reg_sp in | ||
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 "\tmovl\t%s, %s\n" y r) | ||
(shuffle 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 "\tmovsd\t%s, %s\n" z fr) | ||
(shuffle sw zfrs) | ||
*/ | ||
|
||
fn h( | ||
output: &mut Write, | ||
Fundef { | ||
name: id::L(x), | ||
args: ys, | ||
fargs: zs, | ||
body: e, | ||
ret: t, | ||
}: Fundef, | ||
id_gen: &mut IdGen, | ||
) -> Result<(), std::io::Error> { | ||
panic!(); | ||
} | ||
/* | ||
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) | ||
*/ | ||
|
||
pub fn f( | ||
output: &mut Write, | ||
Prog(data, fundefs, e): Prog, | ||
id_gen: &mut IdGen, | ||
) -> Result<(), std::io::Error> { | ||
panic!(); | ||
} | ||
/* | ||
let f oc (Prog(data, fundefs, e)) = | ||
Format.eprintf "generating assembly...@."; | ||
Printf.fprintf oc ".data\n"; | ||
Printf.fprintf oc ".balign\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 ".text\n"; | ||
List.iter (fun fundef -> h oc fundef) fundefs; | ||
Printf.fprintf oc ".globl\tmin_caml_start\n"; | ||
Printf.fprintf oc "min_caml_start:\n"; | ||
Printf.fprintf oc ".globl\t_min_caml_start\n"; | ||
Printf.fprintf oc "_min_caml_start: # for cygwin\n"; | ||
Printf.fprintf oc "\tpushl\t%%eax\n"; | ||
Printf.fprintf oc "\tpushl\t%%ebx\n"; | ||
Printf.fprintf oc "\tpushl\t%%ecx\n"; | ||
Printf.fprintf oc "\tpushl\t%%edx\n"; | ||
Printf.fprintf oc "\tpushl\t%%esi\n"; | ||
Printf.fprintf oc "\tpushl\t%%edi\n"; | ||
Printf.fprintf oc "\tpushl\t%%ebp\n"; | ||
Printf.fprintf oc "\tmovl\t32(%%esp),%s\n" reg_sp; | ||
Printf.fprintf oc "\tmovl\t36(%%esp),%s\n" regs.(0); | ||
Printf.fprintf oc "\tmovl\t%s,%s\n" regs.(0) reg_hp; | ||
stackset := S.empty; | ||
stackmap := []; | ||
g oc (NonTail(regs.(0)), e); | ||
Printf.fprintf oc "\tpopl\t%%ebp\n"; | ||
Printf.fprintf oc "\tpopl\t%%edi\n"; | ||
Printf.fprintf oc "\tpopl\t%%esi\n"; | ||
Printf.fprintf oc "\tpopl\t%%edx\n"; | ||
Printf.fprintf oc "\tpopl\t%%ecx\n"; | ||
Printf.fprintf oc "\tpopl\t%%ebx\n"; | ||
Printf.fprintf oc "\tpopl\t%%eax\n"; | ||
Printf.fprintf oc "\tret\n"; | ||
*/ |
Oops, something went wrong.