4794045208
I introduced a notion of extended values in Obc expressions, replacing the Epattern constructor. Patterns may now only occur at their rightful place, on the left of an assignment. This change allows to index global constant arrays.
685 lines
28 KiB
OCaml
685 lines
28 KiB
OCaml
(**************************************************************************)
|
|
(* *)
|
|
(* Heptagon *)
|
|
(* *)
|
|
(* Author : Marc Pouzet *)
|
|
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
|
|
(* *)
|
|
(**************************************************************************)
|
|
|
|
(* Translation from Minils to Obc. *)
|
|
open Misc
|
|
open Names
|
|
open Idents
|
|
open Clocks
|
|
open Signature
|
|
open Obc
|
|
open Obc_utils
|
|
open Obc_mapfold
|
|
open Types
|
|
open Static
|
|
open Initial
|
|
|
|
|
|
let build_anon, find_anon =
|
|
let anon_nodes = ref QualEnv.empty in
|
|
let build_anon nodes =
|
|
let build env nd = match nd with
|
|
| Minils.Pnode nd ->
|
|
if Itfusion.is_anon_node nd.Minils.n_name
|
|
then QualEnv.add nd.Minils.n_name nd env
|
|
else env
|
|
| _ -> env
|
|
in
|
|
anon_nodes := List.fold_left build QualEnv.empty nodes
|
|
in
|
|
let find_anon qn = QualEnv.find qn !anon_nodes in
|
|
build_anon, find_anon
|
|
|
|
let var_from_name map x =
|
|
begin try
|
|
Env.find x map
|
|
with
|
|
_ -> assert false
|
|
end
|
|
|
|
let ext_value_exp_from_name map x =
|
|
let w = ext_value_of_pattern (var_from_name map x) in
|
|
mk_exp w.w_ty (Eextvalue w)
|
|
|
|
(* let lvar_from_name map ty x = mk_pattern ty (Lvar (var_from_name map x)) *)
|
|
|
|
let fresh_it () =
|
|
let id = Idents.gen_var "mls2obc" "i" in
|
|
id, mk_var_dec id Initial.tint
|
|
|
|
let gen_obj_ident n = Idents.gen_var "mls2obc" ((shortname n) ^ "_inst")
|
|
let fresh_for = fresh_for "mls2obc"
|
|
(*let copy_array = copy_array "mls2obc"*)
|
|
|
|
let op_from_string op = { qual = Pervasives; name = op; }
|
|
|
|
let rec pattern_of_idx_list p l =
|
|
let rec aux p l = match p.pat_ty, l with
|
|
| _, [] -> p
|
|
| Tarray (ty',_), idx :: l -> aux (mk_pattern ty' (Larray (p, idx))) l
|
|
| _ -> internal_error "mls2obc" 1
|
|
in
|
|
aux p l
|
|
|
|
let rec extvalue_of_idx_list w l = match w.w_ty, l with
|
|
| _, [] -> w
|
|
| Tarray (ty',_), idx :: l ->
|
|
extvalue_of_idx_list (mk_ext_value ty' (Warray (w, idx))) l
|
|
| _ -> internal_error "mls2obc" 1
|
|
|
|
let rec ext_value_of_trunc_idx_list p l =
|
|
let mk_between idx se =
|
|
mk_exp_int (Eop (mk_pervasives "between", [idx; mk_ext_value_exp se.se_ty (Wconst se)]))
|
|
in
|
|
let rec aux p l = match p.w_ty, l with
|
|
| _, [] -> p
|
|
| Tarray (ty', se), idx :: l -> aux (mk_ext_value ty' (Warray (p, mk_between idx se))) l
|
|
| _ -> internal_error "mls2obc" 1
|
|
in
|
|
aux p l
|
|
|
|
let array_elt_of_exp idx e =
|
|
match e.e_desc, Modules.unalias_type e.e_ty with
|
|
| Eextvalue { w_desc = Wconst { se_desc = Sarray_power (c, _); _ }; }, Tarray (ty,_) -> mk_ext_value_exp ty (Wconst c)
|
|
| _, Tarray (ty,_) ->
|
|
mk_ext_value_exp ty (Warray(ext_value_of_exp e, idx))
|
|
| _ -> internal_error "mls2obc" 2
|
|
|
|
(** Creates the expression that checks that the indices
|
|
in idx_list are in the bounds. If idx_list=[e1;..;ep]
|
|
and bounds = [n1;..;np], it returns
|
|
0<= e1 < n1 && .. && 0 <= ep < np *)
|
|
let rec bound_check_expr idx_list bounds =
|
|
let mk_comp idx n =
|
|
let e1 = mk_exp_bool (Eop (op_from_string "<",
|
|
[idx; mk_ext_value_exp_int (Wconst n)])) in
|
|
let e2 = mk_exp_bool (Eop (op_from_string "<=",
|
|
[mk_ext_value_exp_int (Wconst (mk_static_int 0)); idx])) in
|
|
mk_exp_bool (Eop (op_from_string "&", [e1;e2]))
|
|
in
|
|
match (idx_list, bounds) with
|
|
| [idx], n::_ -> mk_comp idx n
|
|
| (idx :: idx_list, n :: bounds) ->
|
|
let e = mk_comp idx n in
|
|
mk_exp_bool (Eop (op_from_string "&",
|
|
[e; bound_check_expr idx_list bounds]))
|
|
| (_, _) -> internal_error "mls2obc" 3
|
|
|
|
let mk_plus_one e = match e.e_desc with
|
|
| Eextvalue ({ w_desc = Wconst idx; _ } as w) ->
|
|
let idx_plus_one = mk_static_int_op (mk_pervasives "+") [idx; mk_static_int 1] in
|
|
{ e with e_desc = Eextvalue { w with w_desc = Wconst idx_plus_one; }; }
|
|
| _ ->
|
|
let idx_plus_one = Eop (mk_pervasives "+", [e; mk_exp_const_int 1]) in
|
|
{ e with e_desc = idx_plus_one }
|
|
|
|
(** Creates the action list that copies [src] to [dest],
|
|
updating the value at index [idx_list] with the value [v]. *)
|
|
let rec update_array dest src idx_list v = match dest.pat_ty, idx_list with
|
|
| Tarray (t, n), idx::idx_list ->
|
|
(*Body of the copy loops*)
|
|
let copy i =
|
|
let src_i = array_elt_of_exp i src in
|
|
let dest_i = mk_pattern t (Larray (dest, i)) in
|
|
[Aassgn(dest_i, src_i)]
|
|
in
|
|
(*Copy values < idx*)
|
|
let a_lower = fresh_for (mk_exp_const_int 0) idx copy in
|
|
(* Update the correct element*)
|
|
let src_idx = array_elt_of_exp idx src in
|
|
let dest_idx = mk_pattern t (Larray (dest, idx)) in
|
|
let a_update = update_array dest_idx src_idx idx_list v in
|
|
(*Copy values > idx*)
|
|
let idx_plus_one = mk_plus_one idx in
|
|
let a_upper = fresh_for idx_plus_one (mk_exp_static_int n) copy in
|
|
[a_lower] @ a_update @ [a_upper]
|
|
| _, _ ->
|
|
[Aassgn(dest, v)]
|
|
|
|
(** Creates the action list that copies [src] to [dest],
|
|
updating the value of field [f] with the value [v]. *)
|
|
let update_record dest src f v =
|
|
let assgn_act { f_name = l; f_type = ty } =
|
|
let dest_l = mk_pattern ty (Lfield(dest, l)) in
|
|
let src_l = mk_ext_value_exp ty (Wfield(src, l)) in
|
|
if f = l then
|
|
Aassgn(dest_l, v)
|
|
else
|
|
Aassgn(dest_l, src_l)
|
|
in
|
|
let fields = match dest.pat_ty with
|
|
| Tid n -> Modules.find_struct n
|
|
| _ -> Misc.internal_error "mls2obc field of nonstruct" 1
|
|
in
|
|
List.map assgn_act fields
|
|
|
|
let rec control map ck s = match ck with
|
|
| Cbase | Cvar { contents = Cindex _ } -> s
|
|
| Cvar { contents = Clink ck } -> control map ck s
|
|
| Con(ck, c, n) ->
|
|
let x = ext_value_exp_from_name map n in
|
|
control map ck (Acase(x, [(c, mk_block [s])]))
|
|
|
|
let reinit o =
|
|
Acall ([], o, Mreset, [])
|
|
|
|
let rec translate_pat map ty pat = match pat, ty with
|
|
| Minils.Evarpat x, _ -> [ var_from_name map x ]
|
|
| Minils.Etuplepat pat_list, Tprod ty_l ->
|
|
List.fold_right2 (fun ty pat acc -> (translate_pat map ty pat) @ acc)
|
|
ty_l pat_list []
|
|
| Minils.Etuplepat _, _ -> Misc.internal_error "Ill-typed pattern" 0
|
|
|
|
let translate_var_dec l =
|
|
let one_var { Minils.v_ident = x; Minils.v_type = t; v_loc = loc } =
|
|
mk_var_dec ~loc:loc x t
|
|
in
|
|
List.map one_var l
|
|
|
|
let rec translate_extvalue map w = match w.Minils.w_desc with
|
|
| Minils.Wvar x -> ext_value_of_pattern (var_from_name map x)
|
|
| _ ->
|
|
let desc = match w.Minils.w_desc with
|
|
| Minils.Wconst v -> Wconst v
|
|
| Minils.Wvar x -> assert false
|
|
| Minils.Wfield (w1, f) -> Wfield (translate_extvalue map w1, f)
|
|
| Minils.Wwhen (w1, c, x) -> (translate_extvalue map w1).w_desc
|
|
in
|
|
mk_ext_value w.Minils.w_ty desc
|
|
|
|
and translate_extvalue_to_exp map w =
|
|
mk_exp ~loc:w.Minils.w_loc w.Minils.w_ty (Eextvalue (translate_extvalue map w))
|
|
|
|
(* [translate e = c] *)
|
|
let rec translate map e =
|
|
let desc = match e.Minils.e_desc with
|
|
| Minils.Eextvalue w ->
|
|
let w = translate_extvalue map w in Eextvalue w
|
|
| Minils.Eapp ({ Minils.a_op = Minils.Eequal }, w_list, _) ->
|
|
Eop (op_from_string "=", List.map (translate_extvalue_to_exp map) w_list)
|
|
| Minils.Eapp ({ Minils.a_op = Minils.Efun n }, e_list, _)
|
|
when Mls_utils.is_op n ->
|
|
Eop (n, List.map (translate_extvalue_to_exp map ) e_list)
|
|
| Minils.Estruct f_e_list ->
|
|
let type_name = (match e.Minils.e_ty with
|
|
| Tid name -> name
|
|
| _ -> assert false) in
|
|
let f_e_list = List.map
|
|
(fun (f, e) -> (f, (translate_extvalue_to_exp map e))) f_e_list in
|
|
Estruct (type_name, f_e_list)
|
|
(*Remaining array operators*)
|
|
| Minils.Eapp ({ Minils.a_op = Minils.Earray }, e_list, _) ->
|
|
Earray (List.map (translate_extvalue_to_exp map ) e_list)
|
|
| Minils.Eapp ({ Minils.a_op = Minils.Eselect;
|
|
Minils.a_params = idx_list }, e_list, _) ->
|
|
let e = translate_extvalue map (assert_1 e_list) in
|
|
let idx_list = List.map mk_exp_static_int idx_list in
|
|
Eextvalue (extvalue_of_idx_list e idx_list)
|
|
(* Already treated cases when translating the [eq] *)
|
|
| Minils.Eiterator _ | Minils.Emerge _ | Minils.Efby _
|
|
| Minils.Eapp ({Minils.a_op=(Minils.Enode _|Minils.Efun _|Minils.Econcat
|
|
|Minils.Eupdate|Minils.Eselect_dyn
|
|
|Minils.Eselect_trunc|Minils.Eselect_slice
|
|
|Minils.Earray_fill|Minils.Efield_update
|
|
|Minils.Eifthenelse)}, _, _) ->
|
|
internal_error "mls2obc" 5
|
|
in
|
|
mk_exp e.Minils.e_ty desc
|
|
|
|
and translate_act_extvalue map pat w =
|
|
match pat with
|
|
| Minils.Evarpat n ->
|
|
[Aassgn (var_from_name map n, translate_extvalue_to_exp map w)]
|
|
| _ -> assert false
|
|
|
|
(* [translate pat act = si, d] *)
|
|
and translate_act map pat
|
|
({ Minils.e_desc = desc } as act) =
|
|
match pat, desc with
|
|
(* When Merge *)
|
|
| Minils.Evarpat x, Minils.Emerge (y, c_act_list) ->
|
|
let x = var_from_name map x in
|
|
let translate_c_extvalue (c, w) =
|
|
c, mk_block [Aassgn (x, translate_extvalue_to_exp map w)]
|
|
in
|
|
|
|
[Acase (ext_value_exp_from_name map y,
|
|
List.map translate_c_extvalue c_act_list)]
|
|
(* Array ops *)
|
|
| Minils.Evarpat x,
|
|
Minils.Eapp ({ Minils.a_op = Minils.Econcat }, [e1; e2], _) ->
|
|
let cpt1, cpt1d = fresh_it () in
|
|
let cpt2, cpt2d = fresh_it () in
|
|
let x = var_from_name map x in
|
|
let t = x.pat_ty in
|
|
(match e1.Minils.w_ty, e2.Minils.w_ty with
|
|
| Tarray (t1, n1), Tarray (t2, n2) ->
|
|
let e1 = translate_extvalue_to_exp map e1 in
|
|
let e2 = translate_extvalue_to_exp map e2 in
|
|
let a1 =
|
|
Afor (cpt1d, mk_exp_const_int 0, mk_exp_static_int n1,
|
|
mk_block [Aassgn (mk_pattern t1 (Larray (x, mk_evar_int cpt1)),
|
|
array_elt_of_exp (mk_evar_int cpt1) e1)] ) in
|
|
let idx = mk_exp_int (Eop (op_from_string "+",
|
|
[ mk_exp_static_int n1; mk_evar_int cpt2])) in
|
|
let p2 = array_elt_of_exp (mk_evar_int cpt2) e2 in
|
|
let a2 = Afor (cpt2d, mk_exp_const_int 0, mk_exp_static_int n2,
|
|
mk_block [Aassgn (mk_pattern t2 (Larray (x, idx)), p2)] )
|
|
in
|
|
[a1; a2]
|
|
| _ -> assert false)
|
|
|
|
| Minils.Evarpat x,
|
|
Minils.Eapp ({ Minils.a_op = Minils.Earray_fill; Minils.a_params = n_list }, [e], _) ->
|
|
let e = translate_extvalue_to_exp map e in
|
|
let x = var_from_name map x in
|
|
let t = match x.pat_ty with
|
|
| Tarray (t,_) -> t
|
|
| _ -> Misc.internal_error "mls2obc select slice type" 5
|
|
in
|
|
|
|
let rec make_loop power_list replace = match power_list with
|
|
| [] -> x, replace
|
|
| p :: power_list ->
|
|
let cpt, cptd = fresh_it () in
|
|
let e, replace =
|
|
make_loop power_list
|
|
(fun y -> [Afor (cptd, mk_exp_const_int 0,
|
|
mk_exp_static_int p, mk_block (replace y))]) in
|
|
let e = Larray (e, mk_evar_int cpt) in
|
|
(mk_pattern t e, replace)
|
|
in
|
|
let e, b = make_loop n_list (fun y -> [Aassgn (y, e)]) in
|
|
b e
|
|
|
|
| Minils.Evarpat x,
|
|
Minils.Eapp ({ Minils.a_op = Minils.Eselect_slice;
|
|
Minils.a_params = [idx1; idx2] }, [e], _) ->
|
|
let cpt, cptd = fresh_it () in
|
|
let e = translate_extvalue_to_exp map e in
|
|
let x = var_from_name map x in
|
|
let t = match x.pat_ty with
|
|
| Tarray (t,_) -> t
|
|
| _ -> Misc.internal_error "mls2obc select slice type" 5
|
|
in
|
|
let idx = mk_exp_int (Eop (op_from_string "+",
|
|
[mk_evar_int cpt; mk_exp_static_int idx1 ])) in
|
|
(* bound = (idx2 - idx1) + 1*)
|
|
let bound = mk_static_int_op (op_from_string "+")
|
|
[ mk_static_int 1; mk_static_int_op (op_from_string "-") [idx2;idx1] ] in
|
|
[ Afor (cptd, mk_exp_const_int 0, mk_exp_static_int bound,
|
|
mk_block [Aassgn (mk_pattern t (Larray (x, mk_evar_int cpt)),
|
|
array_elt_of_exp idx e)] ) ]
|
|
|
|
| Minils.Evarpat x, Minils.Eapp ({ Minils.a_op = Minils.Eselect_dyn }, e1::e2::idx, _) ->
|
|
let x = var_from_name map x in
|
|
let bounds = Mls_utils.bounds_list e1.Minils.w_ty in
|
|
let e1 = translate_extvalue map e1 in
|
|
let idx = List.map (translate_extvalue_to_exp map) idx in
|
|
let w = extvalue_of_idx_list e1 idx in
|
|
let true_act = Aassgn (x, mk_exp w.w_ty (Eextvalue w)) in
|
|
let false_act = Aassgn (x, translate_extvalue_to_exp map e2) in
|
|
let cond = bound_check_expr idx bounds in
|
|
[ mk_ifthenelse cond [true_act] [false_act] ]
|
|
|
|
| Minils.Evarpat x, Minils.Eapp ({ Minils.a_op = Minils.Eselect_trunc }, e1::idx, _) ->
|
|
let x = var_from_name map x in
|
|
let bounds = Mls_utils.bounds_list e1.Minils.w_ty in
|
|
let e1 = translate_extvalue map e1 in
|
|
let idx = List.map (translate_extvalue_to_exp map) idx in
|
|
let w = ext_value_of_trunc_idx_list e1 idx in
|
|
[Aassgn (x, mk_exp w.w_ty (Eextvalue w))]
|
|
|
|
| Minils.Evarpat x, Minils.Eapp ({ Minils.a_op = Minils.Eupdate }, e1::e2::idx, _) ->
|
|
let x = var_from_name map x in
|
|
let bounds = Mls_utils.bounds_list e1.Minils.w_ty in
|
|
let idx = List.map (translate_extvalue_to_exp map) idx in
|
|
let e1 = translate_extvalue_to_exp map e1 in
|
|
let e2 = translate_extvalue_to_exp map e2 in
|
|
let cond = bound_check_expr idx bounds in
|
|
let true_act = update_array x e1 idx e2 in
|
|
let false_act = Aassgn (x, e1) in
|
|
[ mk_ifthenelse cond true_act [false_act] ]
|
|
|
|
| Minils.Evarpat x,
|
|
Minils.Eapp ({ Minils.a_op = Minils.Efield_update;
|
|
Minils.a_params = [{ se_desc = Sfield f }] }, [e1; e2], _) ->
|
|
let x = var_from_name map x in
|
|
let e1 = translate_extvalue map e1 in
|
|
let e2 = translate_extvalue_to_exp map e2 in
|
|
update_record x e1 f e2
|
|
|
|
| Minils.Evarpat n, _ ->
|
|
[Aassgn (var_from_name map n, translate map act)]
|
|
| _ ->
|
|
Format.eprintf "%a The pattern %a should be a simple var to be translated to obc.@."
|
|
Location.print_location act.Minils.e_loc Mls_printer.print_pat pat;
|
|
assert false
|
|
|
|
(** In an iteration, objects used are element of object arrays *)
|
|
type obj_array = { oa_index : Obc.pattern; oa_size : static_exp }
|
|
|
|
(** A [None] context is normal, otherwise, we are in an iteration *)
|
|
type call_context = obj_array option
|
|
|
|
let mk_obj_call_from_context c n = match c with
|
|
| None -> Oobj n
|
|
| Some oa -> Oarray (n, oa.oa_index)
|
|
|
|
let size_from_call_context c = match c with
|
|
| None -> None
|
|
| Some oa -> Some (oa.oa_size)
|
|
|
|
let empty_call_context = None
|
|
|
|
(** [si] the initialization actions used in the reset method,
|
|
[j] obj decs
|
|
[s] the actions used in the step method.
|
|
[v] var decs *)
|
|
let rec translate_eq map call_context { Minils.eq_lhs = pat; Minils.eq_rhs = e }
|
|
(v, si, j, s) =
|
|
let { Minils.e_desc = desc; Minils.e_ck = ck; Minils.e_loc = loc } = e in
|
|
match (pat, desc) with
|
|
| Minils.Evarpat n, Minils.Efby (opt_c, e) ->
|
|
let x = var_from_name map n in
|
|
let si = (match opt_c with
|
|
| None -> si
|
|
| Some c -> (Aassgn (x, mk_ext_value_static x.pat_ty c)) :: si) in
|
|
let action = Aassgn (var_from_name map n, translate_extvalue_to_exp map e) in
|
|
v, si, j, (control map ck action) :: s
|
|
(* should be unnecessary
|
|
| Minils.Etuplepat p_list,
|
|
Minils.Eapp({ Minils.a_op = Minils.Etuple }, act_list, _) ->
|
|
List.fold_right2
|
|
(fun pat e ->
|
|
translate_eq map call_context
|
|
(Minils.mk_equation pat e))
|
|
p_list act_list (v, si, j, s)
|
|
*)
|
|
| pat, Minils.Eapp({ Minils.a_op = Minils.Eifthenelse }, [e1;e2;e3], _) ->
|
|
let cond = translate_extvalue_to_exp map e1 in
|
|
let true_act = translate_act_extvalue map pat e2 in
|
|
let false_act = translate_act_extvalue map pat e3 in
|
|
let action = mk_ifthenelse cond true_act false_act in
|
|
v, si, j, (control map ck action) :: s
|
|
|
|
| pat, Minils.Eapp ({ Minils.a_op = Minils.Efun _ | Minils.Enode _ } as app, e_list, r) ->
|
|
let name_list = translate_pat map e.Minils.e_ty pat in
|
|
let c_list = List.map (translate_extvalue_to_exp map) e_list in
|
|
let v', si', j', action = mk_node_call map call_context
|
|
app loc name_list c_list e.Minils.e_ty in
|
|
let action = List.map (control map ck) action in
|
|
let s = (match r, app.Minils.a_op with
|
|
| Some r, Minils.Enode _ ->
|
|
let ck = Clocks.Con (ck, Initial.ptrue, r) in
|
|
let ra = List.map (control map ck) si' in
|
|
ra @ action @ s
|
|
| _, _ -> action @ s) in
|
|
v' @ v, si'@si, j'@j, s
|
|
|
|
| pat, Minils.Eiterator (it, app, n, pe_list, e_list, reset) ->
|
|
let name_list = translate_pat map e.Minils.e_ty pat in
|
|
let p_list = List.map (translate_extvalue_to_exp map) pe_list in
|
|
let c_list = List.map (translate_extvalue_to_exp map) e_list in
|
|
let x, xd = fresh_it () in
|
|
let call_context =
|
|
Some { oa_index = mk_pattern_int (Lvar x); oa_size = n} in
|
|
let n = mk_exp_static_int n in
|
|
let si', j', action = translate_iterator map call_context it
|
|
name_list app loc n x xd p_list c_list e.Minils.e_ty in
|
|
let action = List.map (control map ck) action in
|
|
let s =
|
|
(match reset, app.Minils.a_op with
|
|
| Some r, Minils.Enode _ ->
|
|
let ck = Clocks.Con (ck, Initial.ptrue, r) in
|
|
let ra = List.map (control map ck) si' in
|
|
ra @ action @ s
|
|
| _, _ -> action @ s)
|
|
in (v, si' @ si, j' @ j, s)
|
|
|
|
| (pat, _) ->
|
|
let action = translate_act map pat e in
|
|
let action = List.map (control map ck) action in
|
|
v, si, j, action @ s
|
|
|
|
and translate_eq_list map call_context act_list =
|
|
List.fold_right (translate_eq map call_context) act_list ([], [], [], [])
|
|
|
|
and mk_node_call map call_context app loc (name_list : Obc.pattern list) args ty =
|
|
match app.Minils.a_op with
|
|
| Minils.Efun f when Mls_utils.is_op f ->
|
|
let act = match name_list with
|
|
| [] -> Aop (f, args)
|
|
| [name] ->
|
|
let e = mk_exp ty (Eop(f, args)) in
|
|
Aassgn (name, e)
|
|
| _ ->
|
|
Misc.unsupported "mls2obc: external function with multiple return values" 1 in
|
|
[], [], [], [act]
|
|
|
|
| Minils.Enode f when Itfusion.is_anon_node f ->
|
|
let add_input env vd =
|
|
Env.add vd.Minils.v_ident
|
|
(mk_pattern vd.Minils.v_type (Lvar vd.Minils.v_ident)) env in
|
|
let build env vd a = Env.add vd.Minils.v_ident a env in
|
|
let subst_act_list env act_list =
|
|
let exp funs env e = match e.e_desc with
|
|
| Eextvalue { w_desc = Wvar x } ->
|
|
let e =
|
|
(try Env.find x env
|
|
with Not_found -> e) in
|
|
e, env
|
|
| _ -> Obc_mapfold.exp funs env e
|
|
in
|
|
let funs = { Obc_mapfold.defaults with exp = exp } in
|
|
let act_list, _ = mapfold (Obc_mapfold.act_it funs) env act_list in
|
|
act_list
|
|
in
|
|
|
|
let nd = find_anon f in
|
|
let map = List.fold_left add_input map nd.Minils.n_input in
|
|
let map = List.fold_left2 build map nd.Minils.n_output name_list in
|
|
let map = List.fold_left add_input map nd.Minils.n_local in
|
|
let v, si, j, s = translate_eq_list map call_context nd.Minils.n_equs in
|
|
let env = List.fold_left2 build Env.empty nd.Minils.n_input args in
|
|
v @ nd.Minils.n_local, si, j, subst_act_list env s
|
|
|
|
| Minils.Enode f | Minils.Efun f ->
|
|
let o = mk_obj_call_from_context call_context (gen_obj_ident f) in
|
|
let obj =
|
|
{ o_ident = obj_ref_name o; o_class = f;
|
|
o_params = app.Minils.a_params;
|
|
o_size = size_from_call_context call_context; o_loc = loc } in
|
|
let si = (match app.Minils.a_op with
|
|
| Minils.Efun _ -> []
|
|
| Minils.Enode _ -> [reinit o]
|
|
| _ -> assert false) in
|
|
let s = [Acall (name_list, o, Mstep, args)] in
|
|
[], si, [obj], s
|
|
| _ -> assert false
|
|
|
|
and translate_iterator map call_context it name_list
|
|
app loc n x xd p_list c_list ty =
|
|
let unarray ty = match ty with
|
|
| Tarray (t,_) -> t
|
|
| _ ->
|
|
Format.eprintf "%a" Global_printer.print_type ty;
|
|
internal_error "mls2obc" 6
|
|
in
|
|
let array_of_output name_list ty_list =
|
|
List.map2 (fun l ty -> mk_pattern ty (Larray (l, mk_evar_int x))) name_list ty_list
|
|
in
|
|
let array_of_input c_list =
|
|
List.map (array_elt_of_exp (mk_evar_int x)) c_list in
|
|
match it with
|
|
| Minils.Imap ->
|
|
let c_list = array_of_input c_list in
|
|
let ty_list = List.map unarray (Types.unprod ty) in
|
|
let name_list = array_of_output name_list ty_list in
|
|
let node_out_ty = Types.prod ty_list in
|
|
let v, si, j, action = mk_node_call map call_context
|
|
app loc name_list (p_list@c_list) node_out_ty in
|
|
let v = translate_var_dec v in
|
|
let b = mk_block ~locals:v action in
|
|
let bi = mk_block si in
|
|
[Afor (xd, mk_exp_const_int 0, n, bi)], j,
|
|
[Afor (xd, mk_exp_const_int 0, n, b)]
|
|
|
|
| Minils.Imapi ->
|
|
let c_list = array_of_input c_list in
|
|
let ty_list = List.map unarray (Types.unprod ty) in
|
|
let name_list = array_of_output name_list ty_list in
|
|
let node_out_ty = Types.prod ty_list in
|
|
let v, si, j, action = mk_node_call map call_context
|
|
app loc name_list (p_list@c_list@[mk_evar_int x]) node_out_ty in
|
|
let v = translate_var_dec v in
|
|
let b = mk_block ~locals:v action in
|
|
let bi = mk_block si in
|
|
[Afor (xd, mk_exp_const_int 0, n, bi)], j,
|
|
[Afor (xd, mk_exp_const_int 0, n, b)]
|
|
|
|
| Minils.Imapfold ->
|
|
let (c_list, acc_in) = split_last c_list in
|
|
let c_list = array_of_input c_list in
|
|
let ty_list = Misc.map_butlast unarray (Types.unprod ty) in
|
|
let ty_name_list, ty_acc_out = Misc.split_last ty_list in
|
|
let (name_list, acc_out) = Misc.split_last name_list in
|
|
let name_list = array_of_output name_list ty_name_list in
|
|
let node_out_ty = Types.prod ty_list in
|
|
let v, si, j, action = mk_node_call map call_context app loc
|
|
(name_list @ [ acc_out ])
|
|
(p_list @ c_list @ [ exp_of_pattern acc_out ])
|
|
node_out_ty
|
|
in
|
|
let v = translate_var_dec v in
|
|
let b = mk_block ~locals:v action in
|
|
let bi = mk_block si in
|
|
[Afor (xd, mk_exp_const_int 0, n, bi)], j,
|
|
[Aassgn (acc_out, acc_in); Afor (xd, mk_exp_const_int 0, n, b)]
|
|
|
|
| Minils.Ifold ->
|
|
let (c_list, acc_in) = split_last c_list in
|
|
let c_list = array_of_input c_list in
|
|
let acc_out = last_element name_list in
|
|
let v, si, j, action =
|
|
mk_node_call map call_context app loc name_list
|
|
(p_list @ c_list @ [ exp_of_pattern acc_out ]) ty
|
|
in
|
|
let v = translate_var_dec v in
|
|
let b = mk_block ~locals:v action in
|
|
let bi = mk_block si in
|
|
[Afor (xd, mk_exp_const_int 0, n, bi)], j,
|
|
[ Aassgn (acc_out, acc_in); Afor (xd, mk_exp_const_int 0, n, b) ]
|
|
|
|
| Minils.Ifoldi ->
|
|
let (c_list, acc_in) = split_last c_list in
|
|
let c_list = array_of_input c_list in
|
|
let acc_out = last_element name_list in
|
|
let v, si, j, action = mk_node_call map call_context app loc name_list
|
|
(p_list @ c_list @ [ mk_evar_int x; exp_of_pattern acc_out ]) ty
|
|
in
|
|
let v = translate_var_dec v in
|
|
let b = mk_block ~locals:v action in
|
|
let bi = mk_block si in
|
|
[Afor (xd, mk_exp_const_int 0, n, bi)], j,
|
|
[ Aassgn (acc_out, acc_in); Afor (xd, mk_exp_const_int 0, n, b) ]
|
|
|
|
let remove m d_list =
|
|
List.filter (fun { Minils.v_ident = n } -> not (List.mem_assoc n m)) d_list
|
|
|
|
let translate_contract map mem_var_tys =
|
|
function
|
|
| None -> ([], [], [], [])
|
|
| Some
|
|
{
|
|
Minils.c_eq = eq_list;
|
|
Minils.c_local = d_list;
|
|
} ->
|
|
let (v, si, j, s_list) = translate_eq_list map empty_call_context eq_list in
|
|
let d_list = translate_var_dec (v @ d_list) in
|
|
let d_list = List.filter
|
|
(fun vd -> not (List.exists (fun (i,_) -> i = vd.v_ident) mem_var_tys)) d_list in
|
|
(si, j, s_list, d_list)
|
|
|
|
(** Returns a map, mapping variables names to the variables
|
|
where they will be stored. *)
|
|
let subst_map inputs outputs locals mem_tys =
|
|
(* Create a map that simply maps each var to itself *)
|
|
let map =
|
|
List.fold_left
|
|
(fun m { Minils.v_ident = x; Minils.v_type = ty } -> Env.add x (mk_pattern ty (Lvar x)) m)
|
|
Env.empty (inputs @ outputs @ locals)
|
|
in
|
|
List.fold_left (fun map (x, x_ty) -> Env.add x (mk_pattern x_ty (Lmem x)) map) map mem_tys
|
|
|
|
let translate_node
|
|
({ Minils.n_name = f; Minils.n_input = i_list; Minils.n_output = o_list;
|
|
Minils.n_local = d_list; Minils.n_equs = eq_list; Minils.n_stateful = stateful;
|
|
Minils.n_contract = contract; Minils.n_params = params; Minils.n_loc = loc;
|
|
} as n) =
|
|
Idents.enter_node f;
|
|
let mem_var_tys = Mls_utils.node_memory_vars n in
|
|
let subst_map = subst_map i_list o_list d_list mem_var_tys in
|
|
let (v, si, j, s_list) = translate_eq_list subst_map empty_call_context eq_list in
|
|
let (si', j', s_list', d_list') = translate_contract subst_map mem_var_tys contract in
|
|
let i_list = translate_var_dec i_list in
|
|
let o_list = translate_var_dec o_list in
|
|
let d_list = translate_var_dec (v @ d_list) in
|
|
let m, d_list = List.partition
|
|
(fun vd -> List.exists (fun (i,_) -> i = vd.v_ident) mem_var_tys) d_list in
|
|
let s = s_list @ s_list' in
|
|
let j = j' @ j in
|
|
let si = si @ si' in
|
|
let stepm = { m_name = Mstep; m_inputs = i_list; m_outputs = o_list;
|
|
m_body = mk_block ~locals:(d_list' @ d_list) s }
|
|
in
|
|
let resetm = { m_name = Mreset; m_inputs = []; m_outputs = []; m_body = mk_block si } in
|
|
if stateful
|
|
then { cd_name = f; cd_stateful = true; cd_mems = m; cd_params = params;
|
|
cd_objs = j; cd_methods = [stepm; resetm]; cd_loc = loc; }
|
|
else (
|
|
(* Functions won't have [Mreset] or memories,
|
|
they still have [params] and instances (of functions) *)
|
|
{ cd_name = f; cd_stateful = false; cd_mems = []; cd_params = params;
|
|
cd_objs = j; cd_methods = [stepm]; cd_loc = loc; }
|
|
)
|
|
|
|
let translate_ty_def { Minils.t_name = name; Minils.t_desc = tdesc;
|
|
Minils.t_loc = loc } =
|
|
let tdesc = match tdesc with
|
|
| Minils.Type_abs -> Type_abs
|
|
| Minils.Type_alias ln -> Type_alias ln
|
|
| Minils.Type_enum tag_name_list -> Type_enum tag_name_list
|
|
| Minils.Type_struct field_ty_list -> Type_struct field_ty_list
|
|
in
|
|
{ t_name = name; t_desc = tdesc; t_loc = loc }
|
|
|
|
let translate_const_def { Minils.c_name = name; Minils.c_value = se;
|
|
Minils.c_type = ty; Minils.c_loc = loc } =
|
|
{ c_name = name;
|
|
c_value = se;
|
|
c_type = ty;
|
|
c_loc = loc }
|
|
|
|
let program { Minils.p_modname = p_modname; Minils.p_opened = p_o; Minils.p_desc = pd; } =
|
|
build_anon pd;
|
|
|
|
let program_desc pd acc = match pd with
|
|
| Minils.Pnode n when not (Itfusion.is_anon_node n.Minils.n_name) ->
|
|
Pclass (translate_node n) :: acc
|
|
(* dont't translate anonymous nodes, they will be inlined *)
|
|
| Minils.Pnode n -> acc
|
|
| Minils.Ptype t -> Ptype (translate_ty_def t) :: acc
|
|
| Minils.Pconst c -> Pconst (translate_const_def c) :: acc
|
|
in
|
|
let p_desc = List.fold_right program_desc pd [] in
|
|
{ p_modname = p_modname;
|
|
p_opened = p_o;
|
|
p_desc = p_desc }
|
|
|