heptagon/compiler/main/mls2obc.ml

467 lines
18 KiB
OCaml
Raw Normal View History

2010-06-15 10:49:03 +02:00
(**************************************************************************)
(* *)
(* Heptagon *)
(* *)
(* Author : Marc Pouzet *)
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
(* *)
(**************************************************************************)
2010-06-18 10:30:23 +02:00
(* Translation from Minils to Obc. *)
2010-06-15 10:49:03 +02:00
open Misc
2010-06-18 10:30:23 +02:00
open Names
2010-06-15 10:49:03 +02:00
open Ident
2010-06-18 10:30:23 +02:00
open Signature
2010-06-15 10:49:03 +02:00
open Obc
open Control
open Static
let gen_obj_name n =
(shortname n) ^ "_mem" ^ (gen_symbol ())
let rec encode_name_params n = function
| [] -> n
| p :: params -> encode_name_params (n ^ ("__" ^ (string_of_int p))) params
2010-06-29 11:18:50 +02:00
let encode_longname_params n params = match n with
| Name n -> Name (encode_name_params n params)
| Modname { qual = qual; id = id } ->
Modname { qual = qual; id = encode_name_params id params; }
2010-06-29 11:18:50 +02:00
2010-06-18 10:30:23 +02:00
let op_from_string op = Modname { qual = "Pervasives"; id = op; }
let rec lhs_of_idx_list e = function
2010-06-18 10:30:23 +02:00
| [] -> e | idx :: l -> Array (lhs_of_idx_list e l, idx)
2010-06-25 13:42:10 +02:00
let array_elt_of_exp idx e =
match e with
| Const (Carray (_, c)) ->
Const c
| _ ->
2010-06-25 13:42:10 +02:00
Lhs (Array(lhs_of_exp e, Lhs idx))
(** 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
e1 <= n1 && .. && ep <= np *)
let rec bound_check_expr idx_list bounds =
2010-06-18 10:30:23 +02:00
match (idx_list, bounds) with
2010-06-29 11:18:50 +02:00
| ([ idx ], [ n ]) -> Op (op_from_string "<", [ idx; Const (Cint n) ])
| (idx :: idx_list, n :: bounds) ->
Op (op_from_string "&",
[ Op (op_from_string "<", [ idx; Const (Cint n) ]);
bound_check_expr idx_list bounds ])
| (_, _) -> assert false
let rec translate_type const_env = function
| Types.Tid id when id = Initial.pint -> Tint
| Types.Tid id when id = Initial.pfloat -> Tfloat
| Types.Tid id when id = Initial.pbool -> Tbool
| Types.Tid id -> Tid id
| Types.Tarray (ty, n) ->
2010-06-30 17:20:56 +02:00
Tarray (translate_type const_env ty, int_of_static_exp const_env n)
| Types.Tprod ty -> assert false
2010-06-29 11:18:50 +02:00
let rec translate_const const_env = function
| Minils.Sint v -> Cint v
| Minils.Sbool v -> Cbool v
| Minils.Sfloat v -> Cfloat v
| Minils.Sconstructor c -> Cconstr c
| Minils.Sarray_power (n, c) ->
Carray_power (int_of_static_exp const_env n, translate_const const_env c)
| Minils.Sarray se_list ->
Carray (List.map (translate_const const_env) se_list)
| Minils.Stuple se_list ->
Ctuple (List.map (translate_const const_env) se_list)
| Minils.Svar n -> simplify const_env (SVar n)
2010-06-29 11:18:50 +02:00
let rec translate_pat map = function
| Minils.Evarpat x -> [ var_from_name map x ]
| Minils.Etuplepat pat_list ->
2010-06-29 11:18:50 +02:00
List.fold_right (fun pat acc -> (translate_pat map pat) @ acc)
pat_list []
2010-06-29 11:18:50 +02:00
2010-06-15 10:49:03 +02:00
(* [translate e = c] *)
let rec translate const_env map (m, si, j, s)
2010-06-29 11:18:50 +02:00
(({ Minils.e_desc = desc } as e)) =
2010-06-15 10:49:03 +02:00
match desc with
2010-06-29 11:18:50 +02:00
| Minils.Econst v -> Const (translate_const const_env v)
| Minils.Evar n -> Lhs (var_from_name map n)
| Minils.Ecall ({ Minils.op_name = n; Minils.op_kind = Minils.Efun },
e_list, _) when Mls_utils.is_op n ->
2010-06-29 11:18:50 +02:00
Op (n, List.map (translate const_env map (m, si, j, s)) e_list)
| Minils.Ewhen (e, _, _) -> translate const_env map (m, si, j, s) e
| Minils.Efield (e, field) ->
let e = translate const_env map (m, si, j, s) e
in Lhs (Field (lhs_of_exp e, field))
| Minils.Estruct f_e_list ->
let type_name =
(match e.Minils.e_ty with
| Types.Tid name -> name
| _ -> assert false) in
let f_e_list =
List.map
(fun (f, e) -> (f, (translate const_env map (m, si, j, s) e)))
f_e_list
in Struct_lit (type_name, f_e_list)
(*Array operators*)
| Minils.Earray e_list ->
Array_lit (List.map (translate const_env map (m, si, j, s)) e_list)
| Minils.Earray_op (Minils.Eselect (idx, e)) ->
let e = translate const_env map (m, si, j, s) e in
let idx_list =
2010-06-30 17:20:56 +02:00
List.map (fun e -> Const (Cint (int_of_static_exp const_env e))) idx
2010-06-29 11:18:50 +02:00
in
Lhs (lhs_of_idx_list (lhs_of_exp e) idx_list)
| _ -> (*Minils_printer.print_exp stdout e; flush stdout;*) assert false
2010-06-15 10:49:03 +02:00
(* [translate pat act = si, j, d, s] *)
2010-06-18 10:30:23 +02:00
and translate_act const_env map ((m, _, _, _) as context) pat
2010-06-29 11:18:50 +02:00
({ Minils.e_desc = desc } as act) =
2010-06-15 10:49:03 +02:00
match pat, desc with
2010-06-29 11:18:50 +02:00
| Minils.Etuplepat p_list, Minils.Etuple act_list ->
comp (List.map2 (translate_act const_env map context) p_list act_list)
| pat, Minils.Ewhen (e, _, _) ->
translate_act const_env map context pat e
| pat, Minils.Emerge (x, c_act_list) ->
let lhs = var_from_name map x in
Case (Lhs lhs
, translate_c_act_list const_env map context pat c_act_list)
| Minils.Evarpat n, _ ->
Assgn (var_from_name map n, translate const_env map context act)
| _ -> (*Minils_printer.print_exp stdout act;*) assert false
2010-06-15 10:49:03 +02:00
and translate_c_act_list const_env map context pat c_act_list =
List.map
2010-06-18 10:30:23 +02:00
(fun (c, act) -> (c, (translate_act const_env map context pat act)))
2010-06-15 10:49:03 +02:00
c_act_list
and comp s_list =
2010-06-18 10:30:23 +02:00
List.fold_right (fun s rest -> Comp (s, rest)) s_list Nothing
let rec translate_eq const_env map { Minils.eq_lhs = pat; Minils.eq_rhs = e }
2010-06-29 11:18:50 +02:00
(m, si, j, s) =
let { Minils.e_desc = desc; Minils.e_ty = ty; Minils.e_ck = ck } = e in
match (pat, desc) with
2010-06-29 11:18:50 +02:00
| 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 ->
(Assgn (x,
Const (translate_const const_env c))) :: si) in
let ty = translate_type const_env ty in
let m = (n, ty) :: m in
let action = Assgn (var_from_name map n,
translate const_env map (m, si, j, s) e)
in
m, si, j, (control map ck action) :: s
| pat, Minils.Ecall ({ Minils.op_name = n; Minils.op_params = params;
Minils.op_kind = (Minils.Enode
| Minils.Efun) as op_kind },
2010-06-18 10:30:23 +02:00
e_list, r) ->
2010-06-29 11:18:50 +02:00
let name_list = translate_pat map pat in
let c_list = List.map (translate const_env map (m, si, j, s)) e_list in
let o = gen_obj_name n in
let si =
(match op_kind with
| Minils.Enode -> (Reinit o) :: si
| Minils.Efun -> si) in
2010-06-30 17:20:56 +02:00
let params = List.map (int_of_static_exp const_env) params in
2010-06-29 11:18:50 +02:00
let j = (o, (encode_longname_params n params), 1) :: j in
let action = Step_ap (name_list, Context o, c_list) in
let s = (match r, op_kind with
| Some r, Minils.Enode ->
2010-06-29 11:18:50 +02:00
let ra =
control map (Minils.Con (ck, Name "true", r))
(Reinit o) in
ra :: (control map ck action) :: s
| _, _ -> (control map ck action) :: s) in
2010-06-29 11:18:50 +02:00
m, si, j, s
| Minils.Etuplepat p_list, Minils.Etuple act_list ->
List.fold_right2
(fun pat e ->
translate_eq const_env map
(Minils.mk_equation pat e))
p_list act_list (m, si, j, s)
| Minils.Evarpat x, Minils.Efield_update (f, e1, e2) ->
let x = var_from_name map x in
let copy = Assgn (x, translate const_env map (m, si, j, s) e1) in
let action =
Assgn (Field (x, f), translate const_env map (m, si, j, s) e2)
in
m, si, j, (control map ck copy) :: (control map ck action) :: s
| Minils.Evarpat x,
Minils.Earray_op (Minils.Eselect_slice (idx1, idx2, e)) ->
2010-06-30 17:20:56 +02:00
let idx1 = int_of_static_exp const_env idx1 in
let idx2 = int_of_static_exp const_env idx2 in
2010-06-29 11:18:50 +02:00
let cpt = Ident.fresh "i" in
let e = translate const_env map (m, si, j, s) e in
let idx =
Op (op_from_string "+", [ Lhs (Var cpt); Const (Cint idx1) ]) in
let action =
For (cpt, 0, (idx2 - idx1) + 1,
Assgn (Array (var_from_name map x, Lhs (Var cpt)),
Lhs (Array (lhs_of_exp e, idx))))
in
m, si, j, (control map ck action) :: s
| Minils.Evarpat x,
Minils.Earray_op (Minils.Eselect_dyn (idx, e1, e2)) ->
2010-06-29 11:18:50 +02:00
let x = var_from_name map x in
let bounds = Mls_utils.bounds_list e1.Minils.e_ty in
2010-06-29 11:18:50 +02:00
let e1 = translate const_env map (m, si, j, s) e1 in
2010-06-30 17:20:56 +02:00
let bounds = List.map (int_of_static_exp const_env) bounds in
2010-06-29 11:18:50 +02:00
let idx = List.map (translate const_env map (m, si, j, s)) idx in
let true_act =
Assgn (x, Lhs (lhs_of_idx_list (lhs_of_exp e1) idx)) in
let false_act =
Assgn (x, translate const_env map (m, si, j, s) e2) in
let cond = bound_check_expr idx bounds in
let action =
Case (cond,
[ ((Name "true"), true_act); ((Name "false"), false_act) ])
in
m, si, j, (control map ck action) :: s
| Minils.Evarpat x,
Minils.Earray_op (Minils.Eupdate (idx, e1, e2)) ->
let x = var_from_name map x in
let copy = Assgn (x, translate const_env map (m, si, j, s) e1) in
let idx =
2010-06-30 17:20:56 +02:00
List.map (fun se -> Const (Cint (int_of_static_exp const_env se)))
2010-06-29 11:18:50 +02:00
idx in
let action = Assgn (lhs_of_idx_list x idx,
translate const_env map (m, si, j, s) e2)
in
m, si, j, (control map ck copy) :: (control map ck action) :: s
| Minils.Evarpat x,
Minils.Earray_op (Minils.Erepeat (n, e)) ->
let cpt = Ident.fresh "i" in
let action =
2010-06-30 17:20:56 +02:00
For (cpt, 0, int_of_static_exp const_env n,
2010-06-29 11:18:50 +02:00
Assgn (Array (var_from_name map x, Lhs (Var cpt)),
translate const_env map (m, si, j, s) e))
in
m, si, j, (control map ck action) :: s
| Minils.Evarpat x,
Minils.Earray_op (Minils.Econcat (e1, e2)) ->
let cpt1 = Ident.fresh "i" in
let cpt2 = Ident.fresh "i" in
let x = var_from_name map x in
(match e1.Minils.e_ty, e2.Minils.e_ty with
| Types.Tarray (_, n1), Types.Tarray (_, n2) ->
let e1 = translate const_env map (m, si, j, s) e1 in
let e2 = translate const_env map (m, si, j, s) e2 in
2010-06-30 17:20:56 +02:00
let n1 = int_of_static_exp const_env n1 in
let n2 = int_of_static_exp const_env n2 in
2010-06-29 11:18:50 +02:00
let a1 =
For (cpt1, 0, n1,
Assgn (Array (x, Lhs (Var cpt1)),
Lhs (Array (lhs_of_exp e1, Lhs (Var cpt1))))) in
let idx =
Op (op_from_string "+", [ Const (Cint n1); Lhs (Var cpt2) ]) in
let a2 =
For (cpt2, 0, n2,
Assgn (Array (x, idx),
Lhs (Array (lhs_of_exp e2, Lhs (Var cpt2)))))
in
m, si, j, (control map ck a1) :: (control map ck a2) :: s
| _ -> assert false )
| pat, Minils.Earray_op (
Minils.Eiterator (it,
{ Minils.op_name = f; Minils.op_params = params;
Minils.op_kind = k },
n, e_list, reset)) ->
let name_list = translate_pat map pat in
let c_list =
List.map (translate const_env map (m, si, j, s)) e_list in
let o = gen_obj_name f in
2010-06-30 17:20:56 +02:00
let n = int_of_static_exp const_env n in
2010-06-29 11:18:50 +02:00
let si =
(match k with
| Minils.Efun -> si
2010-06-29 11:18:50 +02:00
| Minils.Enode -> (Reinit o) :: si) in
2010-06-30 17:20:56 +02:00
let params = List.map (int_of_static_exp const_env) params in
2010-06-29 11:18:50 +02:00
let j = (o, (encode_longname_params f params), n) :: j in
let x = Ident.fresh "i" in
let action =
translate_iterator const_env map it x name_list o n c_list in
let s =
(match reset with
| None -> (control map ck action) :: s
| Some r ->
(control map (Minils.Con (ck, Name "true", r)) (Reinit o)) ::
(control map ck action) :: s )
in (m, si, j, s)
| (pat, _) ->
let action = translate_act const_env map (m, si, j, s) pat e
in (m, si, j, ((control map ck action) :: s))
2010-06-18 10:30:23 +02:00
and translate_iterator const_env map it x name_list o n c_list =
match it with
| Minils.Imap ->
let c_list =
List.map (array_elt_of_exp (Var x)) c_list in
let name_list = List.map (fun l -> Array (l, Lhs (Var x))) name_list in
let objn = Array_context (o, Var x) in
2010-06-18 10:30:23 +02:00
For (x, 0, n, Step_ap (name_list, objn, c_list))
| Minils.Imapfold ->
let (c_list, acc_in) = split_last c_list in
let c_list = List.map (array_elt_of_exp (Var x)) c_list in
let objn = Array_context (o, Var x) in
let (name_list, acc_out) = split_last name_list in
let name_list = List.map (fun l -> Array (l, Lhs (Var x))) name_list in
2010-06-18 10:30:23 +02:00
Comp (Assgn (acc_out, acc_in),
For (x, 0, n,
Step_ap (name_list @ [ acc_out ], objn,
c_list @ [ Lhs acc_out ])))
| Minils.Ifold ->
let (c_list, acc_in) = split_last c_list in
let c_list = List.map (array_elt_of_exp (Var x)) c_list in
let objn = Array_context (o, Var x) in
let acc_out = last_element name_list in
2010-06-18 10:30:23 +02:00
Comp (Assgn (acc_out, acc_in),
For (x, 0, n,
Step_ap (name_list, objn, c_list @ [ Lhs acc_out ])))
2010-06-15 10:49:03 +02:00
let translate_eq_list const_env map act_list =
List.fold_right (translate_eq const_env map) act_list ([], [], [], [])
2010-06-15 10:49:03 +02:00
let remove m d_list =
List.filter (fun { Minils.v_ident = n } -> not (List.mem_assoc n m)) d_list
2010-06-15 10:49:03 +02:00
let var_decl l =
2010-06-18 10:30:23 +02:00
List.map (fun (x, t) -> mk_var_dec x t) l
2010-06-18 10:30:23 +02:00
let obj_decl l = List.map (fun (x, t, i) -> { obj = x; cls = t; size = i; }) l
2010-06-15 10:49:03 +02:00
let translate_var_dec const_env map l =
let one_var { Minils.v_ident = x; Minils.v_type = t } =
2010-06-18 10:30:23 +02:00
mk_var_dec x (translate_type const_env t)
2010-06-15 10:49:03 +02:00
in
List.map one_var l
2010-06-18 10:30:23 +02:00
let translate_contract const_env map =
function
| None -> ([], [], [], [], [], [])
| Some
{
Minils.c_eq = eq_list;
Minils.c_local = d_list;
Minils.c_controllables = c_list;
Minils.c_assume = e_a;
Minils.c_enforce = e_c
} ->
let (m, si, j, s_list) = translate_eq_list const_env map eq_list in
let d_list = remove m d_list in
let d_list = translate_var_dec const_env map d_list in
let c_list = translate_var_dec const_env map c_list
in (m, si, j, s_list, d_list, c_list)
2010-06-15 10:49:03 +02:00
(** Returns a map, mapping variables names to the variables
2010-06-18 10:30:23 +02:00
where they will be stored. *)
let subst_map inputs outputs locals mems =
(* Create a map that simply maps each var to itself *)
let m =
List.fold_left (fun m { Minils.v_ident = x } -> Env.add x (Var x) m)
2010-06-18 10:30:23 +02:00
Env.empty (inputs @ outputs @ locals)
in
List.fold_left (fun m x -> Env.add x (Mem x) m) m mems
2010-06-18 10:30:23 +02:00
let translate_node_aux const_env
2010-06-29 11:18:50 +02:00
{
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_contract = contract;
Minils.n_params = params
} =
let mem_vars = List.flatten (List.map Mls_utils.Vars.memory_vars eq_list) in
2010-06-18 10:30:23 +02:00
let subst_map = subst_map i_list o_list d_list mem_vars in
let (m, si, j, s_list) = translate_eq_list const_env subst_map eq_list in
let (m', si', j', s_list', d_list', c_list) =
translate_contract const_env subst_map contract in
2010-06-15 10:49:03 +02:00
let d_list = remove m d_list in
let i_list = translate_var_dec const_env subst_map i_list in
let o_list = translate_var_dec const_env subst_map o_list in
let d_list = translate_var_dec const_env subst_map d_list in
2010-06-18 10:30:23 +02:00
let s = joinlist (s_list @ s_list') in
let m = var_decl (m @ m') in
let j = obj_decl (j @ j') in
let si = joinlist (si @ si') in
let step =
{
inp = i_list;
out = o_list;
local = d_list @ (d_list' @ c_list);
controllables = c_list;
bd = s;
}
in
{ cl_id = f; mem = m; objs = j; reset = si; step = step; }
2010-06-15 10:49:03 +02:00
let build_params_list env params_names params_values =
2010-07-06 11:12:14 +02:00
List.fold_left2 (fun env { p_name = n } v -> NamesEnv.add n (Sconst v) env)
2010-06-18 10:30:23 +02:00
env params_names params_values
2010-06-15 10:49:03 +02:00
let translate_node const_env n =
let translate_one p =
let const_env = build_params_list const_env n.Minils.n_params p in
2010-06-18 10:30:23 +02:00
let c = translate_node_aux const_env n
in
{ c with cl_id = encode_name_params c.cl_id p; }
2010-06-15 10:49:03 +02:00
in
match n.Minils.n_params_instances with
2010-06-18 10:30:23 +02:00
| [] -> [ translate_node_aux const_env n ]
| params_lists -> List.map translate_one params_lists
2010-06-18 10:30:23 +02:00
let translate_ty_def const_env { Minils.t_name = name; Minils.t_desc = tdesc
} =
2010-06-18 10:30:23 +02:00
let tdesc =
match tdesc with
| Minils.Type_abs -> Type_abs
| Minils.Type_enum tag_name_list -> Type_enum tag_name_list
| Minils.Type_struct field_ty_list ->
Type_struct
(List.map
(fun { f_name = f; f_type = ty } ->
(f, translate_type const_env ty))
field_ty_list)
2010-06-18 10:30:23 +02:00
in { t_name = name; t_desc = tdesc; }
2010-06-15 10:49:03 +02:00
let build_const_env cd_list =
2010-06-18 10:30:23 +02:00
List.fold_left
(fun env cd -> NamesEnv.add cd.Minils.c_name cd.Minils.c_value env)
NamesEnv.empty cd_list
2010-06-18 10:30:23 +02:00
let program {
Minils.p_pragmas = p_pragmas_list;
Minils.p_opened = p_module_list;
Minils.p_types = p_type_list;
Minils.p_nodes = p_node_list;
Minils.p_consts = p_const_list
} =
2010-06-18 10:30:23 +02:00
let const_env = build_const_env p_const_list
in
{
o_pragmas = p_pragmas_list;
o_opened = p_module_list;
o_types = List.map (translate_ty_def const_env) p_type_list;
o_defs = List.flatten (List.map (translate_node const_env) p_node_list);
}
2010-06-18 10:30:23 +02:00