summaryrefslogtreecommitdiff
path: root/src/c_backend.ml
diff options
context:
space:
mode:
authorAlasdair Armstrong2018-07-24 18:16:53 +0100
committerAlasdair Armstrong2018-07-24 18:16:53 +0100
commit7cb3aa7b82423f1744d1006fc7c076aa2fcaf15a (patch)
tree3c9a607b9e0b2fce55cbd0a84475614e3d3d35cd /src/c_backend.ml
parent8b1bbeed703da7ba78dfe2728c99b0ec9088cf47 (diff)
parent6b4f407ad34ca7d4d8a89a5a4d401ac80c7413b0 (diff)
Merge branch 'c_fixes' into sail2
Diffstat (limited to 'src/c_backend.ml')
-rw-r--r--src/c_backend.ml802
1 files changed, 436 insertions, 366 deletions
diff --git a/src/c_backend.ml b/src/c_backend.ml
index cb732e2d..433e3d85 100644
--- a/src/c_backend.ml
+++ b/src/c_backend.ml
@@ -67,7 +67,6 @@ let opt_static = ref false
(* Optimization flags *)
let optimize_primops = ref false
-let optimize_z3 = ref false
let optimize_hoist_allocations = ref false
let optimize_struct_updates = ref false
@@ -94,9 +93,11 @@ type ctx =
variants : (ctyp Bindings.t) Bindings.t;
tc_env : Env.t;
local_env : Env.t;
+ locals : (mut * ctyp) Bindings.t;
letbinds : int list;
recursive_functions : IdSet.t;
no_raw : bool;
+ optimize_z3 : bool;
}
let initial_ctx env =
@@ -105,9 +106,11 @@ let initial_ctx env =
variants = Bindings.empty;
tc_env = env;
local_env = env;
+ locals = Bindings.empty;
letbinds = [];
recursive_functions = IdSet.empty;
no_raw = false;
+ optimize_z3 = true;
}
let rec ctyp_equal ctyp1 ctyp2 =
@@ -148,12 +151,11 @@ let rec ctyp_of_typ ctx typ =
| Nexp_aux (Nexp_constant n, _), Nexp_aux (Nexp_constant m, _)
when Big_int.less_equal min_int64 n && Big_int.less_equal m max_int64 ->
CT_int64
- | n, m when !optimize_z3 ->
- prerr_endline ("optimize atom " ^ string_of_nexp n ^ ", " ^ string_of_nexp m ^ " in context " ^ (Util.string_of_list ", " string_of_n_constraint (Env.get_constraints ctx.local_env)));
+ | n, m when ctx.optimize_z3 ->
if prove ctx.local_env (nc_lteq (nconstant min_int64) n) && prove ctx.local_env (nc_lteq m (nconstant max_int64)) then
- (prerr_endline "yes"; CT_int64)
+ CT_int64
else
- (prerr_endline "no"; CT_int)
+ CT_int
| _ -> CT_int
end
@@ -168,7 +170,13 @@ let rec ctyp_of_typ ctx typ =
let direction = match ord with Ord_aux (Ord_dec, _) -> true | Ord_aux (Ord_inc, _) -> false | _ -> assert false in
match nexp_simp n with
| Nexp_aux (Nexp_constant n, _) when Big_int.less_equal n (Big_int.of_int 64) -> CT_bits64 (Big_int.to_int n, direction)
+ | _ when not ctx.optimize_z3 -> CT_bits direction
| _ -> CT_bits direction
+ (* This is extremely slow :(
+ match solve ctx.local_env n with
+ | Some n when Big_int.less_equal n (Big_int.of_int 64) -> CT_bits64 (Big_int.to_int n, direction)
+ | _ -> CT_bits direction
+ *)
end
| Typ_app (id, [Typ_arg_aux (Typ_arg_nexp n, _);
Typ_arg_aux (Typ_arg_order ord, _);
@@ -190,13 +198,11 @@ let rec ctyp_of_typ ctx typ =
| Typ_tup typs -> CT_tup (List.map (ctyp_of_typ ctx) typs)
- | Typ_exist _ when !optimize_z3 ->
+ | Typ_exist _ when ctx.optimize_z3 ->
(* Use Type_check.destruct_exist when optimising with z3, to ensure that we
don't cause any type variable clashes in local_env. *)
begin match destruct_exist ctx.local_env typ with
| Some (kids, nc, typ) ->
- c_debug (lazy ("optimize existential: " ^ string_of_n_constraint nc ^ ". " ^ string_of_typ typ
- ^ " in context " ^ (Util.string_of_list ", " string_of_n_constraint (Env.get_constraints ctx.local_env))));
let env = add_existential l kids nc ctx.local_env in
ctyp_of_typ { ctx with local_env = env } typ
| None -> c_error "Existential cannot be destructured. This should be impossible!"
@@ -298,12 +304,24 @@ let rec c_aval ctx = function
| None -> v
end
| AV_C_fragment (str, typ) -> AV_C_fragment (str, typ)
- (* An id can be converted to a C fragment if it's type can be stack-allocated. *)
+ (* An id can be converted to a C fragment if it's type can be
+ stack-allocated. *)
| AV_id (id, lvar) as v ->
begin
match lvar with
| Local (_, typ) when is_stack_typ ctx typ ->
- AV_C_fragment (F_id id, typ)
+ begin
+ try
+ (* We need to check that id's type hasn't changed due to flow typing *)
+ let _, ctyp = Bindings.find id ctx.locals in
+ if is_stack_ctyp ctyp then
+ AV_C_fragment (F_id id, typ)
+ else
+ (prerr_endline (string_of_id id ^ " : " ^ string_of_ctyp ctyp ^ " -> " ^ string_of_ctyp (ctyp_of_typ ctx typ));
+ v) (* id's type went from heap -> stack due to flow typing, so it's really still heap allocated! *)
+ with
+ Not_found -> failwith ("could not find " ^ string_of_id id ^ " in local variables")
+ end
| Register (_, _, typ) when is_stack_typ ctx typ ->
AV_C_fragment (F_id id, typ)
| _ -> v
@@ -324,16 +342,65 @@ let c_fragment = function
let v_mask_lower i = F_lit (V_bits (Util.list_init i (fun _ -> Sail2_values.B1)))
-let analyze_primop' ctx env l id args typ =
+(* Map over all the functions in an aexp. *)
+let rec analyze_functions ctx f (AE_aux (aexp, env, l)) =
let ctx = { ctx with local_env = env } in
+ let aexp = match aexp with
+ | AE_app (id, vs, typ) -> f ctx id vs typ
+
+ | AE_cast (aexp, typ) -> AE_cast (analyze_functions ctx f aexp, typ)
+
+ | AE_assign (id, typ, aexp) -> AE_assign (id, typ, analyze_functions ctx f aexp)
+
+ | AE_short_circuit (op, aval, aexp) -> AE_short_circuit (op, aval, analyze_functions ctx f aexp)
+
+ | AE_let (mut, id, typ1, aexp1, aexp2, typ2) ->
+ let aexp1 = analyze_functions ctx f aexp1 in
+ let ctyp1 = ctyp_of_typ ctx typ1 in
+ let ctx = { ctx with locals = Bindings.add id (mut, ctyp1) ctx.locals } in
+ AE_let (mut, id, typ1, aexp1, analyze_functions ctx f aexp2, typ2)
+
+ | AE_block (aexps, aexp, typ) -> AE_block (List.map (analyze_functions ctx f) aexps, analyze_functions ctx f aexp, typ)
+
+ | AE_if (aval, aexp1, aexp2, typ) ->
+ AE_if (aval, analyze_functions ctx f aexp1, analyze_functions ctx f aexp2, typ)
+
+ | AE_loop (loop_typ, aexp1, aexp2) -> AE_loop (loop_typ, analyze_functions ctx f aexp1, analyze_functions ctx f aexp2)
+
+ | AE_for (id, aexp1, aexp2, aexp3, order, aexp4) ->
+ let aexp1 = analyze_functions ctx f aexp1 in
+ let aexp2 = analyze_functions ctx f aexp2 in
+ let aexp3 = analyze_functions ctx f aexp3 in
+ let aexp4 = analyze_functions ctx f aexp4 in
+ AE_for (id, aexp1, aexp2, aexp3, order, aexp4)
+
+ | AE_case (aval, cases, typ) ->
+ let analyze_case (pat, aexp1, aexp2) =
+ let pat_bindings = Bindings.bindings (apat_types pat) in
+ let ctx =
+ List.fold_left (fun ctx (id, typ) -> { ctx with locals = Bindings.add id (Immutable, ctyp_of_typ ctx typ) ctx.locals }) ctx pat_bindings
+ in
+ pat, analyze_functions ctx f aexp1, analyze_functions ctx f aexp2
+ in
+ AE_case (aval, List.map analyze_case cases, typ)
+
+ | AE_try (aexp, cases, typ) ->
+ AE_try (analyze_functions ctx f aexp, List.map (fun (pat, aexp1, aexp2) -> pat, analyze_functions ctx f aexp1, analyze_functions ctx f aexp2) cases, typ)
+
+ | AE_field _ | AE_record_update _ | AE_val _ | AE_return _ | AE_throw _ as v -> v
+ in
+ AE_aux (aexp, env, l)
+
+let analyze_primop' ctx id args typ =
let no_change = AE_app (id, args, typ) in
let args = List.map (c_aval ctx) args in
let extern = if Env.is_extern id ctx.tc_env "c" then Env.get_extern id ctx.tc_env "c" else failwith "Not extern" in
- (* prerr_endline ("Analysing: " ^ string_of_typ typ ^ " " ^ extern ^ Pretty_print_sail.to_string (separate_map (string ", ") pp_aval args)); *)
let v_one = F_lit (V_int (Big_int.of_int 1)) in
let v_int n = F_lit (V_int (Big_int.of_int n)) in
+ c_debug (lazy ("Analyzing primop " ^ extern ^ "(" ^ Util.string_of_list ", " (fun aval -> Pretty_print_sail.to_string (pp_aval aval)) args ^ ")"));
+
match extern, args with
| "eq_bits", [AV_C_fragment (v1, typ1); AV_C_fragment (v2, typ2)] ->
AE_val (AV_C_fragment (F_op (v1, "==", v2), typ))
@@ -352,6 +419,9 @@ let analyze_primop' ctx env l id args typ =
| _ -> no_change
end
+ | "gteq", [AV_C_fragment (v1, _); AV_C_fragment (v2, _)] ->
+ AE_val (AV_C_fragment (F_op (v1, ">=", v2), typ))
+
| "xor_bits", [AV_C_fragment (v1, typ1); AV_C_fragment (v2, typ2)] ->
AE_val (AV_C_fragment (F_op (v1, "^", v2), typ))
@@ -369,7 +439,7 @@ let analyze_primop' ctx env l id args typ =
| _ -> no_change
end
- | "vector_subrange", [AV_C_fragment (vec, _); AV_C_fragment (f, _); AV_C_fragment (t, _)] ->
+ | "vector_subrange", [AV_C_fragment (vec, _); AV_C_fragment (f, _); AV_C_fragment (t, _)] when is_stack_typ ctx typ ->
let len = F_op (f, "-", F_op (t, "-", v_one)) in
AE_val (AV_C_fragment (F_op (F_call ("safe_rshift", [F_raw "UINT64_MAX"; F_op (v_int 64, "-", len)]), "&", F_op (vec, ">>", t)), typ))
@@ -413,13 +483,17 @@ let analyze_primop' ctx env l id args typ =
| "undefined_bool", _ ->
AE_val (AV_C_fragment (F_lit (V_bool false), typ))
- | _, _ -> no_change
+ | _, _ ->
+ c_debug (lazy ("No optimization routine found"));
+ no_change
-let analyze_primop ctx env l id args typ =
+let analyze_primop ctx id args typ =
let no_change = AE_app (id, args, typ) in
if !optimize_primops then
- try analyze_primop' ctx env l id args typ with
- | Failure _ -> no_change
+ try analyze_primop' ctx id args typ with
+ | Failure str ->
+ (c_debug (lazy ("Analyze primop failed for id " ^ string_of_id id ^ " reason: " ^ str)));
+ no_change
else
no_change
@@ -456,15 +530,23 @@ let ctype_def_ctyps = function
let cval_ctyp = function (_, ctyp) -> ctyp
+let clexp_ctyp = function
+ | CL_id (_, ctyp) -> ctyp
+ | CL_field (_, _, ctyp) -> ctyp
+ | CL_addr (_, ctyp) -> ctyp
+ | CL_addr_field (_, _, ctyp) -> ctyp
+ | CL_have_exception -> CT_bool
+ | CL_current_exception ctyp -> ctyp
+
let rec map_instrs f (I_aux (instr, aux)) =
let instr = match instr with
| I_decl _ | I_init _ | I_reset _ | I_reinit _ -> instr
| I_if (cval, instrs1, instrs2, ctyp) ->
I_if (cval, f (List.map (map_instrs f) instrs1), f (List.map (map_instrs f) instrs2), ctyp)
- | I_funcall _ | I_convert _ | I_copy _ | I_clear _ | I_jump _ | I_throw _ | I_return _ -> instr
+ | I_funcall _ | I_copy _ | I_clear _ | I_jump _ | I_throw _ | I_return _ -> instr
| I_block instrs -> I_block (f (List.map (map_instrs f) instrs))
| I_try_block instrs -> I_try_block (f (List.map (map_instrs f) instrs))
- | I_comment _ | I_label _ | I_goto _ | I_raw _ | I_match_failure -> instr
+ | I_comment _ | I_label _ | I_goto _ | I_raw _ | I_match_failure | I_undefined _ -> instr
in
I_aux (instr, aux)
@@ -472,14 +554,13 @@ let cval_rename from_id to_id (frag, ctyp) = (frag_rename from_id to_id frag, ct
let rec instr_ctyps (I_aux (instr, aux)) =
match instr with
- | I_decl (ctyp, _) | I_reset (ctyp, _) | I_clear (ctyp, _) -> [ctyp]
+ | I_decl (ctyp, _) | I_reset (ctyp, _) | I_clear (ctyp, _) | I_undefined ctyp -> [ctyp]
| I_init (ctyp, _, cval) | I_reinit (ctyp, _, cval) -> [ctyp; cval_ctyp cval]
| I_if (cval, instrs1, instrs2, ctyp) ->
ctyp :: cval_ctyp cval :: List.concat (List.map instr_ctyps instrs1 @ List.map instr_ctyps instrs2)
- | I_funcall (_, _, _, cvals, ctyp) ->
- ctyp :: List.map cval_ctyp cvals
- | I_convert (_, ctyp1, _, ctyp2) -> [ctyp1; ctyp2]
- | I_copy (_, cval) -> [cval_ctyp cval]
+ | I_funcall (clexp, _, _, cvals) ->
+ clexp_ctyp clexp :: List.map cval_ctyp cvals
+ | I_copy (clexp, cval) -> [clexp_ctyp clexp; cval_ctyp cval]
| I_block instrs | I_try_block instrs -> List.concat (List.map instr_ctyps instrs)
| I_throw cval | I_jump (cval, _) | I_return cval -> [cval_ctyp cval]
| I_comment _ | I_label _ | I_goto _ | I_raw _ | I_match_failure -> []
@@ -546,7 +627,14 @@ let rec compile_aval ctx = function
[], (frag, ctyp_of_typ ctx typ), []
| AV_id (id, typ) ->
- [], (F_id id, ctyp_of_typ ctx (lvar_typ typ)), []
+ begin
+ try
+ let _, ctyp = Bindings.find id ctx.locals in
+ [], (F_id id, ctyp), []
+ with
+ | Not_found ->
+ [], (F_id id, ctyp_of_typ ctx (lvar_typ typ)), []
+ end
| AV_ref (id, typ) ->
[], (F_ref id, CT_ref (ctyp_of_typ ctx (lvar_typ typ))), []
@@ -590,7 +678,7 @@ let rec compile_aval ctx = function
let gs = gensym () in
setup
@ [idecl tup_ctyp gs]
- @ List.mapi (fun n cval -> icopy (CL_field (gs, "tup" ^ string_of_int n)) cval) cvals,
+ @ List.mapi (fun n cval -> icopy (CL_field (gs, "tup" ^ string_of_int n, cval_ctyp cval)) cval) cvals,
(F_id gs, CT_tup (List.map cval_ctyp cvals)),
[iclear tup_ctyp gs]
@ cleanup
@@ -601,7 +689,7 @@ let rec compile_aval ctx = function
let compile_fields (id, aval) =
let field_setup, cval, field_cleanup = compile_aval ctx aval in
field_setup
- @ [icopy (CL_field (gs, string_of_id id)) cval]
+ @ [icopy (CL_field (gs, string_of_id id, cval_ctyp cval)) cval]
@ field_cleanup
in
[idecl ctyp gs]
@@ -637,10 +725,9 @@ let rec compile_aval ctx = function
let chunks = Util.drop (len mod 64) avals |> chunkify 64 |> List.map bitstring in
let gs = gensym () in
[iinit (CT_bits true) gs (first_chunk, CT_bits64 (len mod 64, true))]
- @ List.map (fun chunk -> ifuncall (CL_id gs)
+ @ List.map (fun chunk -> ifuncall (CL_id (gs, CT_bits true))
(mk_id "append_64")
- [(F_id gs, CT_bits true); (chunk, CT_bits64 (64, true))]
- (CT_bits true)) chunks,
+ [(F_id gs, CT_bits true); (chunk, CT_bits64 (64, true))]) chunks,
(F_id gs, CT_bits true),
[iclear (CT_bits true) gs]
@@ -661,12 +748,12 @@ let rec compile_aval ctx = function
match cval with
| (F_lit (V_bit Sail2_values.B0), _) -> []
| (F_lit (V_bit Sail2_values.B1), _) ->
- [icopy (CL_id gs) (F_op (F_id gs, "|", F_lit (mask i)), ctyp)]
+ [icopy (CL_id (gs, ctyp)) (F_op (F_id gs, "|", F_lit (mask i)), ctyp)]
| _ ->
- setup @ [iif cval [icopy (CL_id gs) (F_op (F_id gs, "|", F_lit (mask i)), ctyp)] [] CT_unit] @ cleanup
+ setup @ [iif cval [icopy (CL_id (gs, ctyp)) (F_op (F_id gs, "|", F_lit (mask i)), ctyp)] [] CT_unit] @ cleanup
in
[idecl ctyp gs;
- icopy (CL_id gs) (F_lit (V_bits (Util.list_init 64 (fun _ -> Sail2_values.B0))), ctyp)]
+ icopy (CL_id (gs, ctyp)) (F_lit (V_bits (Util.list_init 64 (fun _ -> Sail2_values.B0))), ctyp)]
@ List.concat (List.mapi aval_mask (List.rev avals)),
(F_id gs, ctyp),
[]
@@ -685,13 +772,13 @@ let rec compile_aval ctx = function
let aval_set i aval =
let setup, cval, cleanup = compile_aval ctx aval in
setup
- @ [iextern (CL_id gs)
+ @ [iextern (CL_id (gs, vector_ctyp))
(mk_id "internal_vector_update")
- [(F_id gs, vector_ctyp); (F_lit (V_int (Big_int.of_int i)), CT_int64); cval] vector_ctyp]
+ [(F_id gs, vector_ctyp); (F_lit (V_int (Big_int.of_int i)), CT_int64); cval]]
@ cleanup
in
[idecl vector_ctyp gs;
- iextern (CL_id gs) (mk_id "internal_vector_init") [(F_lit (V_int (Big_int.of_int len)), CT_int64)] vector_ctyp]
+ iextern (CL_id (gs, vector_ctyp)) (mk_id "internal_vector_init") [(F_lit (V_int (Big_int.of_int len)), CT_int64)]]
@ List.concat (List.mapi aval_set (if direction then List.rev avals else avals)),
(F_id gs, vector_ctyp),
[iclear vector_ctyp gs]
@@ -707,7 +794,7 @@ let rec compile_aval ctx = function
let gs = gensym () in
let mk_cons aval =
let setup, cval, cleanup = compile_aval ctx aval in
- setup @ [ifuncall (CL_id gs) (mk_id ("cons#" ^ string_of_ctyp ctyp)) [cval; (F_id gs, CT_list ctyp)] (CT_list ctyp)] @ cleanup
+ setup @ [ifuncall (CL_id (gs, CT_list ctyp)) (mk_id ("cons#" ^ string_of_ctyp ctyp)) [cval; (F_id gs, CT_list ctyp)]] @ cleanup
in
[idecl (CT_list ctyp) gs]
@ List.concat (List.map mk_cons (List.rev avals)),
@@ -728,125 +815,103 @@ let compile_funcall l ctx id args typ =
| Typ_fn (arg_typ, ret_typ, _) -> [arg_typ], ret_typ
| _ -> assert false
in
- let ctx' = { ctx with local_env = add_typquant (id_loc id) quant ctx.local_env } in
+ let ctx' = { ctx with local_env = add_typquant (id_loc id) quant ctx.tc_env } in
let arg_ctyps, ret_ctyp = List.map (ctyp_of_typ ctx') arg_typs, ctyp_of_typ ctx' ret_typ in
let final_ctyp = ctyp_of_typ ctx typ in
let setup_arg ctyp aval =
let arg_setup, cval, arg_cleanup = compile_aval ctx aval in
- setup := List.rev arg_setup @ !setup;
+ setup := List.rev arg_setup @ [icomment (string_of_ctyp (cval_ctyp cval))] @ !setup;
cleanup := arg_cleanup @ !cleanup;
let have_ctyp = cval_ctyp cval in
if ctyp_equal ctyp have_ctyp then
cval
- else if is_stack_ctyp have_ctyp && not (is_stack_ctyp ctyp) then
+ else
let gs = gensym () in
setup := iinit ctyp gs cval :: !setup;
cleanup := iclear ctyp gs :: !cleanup;
(F_id gs, ctyp)
- else if not (is_stack_ctyp have_ctyp) && is_stack_ctyp ctyp then
- (* This is inefficient. FIXME: Remove id restriction on iconvert
- instruction. Fortunatly only happens when flow typing makes a
- length-polymorphic bitvector monomorphic. *)
- let gs1 = gensym () in
- let gs2 = gensym () in
- setup := idecl have_ctyp gs1 :: !setup;
- setup := icopy (CL_id gs1) cval :: !setup;
- setup := idecl ctyp gs2 :: !setup;
- setup := iconvert (CL_id gs2) ctyp gs1 have_ctyp :: !setup;
- cleanup := iclear have_ctyp gs1 :: !cleanup;
- (F_id gs2, ctyp)
- else
- c_error ~loc:l
- (Printf.sprintf "Failure when setting up function %s arguments: %s and %s." (string_of_id id) (string_of_ctyp have_ctyp) (string_of_ctyp ctyp))
in
assert (List.length arg_ctyps = List.length args);
- let sargs = List.map2 setup_arg arg_ctyps args in
+ let setup_args = List.map2 setup_arg arg_ctyps args in
- let call =
- if ctyp_equal final_ctyp ret_ctyp then
- fun ret -> ifuncall ret id sargs ret_ctyp
- else if not (is_stack_ctyp ret_ctyp) && is_stack_ctyp final_ctyp then
- let gs = gensym () in
- setup := idecl ret_ctyp gs :: !setup;
- setup := ifuncall (CL_id gs) id sargs ret_ctyp :: !setup;
- cleanup := iclear ret_ctyp gs :: !cleanup;
- fun ret -> iconvert ret final_ctyp gs ret_ctyp
- else if is_stack_ctyp ret_ctyp && not (is_stack_ctyp final_ctyp) then
- let gs = gensym () in
- setup := idecl ret_ctyp gs :: !setup;
- setup := ifuncall (CL_id gs) id sargs ret_ctyp :: !setup;
- fun ret -> iconvert ret final_ctyp gs ret_ctyp
- else
- c_error (Printf.sprintf "Funcall call type mismatch between %s and %s" (string_of_ctyp ret_ctyp) (string_of_ctyp final_ctyp))
- in
-
- (List.rev !setup, final_ctyp, call, !cleanup)
+ List.rev !setup,
+ begin fun clexp ->
+ if ctyp_equal (clexp_ctyp clexp) ret_ctyp then
+ ifuncall clexp id setup_args
+ else
+ let gs = gensym () in
+ iblock [idecl ret_ctyp gs;
+ ifuncall (CL_id (gs, ret_ctyp)) id setup_args;
+ icopy clexp (F_id gs, ret_ctyp);
+ iclear ret_ctyp gs]
+ end,
+ !cleanup
let rec compile_match ctx (AP_aux (apat_aux, env, l)) cval case_label =
let ctx = { ctx with local_env = env } in
match apat_aux, cval with
| AP_id (pid, _), (frag, ctyp) when Env.is_union_constructor pid ctx.tc_env ->
[ijump (F_op (F_field (frag, "kind"), "!=", F_lit (V_ctor_kind (string_of_id pid))), CT_bool) case_label],
- []
+ [],
+ ctx
+
| AP_global (pid, typ), (frag, ctyp) ->
let global_ctyp = ctyp_of_typ ctx typ in
- if ctyp_equal global_ctyp ctyp then
- [icopy (CL_id pid) cval], []
- else
- begin match frag with
- | F_id id ->
- [iconvert (CL_id pid) global_ctyp id ctyp], []
- | _ -> c_error "Cannot compile global letbinding"
- end
+ [icopy (CL_id (pid, global_ctyp)) cval], [], ctx
+
| AP_id (pid, _), (frag, ctyp) when is_ct_enum ctyp ->
begin match Env.lookup_id pid ctx.tc_env with
- | Unbound -> [idecl ctyp pid; icopy (CL_id pid) (frag, ctyp)], []
- | _ -> [ijump (F_op (F_id pid, "!=", frag), CT_bool) case_label], []
+ | Unbound -> [idecl ctyp pid; icopy (CL_id (pid, ctyp)) (frag, ctyp)], [], ctx
+ | _ -> [ijump (F_op (F_id pid, "!=", frag), CT_bool) case_label], [], ctx
end
+
| AP_id (pid, typ), _ ->
let ctyp = cval_ctyp cval in
let id_ctyp = ctyp_of_typ ctx typ in
- if ctyp_equal id_ctyp ctyp then
- [idecl ctyp pid; icopy (CL_id pid) cval], [iclear id_ctyp pid]
- else
- let gs = gensym () in
- [idecl id_ctyp pid; idecl ctyp gs; icopy (CL_id gs) cval; iconvert (CL_id pid) id_ctyp gs ctyp; iclear ctyp gs], [iclear id_ctyp pid]
+ c_debug (lazy ("Adding local " ^ string_of_id pid ^ " : " ^ string_of_ctyp id_ctyp));
+ let ctx = { ctx with locals = Bindings.add pid (Immutable, id_ctyp) ctx.locals } in
+ [idecl ctyp pid; icopy (CL_id (pid, id_ctyp)) cval], [iclear id_ctyp pid], ctx
+
| AP_tup apats, (frag, ctyp) ->
begin
let get_tup n ctyp = (F_field (frag, "ztup" ^ string_of_int n), ctyp) in
- let fold (instrs, cleanup, n) apat ctyp =
- let instrs', cleanup' = compile_match ctx apat (get_tup n ctyp) case_label in
- instrs @ instrs', cleanup' @ cleanup, n + 1
+ let fold (instrs, cleanup, n, ctx) apat ctyp =
+ let instrs', cleanup', ctx = compile_match ctx apat (get_tup n ctyp) case_label in
+ instrs @ instrs', cleanup' @ cleanup, n + 1, ctx
in
match ctyp with
| CT_tup ctyps ->
- let instrs, cleanup, _ = List.fold_left2 fold ([], [], 0) apats ctyps in
- instrs, cleanup
+ let instrs, cleanup, _, ctx = List.fold_left2 fold ([], [], 0, ctx) apats ctyps in
+ instrs, cleanup, ctx
| _ -> failwith ("AP_tup with ctyp " ^ string_of_ctyp ctyp)
end
+
| AP_app (ctor, apat), (frag, ctyp) ->
begin match ctyp with
| CT_variant (_, ctors) ->
let ctor_c_id = string_of_id ctor in
let ctor_ctyp = Bindings.find ctor (ctor_bindings ctors) in
- let instrs, cleanup = compile_match ctx apat ((F_field (frag, Util.zencode_string ctor_c_id), ctor_ctyp)) case_label in
+ let instrs, cleanup, ctx = compile_match ctx apat ((F_field (frag, Util.zencode_string ctor_c_id), ctor_ctyp)) case_label in
[ijump (F_op (F_field (frag, "kind"), "!=", F_lit (V_ctor_kind ctor_c_id)), CT_bool) case_label]
@ instrs,
- cleanup
+ cleanup,
+ ctx
| _ -> failwith "AP_app constructor with non-variant type"
end
- | AP_wild, _ -> [], []
+
+ | AP_wild, _ -> [], [], ctx
| AP_cons (hd_apat, tl_apat), (frag, CT_list ctyp) ->
- let hd_setup, hd_cleanup = compile_match ctx hd_apat (F_field (F_unary ("*", frag), "hd"), ctyp) case_label in
- let tl_setup, tl_cleanup = compile_match ctx tl_apat (F_field (F_unary ("*", frag), "tl"), CT_list ctyp) case_label in
- [ijump (F_op (frag, "==", F_lit V_null), CT_bool) case_label] @ hd_setup @ tl_setup, tl_cleanup @ hd_cleanup
+ let hd_setup, hd_cleanup, ctx = compile_match ctx hd_apat (F_field (F_unary ("*", frag), "hd"), ctyp) case_label in
+ let tl_setup, tl_cleanup, ctx = compile_match ctx tl_apat (F_field (F_unary ("*", frag), "tl"), CT_list ctyp) case_label in
+ [ijump (F_op (frag, "==", F_lit V_null), CT_bool) case_label] @ hd_setup @ tl_setup, tl_cleanup @ hd_cleanup, ctx
+
| AP_cons _, (_, _) -> c_error "Tried to pattern match cons on non list type"
- | AP_nil, (frag, _) -> [ijump (F_op (frag, "!=", F_lit V_null), CT_bool) case_label], []
+ | AP_nil, (frag, _) -> [ijump (F_op (frag, "!=", F_lit V_null), CT_bool) case_label], [], ctx
let unit_fragment = (F_lit V_unit, CT_unit)
@@ -860,34 +925,34 @@ let label str =
incr label_counter;
str
+let pointer_assign ctyp1 ctyp2 =
+ match ctyp1 with
+ | CT_ref ctyp1 when ctyp_equal ctyp1 ctyp2 -> true
+ | CT_ref ctyp1 ->
+ c_error (Printf.sprintf "Incompatible type in pointer assignment between %s and %s"
+ (string_of_ctyp ctyp1)
+ (string_of_ctyp ctyp2))
+ | _ -> false
+
let rec compile_aexp ctx (AE_aux (aexp_aux, env, l)) =
let ctx = { ctx with local_env = env } in
match aexp_aux with
- | AE_let (id, _, binding, body, typ) ->
- let setup, ctyp, call, cleanup = compile_aexp ctx binding in
+ | AE_let (mut, id, binding_typ, binding, body, body_typ) ->
+ let binding_ctyp = ctyp_of_typ ctx binding_typ in
+ let setup, call, cleanup = compile_aexp ctx binding in
let letb_setup, letb_cleanup =
- [idecl ctyp id; iblock (setup @ [call (CL_id id)] @ cleanup)], [iclear ctyp id]
+ [idecl binding_ctyp id; iblock (setup @ [call (CL_id (id, binding_ctyp))] @ cleanup)], [iclear binding_ctyp id]
in
- let setup, ctyp, call, cleanup = compile_aexp ctx body in
- let body_ctyp = ctyp_of_typ ctx typ in
- if ctyp_equal body_ctyp ctyp then
- letb_setup @ setup, ctyp, call, cleanup @ letb_cleanup
- else
- begin
- prerr_endline ("Mismatch: " ^ string_of_ctyp body_ctyp ^ " and " ^ string_of_ctyp ctyp);
- let gs = gensym () in
- letb_setup @ setup @ [idecl ctyp gs; call (CL_id gs)],
- body_ctyp,
- (fun clexp -> iconvert clexp body_ctyp gs ctyp),
- [iclear ctyp gs] @ cleanup @ letb_cleanup
- end
+ let ctx = { ctx with locals = Bindings.add id (mut, binding_ctyp) ctx.locals } in
+ let setup, call, cleanup = compile_aexp ctx body in
+ letb_setup @ setup, call, cleanup @ letb_cleanup
| AE_app (id, vs, typ) ->
compile_funcall l ctx id vs typ
| AE_val aval ->
let setup, cval, cleanup = compile_aval ctx aval in
- setup, cval_ctyp cval, (fun clexp -> icopy clexp cval), cleanup
+ setup, (fun clexp -> icopy clexp cval), cleanup
(* Compile case statements *)
| AE_case (aval, cases, typ) ->
@@ -903,19 +968,19 @@ let rec compile_aexp ctx (AE_aux (aexp_aux, env, l)) =
in
let case_label = label "case_" in
c_debug (lazy ("Compiling match"));
- let destructure, destructure_cleanup = compile_match ctx apat cval case_label in
+ let destructure, destructure_cleanup, ctx = compile_match ctx apat cval case_label in
c_debug (lazy ("Compiled match"));
- let guard_setup, _, guard_call, guard_cleanup = compile_aexp ctx guard in
- let body_setup, _, body_call, body_cleanup = compile_aexp ctx body in
+ let guard_setup, guard_call, guard_cleanup = compile_aexp ctx guard in
+ let body_setup, body_call, body_cleanup = compile_aexp ctx body in
let gs = gensym () in
let case_instrs =
destructure @ [icomment "end destructuring"]
@ (if not trivial_guard then
- guard_setup @ [idecl CT_bool gs; guard_call (CL_id gs)] @ guard_cleanup
+ guard_setup @ [idecl CT_bool gs; guard_call (CL_id (gs, CT_bool))] @ guard_cleanup
@ [iif (F_unary ("!", F_id gs), CT_bool) (destructure_cleanup @ [igoto case_label]) [] CT_unit]
@ [icomment "end guard"]
else [])
- @ body_setup @ [body_call (CL_id case_return_id)] @ body_cleanup @ destructure_cleanup
+ @ body_setup @ [body_call (CL_id (case_return_id, ctyp))] @ body_cleanup @ destructure_cleanup
@ [igoto finish_match_label]
in
[iblock case_instrs; ilabel case_label]
@@ -925,15 +990,15 @@ let rec compile_aexp ctx (AE_aux (aexp_aux, env, l)) =
@ List.concat (List.map compile_case cases)
@ [imatch_failure ()]
@ [ilabel finish_match_label],
- ctyp,
(fun clexp -> icopy clexp (F_id case_return_id, ctyp)),
- (if is_stack_ctyp ctyp then [] else [iclear ctyp case_return_id])
+ [iclear ctyp case_return_id]
@ aval_cleanup
@ [icomment "end match"]
(* Compile try statement *)
| AE_try (aexp, cases, typ) ->
- let aexp_setup, ctyp, aexp_call, aexp_cleanup = compile_aexp ctx aexp in
+ let ctyp = ctyp_of_typ ctx typ in
+ let aexp_setup, aexp_call, aexp_cleanup = compile_aexp ctx aexp in
let try_return_id = gensym () in
let handled_exception_label = label "handled_exception_" in
let compile_case (apat, guard, body) =
@@ -944,18 +1009,18 @@ let rec compile_aexp ctx (AE_aux (aexp_aux, env, l)) =
in
let try_label = label "try_" in
let exn_cval = (F_current_exception, ctyp_of_typ ctx (mk_typ (Typ_id (mk_id "exception")))) in
- let destructure, destructure_cleanup = compile_match ctx apat exn_cval try_label in
- let guard_setup, _, guard_call, guard_cleanup = compile_aexp ctx guard in
- let body_setup, _, body_call, body_cleanup = compile_aexp ctx body in
+ let destructure, destructure_cleanup, ctx = compile_match ctx apat exn_cval try_label in
+ let guard_setup, guard_call, guard_cleanup = compile_aexp ctx guard in
+ let body_setup, body_call, body_cleanup = compile_aexp ctx body in
let gs = gensym () in
let case_instrs =
destructure @ [icomment "end destructuring"]
@ (if not trivial_guard then
- guard_setup @ [idecl CT_bool gs; guard_call (CL_id gs)] @ guard_cleanup
+ guard_setup @ [idecl CT_bool gs; guard_call (CL_id (gs, CT_bool))] @ guard_cleanup
@ [ijump (F_unary ("!", F_id gs), CT_bool) try_label]
@ [icomment "end guard"]
else [])
- @ body_setup @ [body_call (CL_id try_return_id)] @ body_cleanup @ destructure_cleanup
+ @ body_setup @ [body_call (CL_id (try_return_id, ctyp))] @ body_cleanup @ destructure_cleanup
@ [igoto handled_exception_label]
in
[iblock case_instrs; ilabel try_label]
@@ -963,35 +1028,23 @@ let rec compile_aexp ctx (AE_aux (aexp_aux, env, l)) =
assert (ctyp_equal ctyp (ctyp_of_typ ctx typ));
[icomment "begin try catch";
idecl ctyp try_return_id;
- itry_block (aexp_setup @ [aexp_call (CL_id try_return_id)] @ aexp_cleanup);
+ itry_block (aexp_setup @ [aexp_call (CL_id (try_return_id, ctyp))] @ aexp_cleanup);
ijump (F_unary ("!", F_have_exception), CT_bool) handled_exception_label]
@ List.concat (List.map compile_case cases)
@ [imatch_failure ();
ilabel handled_exception_label;
icopy CL_have_exception (F_lit (V_bool false), CT_bool)],
- ctyp,
(fun clexp -> icopy clexp (F_id try_return_id, ctyp)),
[]
| AE_if (aval, then_aexp, else_aexp, if_typ) ->
let if_ctyp = ctyp_of_typ ctx if_typ in
let compile_branch aexp =
- let setup, ctyp, call, cleanup = compile_aexp ctx aexp in
- if ctyp_equal if_ctyp ctyp then
- fun clexp -> setup @ [call clexp] @ cleanup
- else
- fun clexp ->
- let gs = gensym () in
- setup
- @ [idecl ctyp gs;
- call (CL_id gs);
- iconvert clexp if_ctyp gs ctyp;
- iclear ctyp gs]
- @ cleanup
+ let setup, call, cleanup = compile_aexp ctx aexp in
+ fun clexp -> setup @ [call clexp] @ cleanup
in
let setup, cval, cleanup = compile_aval ctx aval in
setup,
- if_ctyp,
(fun clexp -> iif cval
(compile_branch then_aexp clexp)
(compile_branch else_aexp clexp)
@@ -1001,43 +1054,51 @@ let rec compile_aexp ctx (AE_aux (aexp_aux, env, l)) =
(* FIXME: AE_record_update could be AV_record_update - would reduce some copying. *)
| AE_record_update (aval, fields, typ) ->
let ctyp = ctyp_of_typ ctx typ in
+ let ctors = match ctyp with
+ | CT_struct (_, ctors) -> List.fold_left (fun m (k, v) -> Bindings.add k v m) Bindings.empty ctors
+ | _ -> c_error "Cannot perform record update for non-record type"
+ in
let gs = gensym () in
let compile_fields (id, aval) =
let field_setup, cval, field_cleanup = compile_aval ctx aval in
field_setup
- @ [icopy (CL_field (gs, string_of_id id)) cval]
+ @ [icomment (string_of_ctyp ctyp)]
+ @ [icopy (CL_field (gs, string_of_id id, Bindings.find id ctors)) cval]
@ field_cleanup
in
let setup, cval, cleanup = compile_aval ctx aval in
[idecl ctyp gs]
@ setup
- @ [icopy (CL_id gs) cval]
+ @ [icopy (CL_id (gs, ctyp)) cval]
@ cleanup
@ List.concat (List.map compile_fields (Bindings.bindings fields)),
- ctyp,
(fun clexp -> icopy clexp (F_id gs, ctyp)),
[iclear ctyp gs]
| AE_short_circuit (SC_and, aval, aexp) ->
let left_setup, cval, left_cleanup = compile_aval ctx aval in
- let right_setup, _, call, right_cleanup = compile_aexp ctx aexp in
+ let right_setup, call, right_cleanup = compile_aexp ctx aexp in
let gs = gensym () in
left_setup
@ [ idecl CT_bool gs;
- iif cval (right_setup @ [call (CL_id gs)] @ right_cleanup) [icopy (CL_id gs) (F_lit (V_bool false), CT_bool)] CT_bool ]
+ iif cval
+ (right_setup @ [call (CL_id (gs, CT_bool))] @ right_cleanup)
+ [icopy (CL_id (gs, CT_bool)) (F_lit (V_bool false), CT_bool)]
+ CT_bool ]
@ left_cleanup,
- CT_bool,
(fun clexp -> icopy clexp (F_id gs, CT_bool)),
[]
| AE_short_circuit (SC_or, aval, aexp) ->
let left_setup, cval, left_cleanup = compile_aval ctx aval in
- let right_setup, _, call, right_cleanup = compile_aexp ctx aexp in
+ let right_setup, call, right_cleanup = compile_aexp ctx aexp in
let gs = gensym () in
left_setup
@ [ idecl CT_bool gs;
- iif cval [icopy (CL_id gs) (F_lit (V_bool true), CT_bool)] (right_setup @ [call (CL_id gs)] @ right_cleanup) CT_bool ]
+ iif cval
+ [icopy (CL_id (gs, CT_bool)) (F_lit (V_bool true), CT_bool)]
+ (right_setup @ [call (CL_id (gs, CT_bool))] @ right_cleanup)
+ CT_bool ]
@ left_cleanup,
- CT_bool,
(fun clexp -> icopy clexp (F_id gs, CT_bool)),
[]
@@ -1049,91 +1110,64 @@ let rec compile_aexp ctx (AE_aux (aexp_aux, env, l)) =
let compile_fields (field_id, aval) =
let field_setup, cval, field_cleanup = compile_aval ctx aval in
field_setup
- @ [icopy (CL_field (id, string_of_id field_id)) cval]
+ @ [icopy (CL_field (id, string_of_id field_id, cval_ctyp cval)) cval]
@ field_cleanup
in
List.concat (List.map compile_fields (Bindings.bindings fields)),
- CT_unit,
(fun clexp -> icopy clexp unit_fragment),
[]
| AE_assign (id, assign_typ, aexp) ->
- (* assign_ctyp is the type of the C variable we are assigning to,
- ctyp is the type of the C expression being assigned. These may
- be different. *)
- let pointer_assign ctyp1 ctyp2 =
- match ctyp1 with
- | CT_ref ctyp1 when ctyp_equal ctyp1 ctyp2 -> true
- | CT_ref ctyp1 -> c_error ~loc:l "Incompatible type in pointer assignment"
- | _ -> false
- in
let assign_ctyp = ctyp_of_typ ctx assign_typ in
- let setup, ctyp, call, cleanup = compile_aexp ctx aexp in
- let comment = "assign " ^ string_of_ctyp assign_ctyp ^ " := " ^ string_of_ctyp ctyp in
- if ctyp_equal assign_ctyp ctyp then
- setup @ [call (CL_id id)], CT_unit, (fun clexp -> icopy clexp unit_fragment), cleanup
- else if pointer_assign assign_ctyp ctyp then
- setup @ [call (CL_addr id)], CT_unit, (fun clexp -> icopy clexp unit_fragment), cleanup
- else
- let gs = gensym () in
- setup @ [ icomment comment;
- idecl ctyp gs;
- call (CL_id gs);
- iconvert (CL_id id) assign_ctyp gs ctyp;
- iclear ctyp gs
- ],
- CT_unit,
- (fun clexp -> icopy clexp unit_fragment),
- cleanup
+ let setup, call, cleanup = compile_aexp ctx aexp in
+ setup @ [call (CL_id (id, assign_ctyp))], (fun clexp -> icopy clexp unit_fragment), cleanup
| AE_block (aexps, aexp, _) ->
let block = compile_block ctx aexps in
- let setup, ctyp, call, cleanup = compile_aexp ctx aexp in
- block @ setup, ctyp, call, cleanup
+ let setup, call, cleanup = compile_aexp ctx aexp in
+ block @ setup, call, cleanup
| AE_loop (While, cond, body) ->
let loop_start_label = label "while_" in
let loop_end_label = label "wend_" in
- let cond_setup, _, cond_call, cond_cleanup = compile_aexp ctx cond in
- let body_setup, _, body_call, body_cleanup = compile_aexp ctx body in
+ let cond_setup, cond_call, cond_cleanup = compile_aexp ctx cond in
+ let body_setup, body_call, body_cleanup = compile_aexp ctx body in
let gs = gensym () in
let unit_gs = gensym () in
let loop_test = (F_unary ("!", F_id gs), CT_bool) in
[idecl CT_bool gs; idecl CT_unit unit_gs]
@ [ilabel loop_start_label]
@ [iblock (cond_setup
- @ [cond_call (CL_id gs)]
+ @ [cond_call (CL_id (gs, CT_bool))]
@ cond_cleanup
@ [ijump loop_test loop_end_label]
@ body_setup
- @ [body_call (CL_id unit_gs)]
+ @ [body_call (CL_id (unit_gs, CT_unit))]
@ body_cleanup
@ [igoto loop_start_label])]
@ [ilabel loop_end_label],
- CT_unit,
(fun clexp -> icopy clexp unit_fragment),
[]
| AE_loop (Until, cond, body) ->
let loop_start_label = label "repeat_" in
let loop_end_label = label "until_" in
- let cond_setup, _, cond_call, cond_cleanup = compile_aexp ctx cond in
- let body_setup, _, body_call, body_cleanup = compile_aexp ctx body in
+ let cond_setup, cond_call, cond_cleanup = compile_aexp ctx cond in
+ let body_setup, body_call, body_cleanup = compile_aexp ctx body in
let gs = gensym () in
let unit_gs = gensym () in
let loop_test = (F_id gs, CT_bool) in
[idecl CT_bool gs; idecl CT_unit unit_gs]
@ [ilabel loop_start_label]
@ [iblock (body_setup
- @ [body_call (CL_id unit_gs)]
+ @ [body_call (CL_id (unit_gs, CT_unit))]
@ body_cleanup
@ cond_setup
- @ [cond_call (CL_id gs)]
+ @ [cond_call (CL_id (gs, CT_bool))]
@ cond_cleanup
@ [ijump loop_test loop_end_label]
@ [igoto loop_start_label])]
@ [ilabel loop_end_label],
- CT_unit,
(fun clexp -> icopy clexp unit_fragment),
[]
@@ -1149,19 +1183,13 @@ let rec compile_aexp ctx (AE_aux (aexp_aux, env, l)) =
let creturn =
if ctyp_equal fn_return_ctyp (cval_ctyp cval) then
[ireturn cval]
- else if is_stack_ctyp (cval_ctyp cval) && not (is_stack_ctyp fn_return_ctyp) then
- let gs1 = gensym () in
- let gs2 = gensym () in
- [idecl (cval_ctyp cval) gs1;
- icopy (CL_id gs1) cval;
- idecl fn_return_ctyp gs2;
- iconvert (CL_id gs2) fn_return_ctyp gs1 (cval_ctyp cval);
- ireturn (F_id gs2, fn_return_ctyp)]
else
- c_error ~loc:l "Can only do return type conversion from stack to heap"
+ let gs = gensym () in
+ [idecl fn_return_ctyp gs;
+ icopy (CL_id (gs, fn_return_ctyp)) cval;
+ ireturn (F_id gs, fn_return_ctyp)]
in
return_setup @ creturn,
- ctyp_of_typ ctx typ,
(fun clexp -> icomment "unreachable after return"),
[]
@@ -1169,7 +1197,6 @@ let rec compile_aexp ctx (AE_aux (aexp_aux, env, l)) =
(* Cleanup info will be handled by fix_exceptions *)
let throw_setup, cval, _ = compile_aval ctx aval in
throw_setup @ [ithrow cval],
- ctyp_of_typ ctx typ,
(fun clexp -> icomment "unreachable after throw"),
[]
@@ -1177,7 +1204,6 @@ let rec compile_aexp ctx (AE_aux (aexp_aux, env, l)) =
let ctyp = ctyp_of_typ ctx typ in
let setup, cval, cleanup = compile_aval ctx aval in
setup,
- ctyp,
(fun clexp -> icopy clexp (F_field (fst cval, Util.zencode_string (string_of_id id)), ctyp)),
cleanup
@@ -1198,43 +1224,37 @@ let rec compile_aexp ctx (AE_aux (aexp_aux, env, l)) =
in
(* Loop variables *)
- let from_setup, from_ctyp, from_call, from_cleanup = compile_aexp ctx loop_from in
+ let from_setup, from_call, from_cleanup = compile_aexp ctx loop_from in
let from_gs = gensym () in
- let to_setup, to_ctyp, to_call, to_cleanup = compile_aexp ctx loop_to in
+ let to_setup, to_call, to_cleanup = compile_aexp ctx loop_to in
let to_gs = gensym () in
- let step_setup, step_ctyp, step_call, step_cleanup = compile_aexp ctx loop_step in
+ let step_setup, step_call, step_cleanup = compile_aexp ctx loop_step in
let step_gs = gensym () in
- let variable_init gs setup ctyp call cleanup =
+ let variable_init gs setup call cleanup =
[idecl CT_int64 gs;
- if is_stack_ctyp ctyp then
- iblock (setup @ [call (CL_id gs)] @ cleanup)
- else
- let gs' = gensym () in
- iblock (setup
- @ [idecl ctyp gs'; call (CL_id gs'); iconvert (CL_id gs) CT_int64 gs' ctyp; iclear ctyp gs']
- @ cleanup)]
+ iblock (setup @ [call (CL_id (gs, CT_int64))] @ cleanup)]
in
let loop_start_label = label "for_start_" in
let loop_end_label = label "for_end_" in
- let body_setup, _, body_call, body_cleanup = compile_aexp ctx body in
+ let body_setup, body_call, body_cleanup = compile_aexp ctx body in
let body_gs = gensym () in
- variable_init from_gs from_setup from_ctyp from_call from_cleanup
- @ variable_init to_gs to_setup to_ctyp to_call to_cleanup
- @ variable_init step_gs step_setup step_ctyp step_call step_cleanup
+ variable_init from_gs from_setup from_call from_cleanup
+ @ variable_init to_gs to_setup to_call to_cleanup
+ @ variable_init step_gs step_setup step_call step_cleanup
@ [iblock ([idecl CT_int64 loop_var;
- icopy (CL_id loop_var) (F_id from_gs, CT_int64);
+ icopy (CL_id (loop_var, CT_int64)) (F_id from_gs, CT_int64);
idecl CT_unit body_gs;
iblock ([ilabel loop_start_label]
@ [ijump (F_op (F_id loop_var, (if is_inc then ">" else "<"), F_id to_gs), CT_bool) loop_end_label]
@ body_setup
- @ [body_call (CL_id body_gs)]
+ @ [body_call (CL_id (body_gs, CT_unit))]
@ body_cleanup
- @ [icopy (CL_id loop_var) (F_op (F_id loop_var, (if is_inc then "+" else "-"), F_id step_gs), CT_int64)]
+ @ [icopy (CL_id (loop_var, CT_int64))
+ (F_op (F_id loop_var, (if is_inc then "+" else "-"), F_id step_gs), CT_int64)]
@ [igoto loop_start_label]);
ilabel loop_end_label])],
- CT_unit,
(fun clexp -> icopy clexp unit_fragment),
[]
@@ -1245,10 +1265,10 @@ let rec compile_aexp ctx (AE_aux (aexp_aux, env, l)) =
and compile_block ctx = function
| [] -> []
| exp :: exps ->
- let setup, _, call, cleanup = compile_aexp ctx exp in
+ let setup, call, cleanup = compile_aexp ctx exp in
let rest = compile_block ctx exps in
let gs = gensym () in
- iblock (setup @ [idecl CT_unit gs; call (CL_id gs)] @ cleanup) :: rest
+ iblock (setup @ [idecl CT_unit gs; call (CL_id (gs, CT_unit))] @ cleanup) :: rest
(** Compile a sail type definition into a IR one. Most of the
actual work of translating the typedefs into C is done by the code
@@ -1384,7 +1404,7 @@ let fix_early_stack_return ctx instrs =
in
rewrite_return [] instrs
-let fix_exception_block ctx instrs =
+let fix_exception_block ?return:(return=None) ctx instrs =
let end_block_label = label "end_block_exception_" in
let is_exception_stop (I_aux (instr, _)) =
match instr with
@@ -1409,12 +1429,12 @@ let fix_exception_block ctx instrs =
@ rewrite_exception historic after
| before, I_aux (I_throw cval, _) :: after ->
before
- @ [icopy CL_current_exception cval;
+ @ [icopy (CL_current_exception (cval_ctyp cval)) cval;
icopy CL_have_exception (F_lit (V_bool true), CT_bool)]
@ generate_cleanup (historic @ before)
@ [igoto end_block_label]
@ rewrite_exception (historic @ before) after
- | before, (I_aux (I_funcall (x, _, f, args, ctyp), _) as funcall) :: after ->
+ | before, (I_aux (I_funcall (x, _, f, args), _) as funcall) :: after ->
let effects = match Env.get_val_spec f ctx.tc_env with
| _, Typ_aux (Typ_fn (_, _, effects), _) -> effects
| exception (Type_error _) -> no_effect (* nullary union constructor, so no val spec *)
@@ -1429,24 +1449,27 @@ let fix_exception_block ctx instrs =
before @ funcall :: rewrite_exception (historic @ before) after
| _, _ -> assert false (* unreachable *)
in
- rewrite_exception [] instrs
- @ [ilabel end_block_label]
-
+ match return with
+ | None ->
+ rewrite_exception [] instrs @ [ilabel end_block_label]
+ | Some ctyp ->
+ rewrite_exception [] instrs @ [ilabel end_block_label; iundefined ctyp]
+
let rec map_try_block f (I_aux (instr, aux)) =
let instr = match instr with
| I_decl _ | I_reset _ | I_init _ | I_reinit _ -> instr
| I_if (cval, instrs1, instrs2, ctyp) ->
I_if (cval, List.map (map_try_block f) instrs1, List.map (map_try_block f) instrs2, ctyp)
- | I_funcall _ | I_convert _ | I_copy _ | I_clear _ | I_throw _ | I_return _ -> instr
+ | I_funcall _ | I_copy _ | I_clear _ | I_throw _ | I_return _ -> instr
| I_block instrs -> I_block (List.map (map_try_block f) instrs)
| I_try_block instrs -> I_try_block (f (List.map (map_try_block f) instrs))
- | I_comment _ | I_label _ | I_goto _ | I_raw _ | I_jump _ | I_match_failure -> instr
+ | I_comment _ | I_label _ | I_goto _ | I_raw _ | I_jump _ | I_match_failure | I_undefined _ -> instr
in
I_aux (instr, aux)
-let fix_exception ctx instrs =
+let fix_exception ?return:(return=None) ctx instrs =
let instrs = List.map (map_try_block (fix_exception_block ctx)) instrs in
- fix_exception_block ctx instrs
+ fix_exception_block ~return:return ctx instrs
let rec arg_pats ctx (Typ_aux (arg_typ_aux, _) as arg_typ) (P_aux (p_aux, (l, _)) as pat) =
match p_aux, arg_typ_aux with
@@ -1466,7 +1489,7 @@ let rec compile_arg_pat ctx label (P_aux (p_aux, (l, _)) as pat, ctyp) =
| _ ->
let apat = anf_pat pat in
let gs = gensym () in
- let destructure, cleanup = compile_match ctx apat (F_id gs, ctyp) label in
+ let destructure, cleanup, _ = compile_match ctx apat (F_id gs, ctyp) label in
(gs, (destructure, cleanup))
let combine_destructure_cleanup xs = List.concat (List.map fst xs), List.concat (List.rev (List.map snd xs))
@@ -1484,9 +1507,9 @@ let rec compile_def ctx = function
| DEF_reg_dec (DEC_aux (DEC_reg (typ, id), _)) ->
[CDEF_reg_dec (id, ctyp_of_typ ctx typ, [])], ctx
| DEF_reg_dec (DEC_aux (DEC_config (id, typ, exp), _)) ->
- let aexp = map_functions (analyze_primop ctx) (c_literals ctx (no_shadow IdSet.empty (anf exp))) in
- let setup, ctyp, call, cleanup = compile_aexp ctx aexp in
- let instrs = setup @ [call (CL_id id)] @ cleanup in
+ let aexp = analyze_functions ctx analyze_primop (c_literals ctx (no_shadow IdSet.empty (anf exp))) in
+ let setup, call, cleanup = compile_aexp ctx aexp in
+ let instrs = setup @ [call (CL_id (id, ctyp_of_typ ctx typ))] @ cleanup in
[CDEF_reg_dec (id, ctyp_of_typ ctx typ, instrs)], ctx
| DEF_spec (VS_aux (VS_val_spec (_, id, _, _), _)) ->
@@ -1503,30 +1526,57 @@ let rec compile_def ctx = function
| DEF_fundef (FD_aux (FD_function (_, _, _, [FCL_aux (FCL_Funcl (id, Pat_aux (Pat_exp (pat, exp), _)), _)]), _)) ->
c_debug (lazy ("Compiling function " ^ string_of_id id));
- let aexp = map_functions (analyze_primop ctx) (c_literals ctx (no_shadow (pat_ids pat) (anf exp))) in
- let setup, ctyp, call, cleanup = compile_aexp ctx aexp in
- c_debug (lazy "Compiled aexp");
- let fundef_label = label "fundef_fail_" in
- let _, Typ_aux (fn_typ, _) = Env.get_val_spec id ctx.tc_env in
+ (* Find the function's type *)
+ let quant, Typ_aux (fn_typ, _) =
+ try Env.get_val_spec id ctx.local_env
+ with Type_error _ ->
+ c_debug (lazy ("Falling back to global env for " ^ string_of_id id)); Env.get_val_spec id ctx.tc_env
+ in
let arg_typ, ret_typ = match fn_typ with
| Typ_fn (arg_typ, ret_typ, _) -> arg_typ, ret_typ
| _ -> assert false
in
- let compiled_args = List.map (compile_arg_pat ctx fundef_label) (arg_pats ctx arg_typ pat) in
+
+ (* Handle the argument pattern *)
+ let fundef_label = label "fundef_fail_" in
+ let orig_ctx = ctx in
+ let ctx = { ctx with local_env = add_typquant (id_loc id) quant ctx.tc_env } in
+ let compiled_args' = arg_pats ctx arg_typ pat in
+ let compiled_args = List.map (compile_arg_pat ctx fundef_label) compiled_args' in
+ let ctx =
+ (* We need the primop analyzer to be aware of the function argument types, so put them in ctx *)
+ List.fold_left2 (fun ctx (id, _) (_, ctyp) -> { ctx with locals = Bindings.add id (Immutable, ctyp) ctx.locals }) ctx compiled_args compiled_args'
+ in
+
+ if string_of_id id = "TLBTranslateC" then c_verbosity := 1 else ();
+
+ (* Optimize and compile the expression *)
+ let aexp = no_shadow (pat_ids pat) (anf exp) in
+ c_debug (lazy (Pretty_print_sail.to_string (pp_aexp aexp)));
+ let aexp = analyze_functions ctx analyze_primop (c_literals ctx aexp) in
+ c_debug (lazy (Pretty_print_sail.to_string (pp_aexp aexp)));
+ let setup, call, cleanup = compile_aexp ctx aexp in
+ c_debug (lazy "Compiled aexp");
let gs = gensym () in
let destructure, destructure_cleanup =
compiled_args |> List.map snd |> combine_destructure_cleanup |> fix_destructure fundef_label
in
- if is_stack_ctyp ctyp then
- let instrs = destructure @ [idecl ctyp gs] @ setup @ [call (CL_id gs)] @ cleanup @ destructure_cleanup @ [ireturn (F_id gs, ctyp)] in
+
+ c_verbosity := 0;
+
+ (* This better be true or something has gone badly wrong. *)
+ let ret_ctyp = ctyp_of_typ ctx ret_typ in
+
+ if is_stack_ctyp ret_ctyp then
+ let instrs = destructure @ [idecl ret_ctyp gs] @ setup @ [call (CL_id (gs, ret_ctyp))] @ cleanup @ destructure_cleanup @ [ireturn (F_id gs, ret_ctyp)] in
let instrs = fix_early_stack_return ctx instrs in
- let instrs = fix_exception ctx instrs in
- [CDEF_fundef (id, None, List.map fst compiled_args, instrs)], ctx
+ let instrs = fix_exception ~return:(Some ret_ctyp) ctx instrs in
+ [CDEF_fundef (id, None, List.map fst compiled_args, instrs)], orig_ctx
else
- let instrs = destructure @ setup @ [call (CL_addr gs)] @ cleanup @ destructure_cleanup in
- let instrs = fix_early_return (CL_addr gs) ctx instrs in
+ let instrs = destructure @ setup @ [call (CL_addr (gs, ret_ctyp))] @ cleanup @ destructure_cleanup in
+ let instrs = fix_early_return (CL_addr (gs, ret_ctyp)) ctx instrs in
let instrs = fix_exception ctx instrs in
- [CDEF_fundef (id, Some gs, List.map fst compiled_args, instrs)], ctx
+ [CDEF_fundef (id, Some gs, List.map fst compiled_args, instrs)], orig_ctx
| DEF_fundef (FD_aux (FD_function (_, _, _, []), (l, _))) ->
c_error ~loc:l "Encountered function with no clauses"
@@ -1543,14 +1593,15 @@ let rec compile_def ctx = function
| DEF_val (LB_aux (LB_val (pat, exp), _)) ->
c_debug (lazy ("Compiling letbind " ^ string_of_pat pat));
- let aexp = map_functions (analyze_primop ctx) (c_literals ctx (no_shadow IdSet.empty (anf exp))) in
- let setup, ctyp, call, cleanup = compile_aexp ctx aexp in
+ let ctyp = ctyp_of_typ ctx (pat_typ_of pat) in
+ let aexp = analyze_functions ctx analyze_primop (c_literals ctx (no_shadow IdSet.empty (anf exp))) in
+ let setup, call, cleanup = compile_aexp ctx aexp in
let apat = anf_pat ~global:true pat in
let gs = gensym () in
let end_label = label "let_end_" in
- let destructure, destructure_cleanup = compile_match ctx apat (F_id gs, ctyp) end_label in
+ let destructure, destructure_cleanup, _ = compile_match ctx apat (F_id gs, ctyp) end_label in
let gs_setup, gs_cleanup =
- [idecl ctyp gs], [iclear ctyp gs]
+ [idecl ctyp gs], [iclear ctyp gs]
in
let bindings = List.map (fun (id, typ) -> id, ctyp_of_typ ctx typ) (apat_globals apat) in
let n = !letdef_count in
@@ -1558,7 +1609,7 @@ let rec compile_def ctx = function
let instrs =
[icomment "gs_setup"] @ gs_setup @ [icomment "setup"] @ setup
@ [icomment "call"]
- @ [call (CL_id gs)]
+ @ [call (CL_id (gs, ctyp))]
@ [icomment "cleanup"]
@ cleanup
@ [icomment "destructure"]
@@ -1618,11 +1669,11 @@ let add_local_labels instrs =
let clexp_rename from_id to_id =
let rename id = if Id.compare id from_id = 0 then to_id else id in
function
- | CL_id id -> CL_id (rename id)
- | CL_field (id, field) -> CL_field (rename id, field)
- | CL_addr id -> CL_addr (rename id)
- | CL_addr_field (id, field) -> CL_addr_field (rename id, field)
- | CL_current_exception -> CL_current_exception
+ | CL_id (id, ctyp) -> CL_id (rename id, ctyp)
+ | CL_field (id, field, ctyp) -> CL_field (rename id, field, ctyp)
+ | CL_addr (id, ctyp) -> CL_addr (rename id, ctyp)
+ | CL_addr_field (id, field, ctyp) -> CL_addr_field (rename id, field, ctyp)
+ | CL_current_exception ctyp -> CL_current_exception ctyp
| CL_have_exception -> CL_have_exception
let rec instrs_rename from_id to_id =
@@ -1639,17 +1690,15 @@ let rec instrs_rename from_id to_id =
| I_aux (I_if (cval, then_instrs, else_instrs, ctyp), aux) :: instrs ->
I_aux (I_if (crename cval, irename then_instrs, irename else_instrs, ctyp), aux) :: irename instrs
| I_aux (I_jump (cval, label), aux) :: instrs -> I_aux (I_jump (crename cval, label), aux) :: irename instrs
- | I_aux (I_funcall (clexp, extern, id, cvals, ctyp), aux) :: instrs ->
- I_aux (I_funcall (lrename clexp, extern, rename id, List.map crename cvals, ctyp), aux) :: irename instrs
+ | I_aux (I_funcall (clexp, extern, id, cvals), aux) :: instrs ->
+ I_aux (I_funcall (lrename clexp, extern, rename id, List.map crename cvals), aux) :: irename instrs
| I_aux (I_copy (clexp, cval), aux) :: instrs -> I_aux (I_copy (lrename clexp, crename cval), aux) :: irename instrs
- | I_aux (I_convert (clexp, ctyp1, id, ctyp2), aux) :: instrs ->
- I_aux (I_convert (lrename clexp, ctyp1, rename id, ctyp2), aux) :: irename instrs
| I_aux (I_clear (ctyp, id), aux) :: instrs -> I_aux (I_clear (ctyp, rename id), aux) :: irename instrs
| I_aux (I_return cval, aux) :: instrs -> I_aux (I_return (crename cval), aux) :: irename instrs
| I_aux (I_block block, aux) :: instrs -> I_aux (I_block (irename block), aux) :: irename instrs
| I_aux (I_try_block block, aux) :: instrs -> I_aux (I_try_block (irename block), aux) :: irename instrs
| I_aux (I_throw cval, aux) :: instrs -> I_aux (I_throw (crename cval), aux) :: irename instrs
- | (I_aux ((I_comment _ | I_raw _ | I_label _ | I_goto _ | I_match_failure), _) as instr) :: instrs -> instr :: irename instrs
+ | (I_aux ((I_comment _ | I_raw _ | I_label _ | I_goto _ | I_match_failure | I_undefined _), _) as instr) :: instrs -> instr :: irename instrs
| [] -> []
let hoist_ctyp = function
@@ -1750,6 +1799,7 @@ let flatten_instrs ctx =
| cdef -> [cdef]
+ (*
(* When this optimization fires we know we have bytecode of the form
recreate x : S; x = y; ...
@@ -1762,18 +1812,18 @@ let flatten_instrs ctx =
let fix_struct_updates ctx =
(* FIXME need to check no remaining references *)
let rec fix_updates struct_id id = function
- | I_aux (I_copy (CL_field (struct_id', field), cval), aux) :: instrs
+ | I_aux (I_copy (CL_field (struct_id', field, ctyp), cval), aux) :: instrs
when Id.compare struct_id struct_id' = 0 ->
- Util.option_map (fun instrs -> I_aux (I_copy (CL_field (id, field), cval), aux) :: instrs) (fix_updates struct_id id instrs)
+ Util.option_map (fun instrs -> I_aux (I_copy (CL_field (id, field, ctyp), cval), aux) :: instrs) (fix_updates struct_id id instrs)
| I_aux (I_copy (CL_id id', (F_id struct_id', ctyp)), aux) :: instrs
when Id.compare struct_id struct_id' = 0 && Id.compare id id' = 0->
Some instrs
| _ -> None
in
let rec fix_updates_ret struct_id id = function
- | I_aux (I_copy (CL_field (struct_id', field), cval), aux) :: instrs
+ | I_aux (I_copy (CL_field (struct_id', field, ctyp), cval), aux) :: instrs
when Id.compare struct_id struct_id' = 0 ->
- Util.option_map (fun instrs -> I_aux (I_copy (CL_addr_field (id, field), cval), aux) :: instrs) (fix_updates_ret struct_id id instrs)
+ Util.option_map (fun instrs -> I_aux (I_copy (CL_addr_field (id, field, ctyp), cval), aux) :: instrs) (fix_updates_ret struct_id id instrs)
| I_aux (I_copy (CL_addr id', (F_id struct_id', ctyp)), aux) :: instrs
when Id.compare struct_id struct_id' = 0 && Id.compare id id' = 0->
Some instrs
@@ -1781,10 +1831,9 @@ let fix_struct_updates ctx =
in
let rec opt hr = function
| (I_aux (I_reset (ctyp, struct_id), _) as instr1)
- :: (I_aux (I_copy (CL_id struct_id', (F_id id, ctyp')), _) as instr2)
+ :: (I_aux (I_copy (CL_id (struct_id', _), (F_id id, ctyp')), _) as instr2)
:: instrs
when is_ct_struct ctyp && ctyp_equal ctyp ctyp' && Id.compare struct_id struct_id' = 0 ->
- prerr_endline ("Potential struct update " ^ string_of_id struct_id);
begin match fix_updates struct_id id instrs with
| None -> instr1 :: instr2 :: opt hr instrs
| Some updated -> opt hr updated
@@ -1793,7 +1842,6 @@ let fix_struct_updates ctx =
| (I_aux (I_reset (ctyp, struct_id), _) as instr) :: instrs
when is_ct_struct ctyp && Util.is_some hr ->
let id = match hr with Some id -> id | None -> assert false in
- prerr_endline ("Potential struct return " ^ string_of_id struct_id ^ " to " ^ string_of_id id);
begin match fix_updates_ret struct_id id instrs with
| None -> instr :: opt hr instrs
| Some updated -> opt hr updated
@@ -1811,6 +1859,7 @@ let fix_struct_updates ctx =
| CDEF_fundef (function_id, heap_return, args, body) ->
[CDEF_fundef (function_id, heap_return, args, opt heap_return body)]
| cdef -> [cdef]
+ *)
let concatMap f xs = List.concat (List.map f xs)
@@ -1818,7 +1867,7 @@ let optimize ctx cdefs =
let nothing cdefs = cdefs in
cdefs
|> (if !optimize_hoist_allocations then concatMap (hoist_allocations ctx) else nothing)
- |> (if !optimize_struct_updates then concatMap (fix_struct_updates ctx) else nothing)
+(* |> (if !optimize_struct_updates then concatMap (fix_struct_updates ctx) else nothing) *)
(**************************************************************************)
(* 6. Code generation *)
@@ -1878,22 +1927,22 @@ let sgen_cval_param (frag, ctyp) =
let sgen_cval = function (frag, _) -> string_of_fragment frag
let sgen_clexp = function
- | CL_id id -> "&" ^ sgen_id id
- | CL_field (id, field) -> "&(" ^ sgen_id id ^ "." ^ Util.zencode_string field ^ ")"
- | CL_addr id -> sgen_id id
- | CL_addr_field (id, field) -> "&(" ^ sgen_id id ^ "->" ^ Util.zencode_string field ^ ")"
+ | CL_id (id, _) -> "&" ^ sgen_id id
+ | CL_field (id, field, _) -> "&(" ^ sgen_id id ^ "." ^ Util.zencode_string field ^ ")"
+ | CL_addr (id, _) -> sgen_id id
+ | CL_addr_field (id, field, _) -> "&(" ^ sgen_id id ^ "->" ^ Util.zencode_string field ^ ")"
| CL_have_exception -> "have_exception"
- | CL_current_exception -> "current_exception"
+ | CL_current_exception _ -> "current_exception"
let sgen_clexp_pure = function
- | CL_id id -> sgen_id id
- | CL_field (id, field) -> sgen_id id ^ "." ^ Util.zencode_string field
- | CL_addr id -> "*" ^ sgen_id id
- | CL_addr_field (id, field) -> sgen_id id ^ "->" ^ Util.zencode_string field
+ | CL_id (id, _) -> sgen_id id
+ | CL_field (id, field, _) -> sgen_id id ^ "." ^ Util.zencode_string field
+ | CL_addr (id, _) -> "*" ^ sgen_id id
+ | CL_addr_field (id, field, _) -> sgen_id id ^ "->" ^ Util.zencode_string field
| CL_have_exception -> "have_exception"
- | CL_current_exception -> "current_exception"
+ | CL_current_exception _ -> "current_exception"
-let rec codegen_instr fid ctx (I_aux (instr, _)) =
+let rec codegen_instr fid ctx (I_aux (instr, (_, l))) =
match instr with
| I_decl (ctyp, id) when is_stack_ctyp ctyp ->
string (Printf.sprintf " %s %s;" (sgen_ctyp ctyp) (sgen_id id))
@@ -1902,11 +1951,30 @@ let rec codegen_instr fid ctx (I_aux (instr, _)) =
^^ string (Printf.sprintf " CREATE(%s)(&%s);" (sgen_ctyp_name ctyp) (sgen_id id))
| I_copy (clexp, cval) ->
- let ctyp = cval_ctyp cval in
- if is_stack_ctyp ctyp then
- string (Printf.sprintf " %s = %s;" (sgen_clexp_pure clexp) (sgen_cval cval))
+ let lctyp = clexp_ctyp clexp in
+ let rctyp = cval_ctyp cval in
+ if ctyp_equal lctyp rctyp then
+ if is_stack_ctyp lctyp then
+ string (Printf.sprintf " %s = %s;" (sgen_clexp_pure clexp) (sgen_cval cval))
+ else
+ string (Printf.sprintf " COPY(%s)(%s, %s);" (sgen_ctyp_name lctyp) (sgen_clexp clexp) (sgen_cval cval))
+ else if pointer_assign lctyp rctyp then
+ let lctyp = match lctyp with
+ | CT_ref lctyp -> lctyp
+ | _ -> assert false
+ in
+ if is_stack_ctyp lctyp then
+ string (Printf.sprintf " *(%s) = %s;" (sgen_clexp_pure clexp) (sgen_cval cval))
+ else
+ string (Printf.sprintf " COPY(%s)(*(%s), %s);" (sgen_ctyp_name lctyp) (sgen_clexp clexp) (sgen_cval cval))
else
- string (Printf.sprintf " COPY(%s)(%s, %s);" (sgen_ctyp_name ctyp) (sgen_clexp clexp) (sgen_cval cval))
+ if is_stack_ctyp lctyp then
+ string (Printf.sprintf " %s = CONVERT_OF(%s, %s)(%s);"
+ (sgen_clexp_pure clexp) (sgen_ctyp_name lctyp) (sgen_ctyp_name rctyp) (sgen_cval cval))
+ else
+ string (Printf.sprintf " CONVERT_OF(%s, %s)(%s, %s);"
+ (sgen_ctyp_name lctyp) (sgen_ctyp_name rctyp) (sgen_clexp clexp) (sgen_cval cval))
+
| I_jump (cval, label) ->
string (Printf.sprintf " if (%s) goto %s;" (sgen_cval cval) label)
| I_if (cval, [then_instr], [], ctyp) ->
@@ -1928,8 +1996,9 @@ let rec codegen_instr fid ctx (I_aux (instr, _)) =
string " { /* try */"
^^ jump 2 2 (separate_map hardline (codegen_instr fid ctx) instrs) ^^ hardline
^^ string " }"
- | I_funcall (x, extern, f, args, ctyp) ->
+ | I_funcall (x, extern, f, args) ->
let c_args = Util.string_of_list ", " sgen_cval args in
+ let ctyp = clexp_ctyp x in
let fname =
if Env.is_extern f ctx.tc_env "c" then
Env.get_extern f ctx.tc_env "c"
@@ -1975,10 +2044,11 @@ let rec codegen_instr fid ctx (I_aux (instr, _)) =
string (Printf.sprintf " %s = *(%s);" (sgen_clexp_pure x) c_args)
else
string (Printf.sprintf " COPY(%s)(&%s, *(%s));" (sgen_ctyp_name ctyp) (sgen_clexp_pure x) c_args)
- else if is_stack_ctyp ctyp then
- string (Printf.sprintf " %s = %s(%s);" (sgen_clexp_pure x) fname c_args)
else
- string (Printf.sprintf " %s(%s, %s);" fname (sgen_clexp x) c_args)
+ if is_stack_ctyp ctyp then
+ string (Printf.sprintf " %s = %s(%s);" (sgen_clexp_pure x) fname c_args)
+ else
+ string (Printf.sprintf " %s(%s, %s);" fname (sgen_clexp x) c_args)
| I_clear (ctyp, id) when is_stack_ctyp ctyp ->
empty
@@ -2009,70 +2079,54 @@ let rec codegen_instr fid ctx (I_aux (instr, _)) =
| I_reset (ctyp, id) ->
string (Printf.sprintf " RECREATE(%s)(&%s);" (sgen_ctyp_name ctyp) (sgen_id id))
- (* FIXME: This just covers the cases we see in our specs, need a
- special conversion code-generator for full generality *)
- | I_convert (x, CT_tup ctyps1, y, CT_tup ctyps2) when List.length ctyps1 = List.length ctyps2 ->
- let convert i (ctyp1, ctyp2) =
- if ctyp_equal ctyp1 ctyp2 then
- string (Printf.sprintf " %s.ztup%i = %s.ztup%i;" (sgen_clexp_pure x) i (sgen_id y) i)
- else if ctyp_equal ctyp1 ctyp2 then
- c_error "heap tuple type conversion"
- else if is_stack_ctyp ctyp1 then
- string (Printf.sprintf " %s.ztup%i = CONVERT_OF(%s, %s)(%s.ztup%i);"
- (sgen_clexp_pure x)
- i
- (sgen_ctyp_name ctyp1)
- (sgen_ctyp_name ctyp2)
- (sgen_id y)
- i)
- else
- string (Printf.sprintf " CONVERT_OF(%s, %s)(%s.ztup%i, %s.ztup%i);"
- (sgen_ctyp_name ctyp1)
- (sgen_ctyp_name ctyp2)
- (sgen_clexp x)
- i
- (sgen_id y)
- i)
- in
- separate hardline (List.mapi convert (List.map2 (fun x y -> (x, y)) ctyps1 ctyps2))
- (* If we're converting from a bits type with a known compile time
- length, pass it as an extra parameter to the conversion. *)
- | I_convert (x, ctyp1, y, (CT_bits64 (n, _) as ctyp2)) ->
- if is_stack_ctyp ctyp1 then
- string (Printf.sprintf " %s = CONVERT_OF(%s, %s)(%s, %d);"
- (sgen_clexp_pure x)
- (sgen_ctyp_name ctyp1)
- (sgen_ctyp_name ctyp2)
- (sgen_id y)
- n)
- else
- string (Printf.sprintf " CONVERT_OF(%s, %s)(%s, %s, %d);"
- (sgen_ctyp_name ctyp1)
- (sgen_ctyp_name ctyp2)
- (sgen_clexp x)
- (sgen_id y)
- n)
- | I_convert (x, ctyp1, y, ctyp2) ->
- if is_stack_ctyp ctyp1 then
- string (Printf.sprintf " %s = CONVERT_OF(%s, %s)(%s);"
- (sgen_clexp_pure x)
- (sgen_ctyp_name ctyp1)
- (sgen_ctyp_name ctyp2)
- (sgen_id y))
- else
- string (Printf.sprintf " CONVERT_OF(%s, %s)(%s, %s);"
- (sgen_ctyp_name ctyp1)
- (sgen_ctyp_name ctyp2)
- (sgen_clexp x)
- (sgen_id y))
| I_return cval ->
string (Printf.sprintf " return %s;" (sgen_cval cval))
+
| I_throw cval ->
c_error "I_throw reached code generator"
+
+ | I_undefined ctyp ->
+ let rec codegen_exn_return ctyp =
+ match ctyp with
+ | CT_unit -> "UNIT", []
+ | CT_bit -> "UINT64_C(0)", []
+ | CT_int64 -> "INT64_C(0xdeadc0de)", []
+ | CT_bits64 _ -> "UINT64_C(0xdeadc0de)", []
+ | CT_bool -> "false", []
+ | CT_enum (_, ctor :: _) -> sgen_id ctor, []
+ | CT_tup ctyps when is_stack_ctyp ctyp ->
+ let gs = gensym () in
+ let fold (inits, prev) (n, ctyp) =
+ let init, prev' = codegen_exn_return ctyp in
+ Printf.sprintf ".ztup%d = %s" n init :: inits, prev @ prev'
+ in
+ let inits, prev = List.fold_left fold ([], []) (List.mapi (fun i x -> (i, x)) ctyps) in
+ sgen_id gs,
+ [Printf.sprintf "struct %s %s = { " (sgen_ctyp_name ctyp) (sgen_id gs)
+ ^ Util.string_of_list ", " (fun x -> x) inits ^ " };"] @ prev
+ | CT_struct (id, ctors) when is_stack_ctyp ctyp ->
+ let gs = gensym () in
+ let fold (inits, prev) (id, ctyp) =
+ let init, prev' = codegen_exn_return ctyp in
+ Printf.sprintf ".%s = %s" (sgen_id id) init :: inits, prev @ prev'
+ in
+ let inits, prev = List.fold_left fold ([], []) ctors in
+ sgen_id gs,
+ [Printf.sprintf "struct %s %s = { " (sgen_ctyp_name ctyp) (sgen_id gs)
+ ^ Util.string_of_list ", " (fun x -> x) inits ^ " };"] @ prev
+ | ctyp -> c_error ("Cannot create undefined value for type: " ^ string_of_ctyp ctyp)
+ in
+ let ret, prev = codegen_exn_return ctyp in
+ separate_map hardline (fun str -> string (" " ^ str)) (List.rev prev)
+ ^^ hardline
+ ^^ string (Printf.sprintf " return %s;" ret)
+
| I_comment str ->
string (" /* " ^ str ^ " */")
+
| I_label str ->
string (str ^ ": ;")
+
| I_goto str ->
string (Printf.sprintf " goto %s;" str)
@@ -2084,17 +2138,26 @@ let rec codegen_instr fid ctx (I_aux (instr, _)) =
string (" sail_match_failure(\"" ^ String.escaped (string_of_id fid) ^ "\");")
let codegen_type_def ctx = function
- | CTD_enum (id, ids) ->
+ | CTD_enum (id, ((first_id :: _) as ids)) ->
let codegen_eq =
let name = sgen_id id in
string (Printf.sprintf "static bool eq_%s(enum %s op1, enum %s op2) { return op1 == op2; }" name name name)
in
+ let codegen_undefined =
+ let name = sgen_id id in
+ string (Printf.sprintf "enum %s UNDEFINED(%s)(unit u) { return %s; }" name name (upper_sgen_id first_id))
+ in
string (Printf.sprintf "// enum %s" (string_of_id id)) ^^ hardline
^^ separate space [string "enum"; codegen_id id; lbrace; separate_map (comma ^^ space) upper_codegen_id ids; rbrace ^^ semi]
^^ twice hardline
^^ codegen_eq
+ ^^ twice hardline
+ ^^ codegen_undefined
+
+ | CTD_enum (id, []) -> c_error ("Cannot compile empty enum " ^ string_of_id id)
| CTD_struct (id, ctors) ->
+ let struct_ctyp = CT_struct (id, ctors) in
(* Generate a set_T function for every struct T *)
let codegen_set (id, ctyp) =
if is_stack_ctyp ctyp then
@@ -2143,12 +2206,14 @@ let codegen_type_def ctx = function
rbrace
^^ semi ^^ twice hardline
^^ codegen_setter id (ctor_bindings ctors)
- ^^ twice hardline
- ^^ codegen_init "CREATE" id (ctor_bindings ctors)
- ^^ twice hardline
- ^^ codegen_init "RECREATE" id (ctor_bindings ctors)
- ^^ twice hardline
- ^^ codegen_init "KILL" id (ctor_bindings ctors)
+ ^^ (if not (is_stack_ctyp struct_ctyp) then
+ twice hardline
+ ^^ codegen_init "CREATE" id (ctor_bindings ctors)
+ ^^ twice hardline
+ ^^ codegen_init "RECREATE" id (ctor_bindings ctors)
+ ^^ twice hardline
+ ^^ codegen_init "KILL" id (ctor_bindings ctors)
+ else empty)
^^ twice hardline
^^ codegen_eq
@@ -2209,7 +2274,10 @@ let codegen_type_def ctx = function
| CT_tup ctyps ->
String.concat ", " (List.mapi (fun i ctyp -> Printf.sprintf "%s op%d" (sgen_ctyp ctyp) i) ctyps),
string (Printf.sprintf "%s op;" (sgen_ctyp ctyp)) ^^ hardline
- ^^ string (Printf.sprintf "CREATE(%s)(&op);" (sgen_ctyp_name ctyp)) ^^ hardline
+ ^^ if not (is_stack_ctyp ctyp) then
+ string (Printf.sprintf "CREATE(%s)(&op);" (sgen_ctyp_name ctyp)) ^^ hardline
+ else
+ empty
^^ separate hardline (List.mapi tuple_set ctyps) ^^ hardline
| ctyp -> Printf.sprintf "%s op" (sgen_ctyp ctyp), empty
in
@@ -2651,12 +2719,12 @@ let sgen_finish = function
Printf.sprintf " finish_%s();" (sgen_id id)
| _ -> assert false
+ (*
let instrument_tracing ctx =
let module StringSet = Set.Make(String) in
let traceable = StringSet.of_list ["mach_bits"; "sail_string"; "sail_bits"; "sail_int"; "unit"; "bool"] in
let rec instrument = function
- | (I_aux (I_funcall (clexp, _, id, args, ctyp), _) as instr) :: instrs when not (Env.is_extern id ctx.tc_env "c") ->
-
+ | (I_aux (I_funcall (clexp, _, id, args), _) as instr) :: instrs ->
let trace_start =
iraw (Printf.sprintf "trace_start(\"%s\");" (String.escaped (string_of_id id)))
in
@@ -2702,6 +2770,7 @@ let instrument_tracing ctx =
| CDEF_fundef (function_id, heap_return, args, body) ->
CDEF_fundef (function_id, heap_return, args, instrument body)
| cdef -> cdef
+ *)
let bytecode_ast ctx rewrites (Defs defs) =
let assert_vs = Initial_check.extern_of_string dec_ord (mk_id "sail_assert") "(bool, string) -> unit effect {escape}" in
@@ -2753,8 +2822,9 @@ let compile_ast ctx (Defs defs) =
let cdefs = List.concat (List.rev chunks) in
let cdefs = optimize ctx cdefs in
+ (*
let cdefs = if !opt_trace then List.map (instrument_tracing ctx) cdefs else cdefs in
-
+ *)
let docs = List.map (codegen_def ctx) cdefs in
let preamble = separate hardline