diff options
Diffstat (limited to 'src/codegen.ml')
-rw-r--r-- | src/codegen.ml | 135 |
1 files changed, 76 insertions, 59 deletions
diff --git a/src/codegen.ml b/src/codegen.ml index 316caa6..b1501fd 100644 --- a/src/codegen.ml +++ b/src/codegen.ml @@ -12,7 +12,6 @@ type whereis_var = type cg_env = { c_penv : env; c_names : whereis_var Smap.t; - c_ret_lbl : string; c_ret_ref : bool; c_fp_used : int; } @@ -36,7 +35,7 @@ let rec gen_expr env e = match e.te_desc with | TEInt(k) -> li a0 k, false | TENull -> move a0 zero, false | TEThis -> (* convention : this is always the last-pushed argument *) - la a0 areg (8, fp), false + lw a0 areg (8, fp), false | TEIdent(i) -> begin match Smap.find i env.c_names with | VGlobal -> la a0 alab i, true @@ -55,7 +54,7 @@ let rec gen_expr env e = match e.te_desc with assert (r || not byref); c ++ cr (r && not byref) ++ push a0 ++ code) nop args in code ++ jal id ++ popn (4 * (List.length args)), b - | TECallVirtual(obj, ti, fi, args, b) -> + | TECallVirtual(obj, fi, args, b) -> let code = List.fold_left (fun code (arg, byref) -> let c, r = gen_expr env arg in @@ -63,15 +62,15 @@ let rec gen_expr env e = match e.te_desc with c ++ cr (r && not byref) ++ push a0 ++ code) nop args in let code2, a = gen_expr env obj in assert a; - code ++ code2 ++ push a0 ++ lw a0 areg (ti, a0) ++ lw a0 areg (fi, a0) + code ++ code2 ++ push a0 ++ lw a0 areg (0, a0) ++ lw a0 areg (fi, a0) ++ jalr a0 ++ popn (4 * (1 + List.length args)), b | TEUnary (x, e) -> let t, a = gen_expr env e in begin match x with | Ast.Deref -> t ++ cr a, true | Ast.Ref -> assert a; t, false - | Ast.Plus -> t, a - | Ast.Minus -> t ++ cr a ++ sub a0 zero oreg a0, false + | Ast.Plus -> t ++ cr a, false + | Ast.Minus -> t ++ cr a ++ neg a0 a0, false | Ast.Not -> t ++ cr a ++ not_ a0 a0, false | Ast.PreIncr -> assert a; t ++ lw a1 areg (0, a0) ++ add a1 a1 oi 1 ++ sw a1 areg (0, a0), true | Ast.PreDecr -> assert a; t ++ lw a1 areg (0, a0) ++ sub a1 a1 oi 1 ++ sw a1 areg (0, a0), true @@ -100,10 +99,10 @@ let rec gen_expr env e = match e.te_desc with | Ast.Ge -> t1 ++ push a0 ++ t2 ++ pop a1 ++ sge a0 a1 a0 | Ast.Land -> let lazy_lbl = id "_lazy" in - t1 ++ beqz a0 lazy_lbl ++ t2 ++ label lazy_lbl + t1 ++ beqz a0 lazy_lbl ++ t2 ++ label lazy_lbl ++ sne a0 a0 zero | Ast.Lor -> let lazy_lbl = id "_lazy" in - t1 ++ bnez a0 lazy_lbl ++ t2 ++ label lazy_lbl + t1 ++ bnez a0 lazy_lbl ++ t2 ++ label lazy_lbl ++ sne a0 a0 zero ), false | TEMember(e, i) -> let c, a = gen_expr env e in @@ -112,20 +111,18 @@ let rec gen_expr env e = match e.te_desc with c ++ la a0 areg (i, a0), true end else c, a + | TEPointerCast(e, i) -> + let c, a = gen_expr env e in + c ++ cr a ++ (if i = 0 then nop else la a0 areg (i, a0)), false | TENew(cls, constr, args) -> - let alloc = - li v0 9 ++ li a0 cls.tc_size ++ syscall in - begin match constr with - | None -> alloc ++ (jal ("_c_" ^ cls.tc_name)), false - | Some x -> - let args_code = List.fold_left - (fun code (arg, byref) -> - let c, r = gen_expr env arg in - assert (r || not byref); - c ++ cr (r && not byref) ++ push a0 ++ code) nop args in - let c = args_code ++ alloc ++ push v0 ++ jal x in - c ++ pop a0 ++ popn (4 * List.length args), false - end + let args_code = List.fold_left + (fun code (arg, byref) -> + let c, r = gen_expr env arg in + assert (r || not byref); + c ++ cr (r && not byref) ++ push a0 ++ code) nop args in + let alloc = li v0 9 ++ li a0 cls.tc_size ++ syscall in + args_code ++ alloc ++ push v0 ++ jal constr + ++ pop a0 ++ popn (4 * List.length args), false let rec gen_stmt env = function @@ -134,8 +131,8 @@ let rec gen_stmt env = function comment "expr" ++ (fst (gen_expr env e)), nop, env | TSIf(cond, s1, s2) -> let c, a = gen_expr env cond in - let l_else = id "_cond" in - let l_end = id "_cond" in + let l_else = id "_cond_then" in + let l_end = id "_cond_end" in let c_then, d_then, _ = gen_stmt env s1 in let c_else, d_else, _ = gen_stmt env s2 in comment "if" ++ c ++ cr a ++ beqz a0 l_else ++ c_then ++ b l_end ++ @@ -165,46 +162,45 @@ let rec gen_stmt env = function let c, d = gen_block env b in comment "block" ++ c, d, env | TSReturn (None) -> - comment "return" ++ b env.c_ret_lbl, nop, env + comment "return" ++ b "_return", nop, env | TSReturn (Some e) -> let c, a = gen_expr env e in assert (a || not env.c_ret_ref); - comment "return" ++ c ++ cr (not env.c_ret_ref && a) ++ b env.c_ret_lbl, nop, env + comment "return" ++ c ++ cr (not env.c_ret_ref && a) ++ b "_return", nop, env | TSDeclare (ty, id) -> let s = type_size env.c_penv ty in let new_fp_used = env.c_fp_used + s in let pos = - new_fp_used in let code = match ty with | TClass(i) -> + let c = get_c env.c_penv i in + let cproto = List.find (fun p -> p.tp_ret_type = None && p.tp_name = i && p.tp_args = []) c.tc_methods in sub sp sp oi s ++ - la v0 areg (pos, fp) ++ - jal ("_c_" ^ i) + la a0 areg (pos, fp) ++ + push a0 ++ + jal cproto.tp_unique_ident | _ -> push zero in comment ("declare " ^ id) ++ code, nop, { c_penv = env.c_penv; c_names = Smap.add id (VStack pos) env.c_names; - c_ret_lbl = env.c_ret_lbl; c_ret_ref = env.c_ret_ref; c_fp_used = new_fp_used } | TSDeclareAssignConstructor(cls, id, constr, args) -> let new_fp_used = env.c_fp_used + cls.tc_size in let pos = - new_fp_used in - let code = match constr with - | None -> sub sp sp oi cls.tc_size ++ move v0 sp ++ (jal ("_c_" ^ cls.tc_name)) - | Some x -> + let code = let args_code = List.fold_left (fun code (arg, byref) -> let c, r = gen_expr env arg in assert (r || not byref); c ++ cr (r && not byref) ++ push a0 ++ code) nop args in - sub sp sp oi cls.tc_size ++ args_code ++ la a0 areg(pos, fp) ++ push a0 ++ jal x ++ + sub sp sp oi cls.tc_size ++ args_code ++ la a0 areg(pos, fp) ++ push a0 ++ jal constr ++ popn (4 * (List.length args + 1)) in comment ("declare " ^ id) ++ code, nop, { c_penv = env.c_penv; c_names = Smap.add id (VStack pos) env.c_names; - c_ret_lbl = env.c_ret_lbl; c_ret_ref = env.c_ret_ref; c_fp_used = new_fp_used; } | TSDeclareAssignExpr ((ty, r), id, e) -> @@ -214,10 +210,9 @@ let rec gen_stmt env = function let pos = - new_fp_used in let code, a = gen_expr env e in assert (a || not r); - comment ("declare " ^ id) ++ code ++ cr (a && not r) ++ push a0, nop, { + comment ("declare " ^ id) ++ sub sp sp oi 4 ++ code ++ cr (a && not r) ++ sw a0 areg (pos, fp), nop, { c_penv = env.c_penv; c_names = Smap.add id (if r then VStackByRef pos else VStack pos) env.c_names; - c_ret_lbl = env.c_ret_lbl; c_ret_ref = env.c_ret_ref; c_fp_used = new_fp_used } | TSWriteCout(sl) -> @@ -260,50 +255,71 @@ let gen_decl tenv decl = match decl with let env = { c_penv = tenv; c_names = names; - c_ret_lbl = id "_ret"; c_ret_ref = (match proto.tp_ret_type with | None -> false | Some(_, r) -> r); c_fp_used = 0; } in let code_for_constructor = match proto.tp_ret_type with | Some _ -> nop | None -> let cls_name = (match proto.tp_class with | Some k -> k | None -> assert false) in - la v0 areg (8, fp) ++ jal ("_c_" ^ cls_name) + lw v0 areg (8, fp) ++ jal ("_c_" ^ cls_name) in + let code_for_virtual = match proto.tp_virtual with + | Some (c, _) when c.h_pos <> 0 -> + lw a0 areg (8, fp) ++ la a0 areg (-c.h_pos, a0) ++ sw a0 areg (8, fp) + | _ -> nop in let text, data = gen_block env block in label proto.tp_unique_ident ++ - push fp ++ push ra ++ move fp sp ++ code_for_constructor ++ - text ++ label env.c_ret_lbl ++ - move sp fp ++ pop ra ++ pop fp ++ jr ra, - data + push fp ++ push ra ++ move fp sp ++ code_for_constructor ++ code_for_virtual ++ + text ++ b "_return", data | TDClass(c) -> + (* Call default constructor of parent classes *) + let code_parents = List.fold_left + (fun code parent -> + let cn = parent.h_class in + let c = get_c tenv cn in + let proto = List.find (fun p -> p.tp_ret_type = None && p.tp_args = [] && p.tp_name = cn) c.tc_methods in + code ++ lw v0 areg(0, sp) ++ la v0 areg(parent.h_pos, v0) ++push v0 ++ jal proto.tp_unique_ident ++ popn 4) + nop c.tc_hier.h_supers in + let code_parents = if code_parents <> nop then push v0 ++ code_parents ++ pop v0 else nop in (* Build vtables and build constructor *) - let rec mk_cls_code hh = + let rec make_vtables hh = + (* calculate vtable contents *) let vtable_size = List.fold_left (fun k (p, _) -> max k (p+4)) 0 hh.h_vtable in let vtable_as_array = Array.make (vtable_size / 4) "_nothing" in List.iter (fun (p, s) -> vtable_as_array.(p/4) <- s.tp_unique_ident) hh.h_vtable; let vt_l = Array.to_list vtable_as_array in - let vtable = label ("_vt_" ^ c.tc_name ^ "_as_" ^ hh.h_class) ++ - (if vt_l = [] then nop else address vt_l) in - let constructor_code = la a0 alab ("_vt_" ^ c.tc_name ^ "_as_" ^ hh.h_class) + (* code for vtable initialization *) + let vtable = + if vt_l = [] + then nop + else label ("_vt_" ^ c.tc_name ^ "_as_" ^ hh.h_class) ++ address vt_l in + let constructor_code = + if vt_l = [] + then sw zero areg (hh.h_pos, v0) + else la a0 alab ("_vt_" ^ c.tc_name ^ "_as_" ^ hh.h_class) ++ sw a0 areg (hh.h_pos, v0) in - let c = get_c tenv hh.h_class in - let init_code = Smap.fold - (fun _ (ty, pos) code -> - (match ty with - | TClass(s) -> - push ra ++ push v0 ++ - la v0 areg (pos + hh.h_pos, v0) ++ - jal ("_c_" ^ s) ++ pop v0 ++ pop ra - | _ -> sw zero areg (pos + hh.h_pos, v0) - ) ++ code) c.tc_members nop in + (* code for subclasses initialization *) List.fold_left (fun (vt, cc) sup -> - let mvt, mcc = mk_cls_code sup in + let mvt, mcc = make_vtables sup in vt ++ mvt, cc ++ mcc) - (vtable, constructor_code ++ init_code) hh.h_supers + (vtable, constructor_code) hh.h_supers + in + let vtables, vtable_init_code = make_vtables c.tc_hier in + let init_code_proper = Smap.fold + (fun _ (ty, pos) code -> + (match ty with + | TClass(s) -> + let cs = get_c tenv s in + let proto = List.find (fun p -> p.tp_ret_type = None && p.tp_args = [] && p.tp_name = s) cs.tc_methods in + push v0 ++ + la a0 areg (pos, v0) ++ push a0 ++ + jal proto.tp_unique_ident ++ popn 4 ++ pop v0 + | _ -> sw zero areg (pos, v0) + ) ++ code) c.tc_members nop in - let vt, cc = mk_cls_code c.tc_hier in - label ("_c_" ^ c.tc_name) ++ cc ++ jr ra, vt + label (c.tc_name ^ "0") ++ lw v0 areg (0, sp) ++ label ("_c_" ^ c.tc_name) + ++ push ra ++ code_parents ++ vtable_init_code ++ init_code_proper ++ pop ra ++ jr ra, vtables let generate p = @@ -314,6 +330,7 @@ let generate p = let text = label "main" ++ jal p.prog_main ++ li v0 10 ++ syscall ++ + label "_return" ++ move sp fp ++ pop ra ++ pop fp ++ label "_nothing" ++ jr ra ++ text in { text = text; |