heptagon/compiler/main/mls2obc.ml

813 lines
34 KiB
OCaml

(***********************************************************************)
(* *)
(* Heptagon *)
(* *)
(* Gwenael Delaval, LIG/INRIA, UJF *)
(* Leonard Gerard, Parkas, ENS *)
(* Adrien Guatto, Parkas, ENS *)
(* Cedric Pasteur, Parkas, ENS *)
(* Marc Pouzet, Parkas, ENS *)
(* *)
(* Copyright 2012 ENS, INRIA, UJF *)
(* *)
(* This file is part of the Heptagon compiler. *)
(* *)
(* Heptagon is free software: you can redistribute it and/or modify it *)
(* under the terms of the GNU General Public License as published by *)
(* the Free Software Foundation, either version 3 of the License, or *)
(* (at your option) any later version. *)
(* *)
(* Heptagon is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *)
(* GNU General Public License for more details. *)
(* *)
(* You should have received a copy of the GNU General Public License *)
(* along with Heptagon. If not, see <http://www.gnu.org/licenses/> *)
(* *)
(***********************************************************************)
(* Translation from Minils to Obc. *)
open Misc
open Names
open Idents
open Signature
open Obc
open Obc_utils
open Obc_mapfold
open Types
open Clocks
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
_ ->
Format.eprintf
"Internal compiler error: unknown identifier %a@."
Global_printer.print_ident x;
assert false
end
let ext_value_exp_from_name map x = exp_of_pattern (var_from_name map x)
(* 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 pattern_of_idx_list p l =
let rec aux p l = match Modules.unalias_type p.pat_ty, l with
| _, [] -> p
| Tarray (ty',_), idx :: l -> aux (mk_pattern ty' (Larray (p, idx))) l
| _ -> internal_error "mls2obc"
in
aux p l
let rec exp_of_idx_list e l = match Modules.unalias_type e.w_ty, l with
| _, [] -> e
| Tarray (ty',_), idx :: l ->
exp_of_idx_list (mk_ext_value ty' (Warray (e, idx))) l
| _ -> internal_error "mls2obc exp_of_idx_list"
let rec extvalue_of_idx_list w l = match Modules.unalias_type 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 extvalue_of_idx_list"
let 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 Modules.unalias_type 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 ext_value_of_trunc_idx_list"
in
aux p l
let rec ty_of_idx_list ty idx_list = match ty, idx_list with
| _, [] -> ty
| Tarray(ty, _), _idx::idx_list -> ty_of_idx_list ty idx_list
| _, _ -> internal_error "mls2obc ty_of_idx_list"
let mk_static_array_power ty c params = match params with
| [] -> mk_ext_value_exp ty (Wconst c)
| _ ->
let se = mk_static_exp ty (Sarray_power (c, params)) in
mk_ext_value_exp ty (Wconst se)
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, _::new_params) }; }, Tarray (ty,_) ->
mk_static_array_power ty c new_params
| _, Tarray (ty,_) ->
mk_ext_value_exp ty (Warray(ext_value_of_exp e, idx))
| _ -> internal_error "mls2obc array_elt_of_exp"
let array_elt_of_exp_list idx_list e =
match e.e_desc, Modules.unalias_type e.e_ty with
| Eextvalue { w_desc = Wconst { se_desc = Sarray_power (c, params) } }, Tarray (ty,n) ->
let new_params, _ = Misc.split_at (List.length params - List.length idx_list) params in
let ty = ty_of_idx_list (Tarray(ty,n)) idx_list in
mk_static_array_power ty c new_params
| _ , t ->
let rec ty id_l t = match id_l, Modules.unalias_type t with
| [] , t -> t
| _::id_l , Tarray (t,_) -> ty id_l t
| _, _ -> internal_error "mls2obc ty"
in
mk_exp (ty idx_list t) (Eextvalue (extvalue_of_idx_list (ext_value_of_exp e) idx_list))
(** 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"
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 ssa_update_array dest src idx_list v = match Modules.unalias_type 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 = ssa_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 ssa_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"
in
List.map assgn_act fields
let rec control map ck s = match ck with
| Clocks.Cbase | Cvar { contents = Cindex _ } -> s
| Cvar { contents = Clink ck } -> control map ck s
| Clocks.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"
let translate_var_dec l =
let one_var { Minils.v_ident = x; Minils.v_type = t; Minils.v_linearity = lin; v_loc = loc } =
mk_var_dec ~loc:loc ~linearity:lin x t
in
List.rev (List.rev_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 _ -> assert false
| Minils.Wfield (w1, f) -> Wfield (translate_extvalue map w1, f)
| Minils.Wwhen (w1, _, _) | Minils.Wreinit(_, w1) -> (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)
| Minils.Ewhen(e,_,_) ->
let e = translate map e in
e.e_desc
(* Already treated cases when translating the [eq] *)
| Minils.Eiterator _ | Minils.Emerge _ | Minils.Efby _
| Minils.Eapp ({Minils.a_op=(Minils.Enode _|Minils.Efun _|Minils.Easync _
|Minils.Econcat
|Minils.Eupdate|Minils.Eselect_dyn
|Minils.Eselect_trunc|Minils.Eselect_slice
|Minils.Earray_fill|Minils.Efield_update
|Minils.Eifthenelse)}, _, _) ->
internal_error "mls2obc"
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 *)
| pat, Minils.Ewhen (e,_,_) -> translate_act map pat e
| 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"
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"
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 copy = Aassgn (x, e1) in
if !Compiler_options.strict_ssa
then (
let ssa_up = ssa_update_array x e1 idx e2 in
[ mk_ifthenelse cond ssa_up [copy] ]
) else (
let assgn = Aassgn (pattern_of_idx_list x idx, e2) in
[copy; mk_if cond [assgn]]
)
| 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
if !Compiler_options.strict_ssa
then ssa_update_record x e1' f e2
else (
let copy = Aassgn (x, translate_extvalue_to_exp map e1) in
let action = Aassgn (mk_pattern (Types.Tid (Modules.find_field f)) (Lfield (x, f)), e2) in
[copy; action]
)
| 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 list; oa_size : static_exp list }
(** 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
(v, si, j, s)
({ Minils.eq_lhs = pat; Minils.eq_base_ck = ck; Minils.eq_rhs = e } as eq) =
let { Minils.e_desc = desc; Minils.e_loc = loc } = e in
match (pat, desc) with
| _pat, Minils.Ewhen (e,_,_) ->
translate_eq map call_context (v, si, j, s) {eq with Minils.eq_rhs = e}
(* TODO Efby and Eifthenelse should be dealt with in translate_act, no ? *)
| 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_exp_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 ({ qual = Module "Iostream"; name = "printf" | "fprintf" } as q)},
args, _) ->
let action = Aop (q, List.map (translate_extvalue_to_exp map) args) 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_list, 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 xl, xdl = List.split (List.map (fun _ -> fresh_it ()) n_list) in
let call_context =
Some { oa_index = List.map (fun x -> mk_pattern_int (Lvar x)) xl;
oa_size = n_list} in
let n_list = List.map mk_exp_static_int n_list in
let si', j', action = translate_iterator map call_context it
name_list app loc n_list xl xdl 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 =
let rev_act = List.rev act_list in
List.fold_left (translate_eq map call_context) ([], [], [], []) rev_act
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" 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 id = match app.Minils.a_id with
| None -> gen_obj_ident f
| Some id -> id
in
let o = mk_obj_call_from_context call_context id 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_list xl xdl p_list c_list ty =
let rec unarray n ty = match ty, n with
| Tarray (t,_), 1 -> t
| Tarray (t,_), n -> unarray (n-1) t
| _ ->
Format.eprintf "%a" Global_printer.print_type ty;
internal_error "mls2obc"
in
let unarray = unarray (List.length n_list) in
let array_of_output name_list ty_list =
let rec aux l ty xl = match ty, xl with
| _, [] -> l
| Tarray(tyn, _), x :: xl -> aux (mk_pattern ~loc:loc tyn (Larray(l, mk_evar_int x))) tyn xl
| _, _ -> assert false
in
List.map2 (fun l ty -> aux l ty xl) name_list ty_list
in
let array_of_input c_list =
List.map (array_elt_of_exp_list (List.map mk_evar_int xl)) c_list
in
let mk_loop b xdl nl =
let rec mk_loop b xdl nl = match xdl, nl with
| xd::[], n::[] -> Afor (xd, mk_exp_const_int 0, n, b)
| xd::xdl, n::nl -> mk_loop (mk_block [Afor (xd, mk_exp_const_int 0, n, b)]) xdl nl
| _, _ -> assert false
in
mk_loop b (List.rev xdl) nl
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 (Types.unprod ty) 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
[mk_loop bi xdl n_list], j, [mk_loop b xdl n_list]
| 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 (Types.unprod ty) 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@(List.map mk_evar_int xl)) 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
[mk_loop bi xdl n_list], j, [mk_loop b xdl n_list]
| Minils.Imapfold ->
let (c_list, acc_in) = split_last c_list in
let c_list = array_of_input c_list in
let ty_list = Types.unprod ty in
let ty_name_list, _ = 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 (Misc.map_butlast unarray 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
[mk_loop bi xdl n_list], j,
[Aassgn (acc_out, acc_in); mk_loop b xdl n_list]
| 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
[mk_loop bi xdl n_list], j,
[ Aassgn (acc_out, acc_in); mk_loop b xdl n_list]
| 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 @ (List.map mk_evar_int xl) @ [ 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
[mk_loop bi xdl n_list], j,
[ Aassgn (acc_out, acc_in); mk_loop b xdl n_list]
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 m, d_list = List.partition
(fun vd -> List.exists (fun (i,_) -> i = vd.v_ident) mem_var_tys) d_list in
(m, 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 controllables c_locals 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 @ controllables @ c_locals @ 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;
Minils.n_mem_alloc = mem_alloc
} as n) =
Idents.enter_node f;
let mem_var_tys = Mls_utils.node_memory_vars n in
let c_list, c_locals =
match contract with
| None -> [], []
| Some c -> c.Minils.c_controllables, c.Minils.c_local in
let subst_map = subst_map i_list o_list c_list c_locals d_list mem_var_tys in
let (v, si, j, s_list) = translate_eq_list subst_map empty_call_context eq_list in
let (m_c, 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 (List.rev_append 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 m', o_list =
List.partition
(fun vd -> List.exists (fun (i,_) -> i = vd.v_ident) mem_var_tys) o_list in
let s = List.rev_append (List.rev 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:(List.rev_append 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' @ m @ m_c; cd_params = params;
cd_objs = j; cd_methods = [stepm; resetm]; cd_loc = loc; cd_mem_alloc = mem_alloc }
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; cd_mem_alloc = mem_alloc }
)
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 } =
{ Obc.c_name = name;
Obc.c_value = se;
Obc.c_type = ty;
Obc.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 _ -> 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 }
let signature s =
{ sig_name = s.Minils.sig_name;
sig_inputs = s.Minils.sig_inputs;
sig_stateful = s.Minils.sig_stateful;
sig_outputs = s.Minils.sig_outputs;
sig_params = s.Minils.sig_params;
sig_param_constraints = s.Minils.sig_param_constraints;
sig_loc = s.Minils.sig_loc }
let interface i =
let interface_decl id = match id with
| Minils.Itypedef td -> Itypedef (translate_ty_def td)
| Minils.Iconstdef cd -> Iconstdef (translate_const_def cd)
| Minils.Isignature s -> Isignature (signature s)
in
{ i_modname = i.Minils.i_modname;
i_opened = i.Minils.i_opened;
i_desc = List.map interface_decl i.Minils.i_desc }