diff --git a/compiler/main/heptc.ml b/compiler/main/heptc.ml index 4853e0d..919cb71 100644 --- a/compiler/main/heptc.ml +++ b/compiler/main/heptc.ml @@ -127,7 +127,7 @@ let main () = "-statefuli", Arg.Set stateful_info, doc_stateful_info; "-fname", Arg.Set full_name, doc_full_name; "-itfusion", Arg.Set do_iterator_fusion, doc_itfusion; - "-strict_ssa", Arg.Set strict_ssa, doc_strict_ssa; + "-strict_ssa", Arg.Unit set_strict_ssa, doc_strict_ssa; "-memalloc", Arg.Unit do_mem_alloc_and_typing, doc_memalloc; "-only-memalloc", Arg.Set do_mem_alloc, doc_memalloc_only; "-only-linear", Arg.Set do_linear_typing, doc_linear_only; diff --git a/compiler/minils/analysis/interference.ml b/compiler/minils/analysis/interference.ml index f1a2bc0..52eb8d5 100644 --- a/compiler/minils/analysis/interference.ml +++ b/compiler/minils/analysis/interference.ml @@ -10,31 +10,6 @@ open Printf let print_interference_graphs = false let verbose_mode = false -let print_debug0 s = - if verbose_mode then - Format.printf s - -let print_debug1 fmt x = - if verbose_mode then - Format.printf fmt x - -let print_debug2 fmt x y = - if verbose_mode then - Format.printf fmt x y - -let print_debug_ivar_env name env = - if verbose_mode then ( - Format.printf "%s: " name; - IvarEnv.iter (fun k v -> Format.printf "%s : %d; " (ivar_to_string k) v) env; - Format.printf "@." - ) - -let print_debug_ivar_set name env = - if verbose_mode then ( - Format.printf "%s: " name; - IvarSet.iter (fun k -> Format.printf "%s; " (ivar_to_string k) ) env; - Format.printf "@." - ) module TyEnv = ListMap(struct @@ -42,6 +17,37 @@ module TyEnv = let compare = Global_compare.type_compare end) +module VarEnv = struct + include Idents.Env + + let add_ivar env iv = + let x = var_ident_of_ivar iv in + if mem x env then + add x (IvarSet.add iv (find x env)) env + else + add x (IvarSet.singleton iv) env +end + +let print_debug fmt = + if verbose_mode then + Format.printf fmt + else + Format.ifprintf Format.std_formatter fmt + +let print_debug_ivar_env name env = + if verbose_mode then ( + Format.printf "%s: " name; + IvarEnv.iter (fun k v -> Format.printf "%a : %d; " print_ivar k v) env; + Format.printf "@." + ) + +let print_debug_var_env name env = + if verbose_mode then ( + Format.printf "%s: " name; + VarEnv.iter (fun _ l -> IvarSet.iter (fun k -> Format.printf "%a; " print_ivar k) l) env; + Format.printf "@." + ) + (** @return whether [ty] corresponds to a record type. *) let is_record_type ty = match Modules.unalias_type ty with | Tid n -> @@ -70,7 +76,7 @@ module InterfRead = struct exception Const_extvalue let rec vars_ck acc = function - | Con(ck2, _, n) -> IvarSet.add (Ivar n) (vars_ck acc ck2) + | Con(ck2, _, n) -> (Ivar n)::(vars_ck acc ck2) | Cbase | Cvar { contents = Cindex _ } -> acc | Cvar { contents = Clink ck } -> vars_ck acc ck @@ -78,10 +84,10 @@ module InterfRead = struct | Ck ck -> vars_ck acc ck | Cprod ct_list -> List.fold_left vars_ct acc ct_list - let rec ivar_of_extvalue w = match w.w_desc with + let rec ivar_of_extvalue w' = match w'.w_desc with | Wvar x -> Ivar x | Wfield(w, f) -> Ifield (ivar_of_extvalue w, f) - | Wwhen(w, _, _) -> ivar_of_extvalue w + | Wwhen(w, _, _) -> Iwhen (ivar_of_extvalue w, w'.w_ck) | Wconst _ -> raise Const_extvalue | Wreinit (_, w) -> ivar_of_extvalue w @@ -100,10 +106,10 @@ module InterfRead = struct let read_extvalue funs acc w = (* recursive call *) - let _, acc = Mls_mapfold.extvalue funs acc w in + (*let _, acc = Mls_mapfold.extvalue funs acc w in*) let acc = try - IvarSet.add (ivar_of_extvalue w) acc + (ivar_of_extvalue w)::acc with | Const_extvalue -> acc in @@ -115,17 +121,19 @@ module InterfRead = struct (* special cases *) let acc = match e.e_desc with | Emerge(x,_) | Eapp(_, _, Some x) - | Eiterator (_, _, _, _, _, Some x) -> IvarSet.add (Ivar x) acc + | Eiterator (_, _, _, _, _, Some x) -> (Ivar x)::acc | _ -> acc in e, acc let rec vars_pat acc = function - | Evarpat x -> IvarSet.add (Ivar x) acc + | Evarpat x -> x::acc | Etuplepat pat_list -> List.fold_left vars_pat acc pat_list let def eq = - vars_pat IvarSet.empty eq.eq_lhs + vars_pat [] eq.eq_lhs + let def_ivars eq = + List.map (fun x -> Ivar x) (def eq) let rec nth_var_from_pat j pat = match j, pat with @@ -137,7 +145,7 @@ module InterfRead = struct let funs = { Mls_mapfold.defaults with Mls_mapfold.exp = read_exp; Mls_mapfold.extvalue = read_extvalue } in - let _, acc = Mls_mapfold.exp_it funs IvarSet.empty e in + let _, acc = Mls_mapfold.exp_it funs [] e in acc let read eq = @@ -147,7 +155,7 @@ end module World = struct let vds = ref Env.empty - let memories = ref IvarSet.empty + let memories = ref IdentSet.empty let igs = ref [] let init f = @@ -161,14 +169,15 @@ module World = struct let env = match f.n_contract with None -> env - | Some c -> + | Some c -> let env = build env c.c_local in build env c.c_controllables in igs := []; vds := env; - (* build the set of memories *) + (* build the set of memories *) let mems = Mls_utils.node_memory_vars f in - memories := List.fold_left (fun s (x, _) -> IvarSet.add (Ivar x) s) IvarSet.empty mems + let s = List.fold_left (fun s (x, _) -> IdentSet.add x s) IdentSet.empty mems in + memories := s let vd_from_ident x = try Env.find x !vds @@ -184,6 +193,13 @@ module World = struct let n = Modules.find_field f in let fields = Modules.find_struct n in Signature.field_assoc f fields + | Iwhen (iv, _) -> ivar_type iv + + let ivar_clock iv = match iv with + | Iwhen (_, ck) -> ck + | _ -> + let vd = vd_from_ident (var_ident_of_ivar iv) in + vd.v_clock let is_optimized_ty ty = (!Compiler_options.interf_all (* && not (is_enum ty)) *) ) || is_array_or_struct ty @@ -192,19 +208,19 @@ module World = struct is_optimized_ty (ivar_type iv) let is_memory x = - IvarSet.mem (Ivar x) !memories + IdentSet.mem x !memories let node_for_ivar iv = let rec _node_for_ivar igs iv = match igs with - | [] -> print_debug1 "Var not in graph: %s@." (ivar_to_string iv); raise Not_found + | [] -> print_debug "Var not in graph: %a@." print_ivar iv; raise Not_found | ig::igs -> (try ig, node_for_value ig iv with Not_found -> _node_for_ivar igs iv) in - _node_for_ivar !igs iv + _node_for_ivar !igs (remove_iwhen iv) let node_for_name x = node_for_ivar (Ivar x) @@ -243,6 +259,7 @@ let add_same_value_link_from_ivar = by_ivar () add_affinity_link let coalesce_from_name = by_name () coalesce let coalesce_from_ivar = by_ivar () coalesce let have_same_value_from_name = by_name false have_same_value +let have_same_value_from_ivar = by_ivar false have_same_value let remove_from_ivar iv = try @@ -252,87 +269,70 @@ let remove_from_ivar iv = | Not_found -> (* var not in graph, just ignore it *) () -(** Adds all the fields of a variable to the set [s] (when it corresponds to a record). *) -let rec all_ivars s iv ty = - let s = if World.is_optimized_ty ty then IvarSet.add iv s else s in - match Modules.unalias_type ty with - | Tid n -> - (try - let fields = Modules.find_struct n in - List.fold_left (fun s { f_name = n; f_type = ty } -> - all_ivars s (Ifield(iv, n)) ty) s fields - with - Not_found -> s - ) - | _ -> s +(** Adds all the fields of a variable to the list [l] (when it corresponds to a record). *) +let rec all_ivars l iv ck ty = + if not (World.is_optimized_ty ty) then + l + else ( + let iv' = match ck with None -> iv | Some ck -> Iwhen(iv, ck) in + let l = iv'::l in + match Modules.unalias_type ty with + | Tid n -> + (try + let fields = Modules.find_struct n in + List.fold_left (all_ivars_field iv ck) l fields + with + Not_found -> l + ) + | _ -> l + ) -let all_ivars_set ivs = - IvarSet.fold (fun iv s -> all_ivars s iv (World.ivar_type iv)) ivs IvarSet.empty +and all_ivars_field iv ck l { f_name = n; f_type = ty } = + let new_iv = match ck with + | None -> Ifield(iv, n) + | Some ck -> Iwhen (Ifield(iv, n), ck) + in + all_ivars l new_iv ck ty - -(** Returns a map giving the number of uses of each ivar in the equations [eqs]. *) -let compute_uses eqs = - let aux env eq = - let incr_uses iv env = - if IvarEnv.mem iv env then - IvarEnv.add iv ((IvarEnv.find iv env) + 1) env - else - IvarEnv.add iv 1 env +let all_ivars_list ivs = + let add_one acc iv = + let ck = match iv with + | Iwhen (_, ck) -> Some ck + | _ -> None in - let ivars = all_ivars_set (InterfRead.read eq) in - IvarSet.fold incr_uses ivars env + let iv = remove_iwhen iv in + all_ivars acc iv ck (World.ivar_type iv) in - List.fold_left aux IvarEnv.empty eqs + List.fold_left add_one [] ivs -let number_uses iv uses = - try - IvarEnv.find iv uses - with - | Not_found -> - (* add one use for memories without any use to make sure they interfere - with other memories and outputs. *) - (match iv with - | Ivar x when World.is_memory x -> 1 - | _ -> 0) - -let add_uses uses iv env = - let ivars = all_ivars IvarSet.empty iv (World.ivar_type iv) in - IvarSet.fold (fun iv env -> IvarEnv.add iv (number_uses iv uses) env) ivars env - -let decr_uses iv env = - try - IvarEnv.add iv ((IvarEnv.find iv env) - 1) env - with - | Not_found -> - print_debug1 "Cannot decrease; var not found : %s@." (ivar_to_string iv); assert false - -(** TODO: compute correct live range for variables wit no use ?*) +(* TODO: variables with no use ?? *) let compute_live_vars eqs = - let uses = compute_uses eqs in - print_debug_ivar_env "Uses" uses; - let aux (env,res) eq = - let alive_vars = IvarEnv.fold (fun iv n acc -> if n > 0 then iv::acc else acc) env [] in - print_debug1 "Alive vars : %s@." (String.concat " " (List.map ivar_to_string alive_vars)); - let read_ivars = all_ivars_set (InterfRead.read eq) in - let env = IvarSet.fold decr_uses read_ivars env in - let res = (eq, alive_vars)::res in - let env = IvarSet.fold (add_uses uses) (InterfRead.def eq) env in - print_debug_ivar_env "Remaining uses" env; - env, res + let aux (alive_vars, res) eq = + let read_ivars = all_ivars_list (InterfRead.read eq) in + let def_ivars = InterfRead.def eq in + (* add vars used in the equation *) + let alive_vars = List.fold_left VarEnv.add_ivar alive_vars read_ivars in + (* remove vars defined in this equation *) + let alive_vars = + List.fold_left (fun alive_vars id -> VarEnv.remove id alive_vars) alive_vars def_ivars + in + print_debug "%a@," Mls_printer.print_eq eq; + print_debug_var_env "alive" alive_vars; + let alive_vars_list = VarEnv.fold (fun _ ivs acc -> (IvarSet.elements ivs)@acc) alive_vars [] in + let res = (eq, alive_vars_list)::res in + alive_vars, res in - let env = IvarSet.fold (add_uses uses) !World.memories IvarEnv.empty in - let _, res = List.fold_left aux (env, []) eqs in + let _, res = List.fold_left aux (VarEnv.empty, []) (List.rev eqs) in res - -let rec disjoint_clock is_mem ck1 ck2 = +let rec disjoint_clock ck1 ck2 = match Clocks.ck_repr ck1, Clocks.ck_repr ck2 with | Cbase, Cbase -> false | Con(ck1, c1, n1), Con(ck2,c2,n2) -> - if ck1 = ck2 & n1 = n2 & c1 <> c2 & not is_mem then + if ck1 = ck2 & n1 = n2 & c1 <> c2 then true else - disjoint_clock is_mem ck1 ck2 + disjoint_clock ck1 ck2 (*let separated_by_reset = (match x_is_mem, y_is_mem with | true, true -> are_separated_by_reset c1 c2 @@ -341,29 +341,41 @@ let rec disjoint_clock is_mem ck1 ck2 = (** [should_interfere x y] returns whether variables x and y can interfere. *) -let should_interfere (x, y) = - let vdx = World.vd_from_ident x in - let vdy = World.vd_from_ident y in - if Global_compare.type_compare vdx.v_type vdy.v_type <> 0 then +let should_interfere (ivx, ivy) = + let tyx = World.ivar_type ivx in + let tyy = World.ivar_type ivy in + if Global_compare.type_compare tyx tyy <> 0 then false else ( - let x_is_mem = World.is_memory x in - let y_is_mem = World.is_memory y in - let are_copies = have_same_value_from_name x y in - let disjoint_clocks = disjoint_clock (x_is_mem || y_is_mem) vdx.v_clock vdy.v_clock in + let x_is_mem = World.is_memory (var_ident_of_ivar ivx) in + let x_is_when = is_when_ivar ivx in + let y_is_mem = World.is_memory (var_ident_of_ivar ivy) in + let y_is_when = is_when_ivar ivy in + let ckx = World.ivar_clock ivx in + let cky = World.ivar_clock ivy in + let are_copies = have_same_value_from_ivar ivx ivy in + (* a register with a slow clock is still alive even when it is not activated. + However, if we read a fast register on a slow rhythm, + we can share it with other variables on disjoint slow rhythms as we know + that the value of the register will + be done at the end of the step. *) + let disjoint_clocks = + not ((x_is_mem && not x_is_when) || (y_is_mem && not y_is_when)) && disjoint_clock ckx cky + in not (disjoint_clocks or are_copies) ) let should_interfere = Misc.memoize_couple should_interfere + (** Builds the (empty) interference graphs corresponding to the variable declaration list vds. It just creates one graph per type and one node per declaration. *) let init_interference_graph () = (** Adds a node for the variable and all fields of a variable. *) let rec add_ivar env iv ty = - let ivars = all_ivars IvarSet.empty iv ty in - IvarSet.fold (fun iv env -> TyEnv.add_element (World.ivar_type iv) (mk_node iv) env) ivars env + let ivars = all_ivars [] iv None ty in + List.fold_left (fun env iv -> TyEnv.add_element (World.ivar_type iv) (mk_node iv) env) env ivars in let env = Env.fold (fun _ vd env -> add_ivar env (Ivar vd.v_ident) vd.v_type) !World.vds TyEnv.empty in @@ -375,12 +387,9 @@ let init_interference_graph () = whatever the variables are, without checking if interference is real. *) let rec add_interferences_from_list force vars = - let add_interference x y = - match x, y with - | Ivar x, Ivar y -> - if force or should_interfere (x, y) then - add_interference_link_from_ivar (Ivar x) (Ivar y) - | _, _ -> add_interference_link_from_ivar x y + let add_interference ivx ivy = + if force or should_interfere (ivx, ivy) then + add_interference_link_from_ivar ivx ivy in Misc.iter_couple add_interference vars @@ -393,24 +402,24 @@ let add_interferences live_vars = (** Spill non linear inputs. *) let spill_inputs f = let spilled_inp = List.filter (fun vd -> not (is_linear vd.v_linearity)) f.n_input in - let spilled_inp = List.fold_left - (fun s vd -> IvarSet.add (Ivar vd.v_ident) s) IvarSet.empty spilled_inp in - let spilled_inp = all_ivars_set spilled_inp in - IvarSet.iter remove_from_ivar spilled_inp + let spilled_inp = List.map (fun vd -> Ivar vd.v_ident) spilled_inp in + let spilled_inp = all_ivars_list spilled_inp in + List.iter remove_from_ivar spilled_inp (** If we optimize all types, we need to spill outputs and memories so that register allocation by the C compiler is not disturbed. *) let spill_mems_outputs f = - let add_output s vd = - if not (is_array_or_struct vd.v_type) then IvarSet.add (Ivar vd.v_ident) s else s + let add_output l vd = + if not (is_array_or_struct vd.v_type) then (Ivar vd.v_ident)::l else l in - let add_memory iv s = - if not (is_array_or_struct (World.ivar_type iv)) then IvarSet.add iv s else s + let add_memory x l = + let iv = Ivar x in + if not (is_array_or_struct (World.ivar_type iv)) then iv::l else l in - let spilled_vars = List.fold_left add_output IvarSet.empty f.n_output in - let spilled_vars = IvarSet.fold add_memory !World.memories spilled_vars in - let spilled_vars = all_ivars_set spilled_vars in - IvarSet.iter remove_from_ivar spilled_vars + let spilled_vars = List.fold_left add_output [] f.n_output in + let spilled_vars = IdentSet.fold add_memory !World.memories spilled_vars in + let spilled_vars = all_ivars_list spilled_vars in + List.iter remove_from_ivar spilled_vars (** [filter_vars l] returns a list of variables whose fields appear in a list of ivar.*) @@ -479,7 +488,7 @@ let process_eq ({ eq_lhs = pat; eq_rhs = e } as eq) = | _, Eiterator((Imap|Imapi), { a_op = Enode _ | Efun _ }, _, pw_list, w_list, _) -> let invars = InterfRead.ivars_of_extvalues w_list in let pinvars = InterfRead.ivars_of_extvalues pw_list in - let outvars = IvarSet.elements (InterfRead.def eq) in + let outvars = InterfRead.def_ivars eq in (* because of the encoding of the fold, the outputs are written before the partially applied inputs are read so they must interfere *) List.iter (fun inv -> List.iter (add_interference_link_from_ivar inv) outvars) pinvars; @@ -516,10 +525,27 @@ let process_eq ({ eq_lhs = pat; eq_rhs = e } as eq) = add_affinity_link_from_ivar (InterfRead.ivar_of_extvalue w) (Ivar x) with | InterfRead.Const_extvalue -> ()) - | Evarpat x, Eapp({ a_op = Eupdate | Efield_update }, args, _) -> - let w, _ = Misc.assert_1min args in + | Evarpat x, Eapp({ a_op = Eupdate }, args, _) -> + let w, _ = Misc.assert_1min args in (try - add_affinity_link_from_ivar (InterfRead.ivar_of_extvalue w) (Ivar x) + add_affinity_link_from_ivar (InterfRead.ivar_of_extvalue w) (Ivar x) + with + | InterfRead.Const_extvalue -> ()) + | Evarpat x, Eapp({ a_op = Efield_update }, args, _) -> + let w1, w2 = Misc.assert_2 args in + (* if we generate code for o = { a with .f = b } that is: + o=a; o.f = b + then we need to make sure that b interferes with all fields of o *) + if !Compiler_options.memcpy_array_and_struct then + (try + let all_iv = all_ivars [] (Ivar x) None w1.w_ty in + let iv2 = InterfRead.ivar_of_extvalue w2 in + List.iter (add_interference_link_from_ivar iv2) all_iv; + with + | InterfRead.Const_extvalue -> ()); + (try + let iv1 = InterfRead.ivar_of_extvalue w1 in + add_affinity_link_from_ivar iv1 (Ivar x) with | InterfRead.Const_extvalue -> ()) | Evarpat x, Eextvalue w -> @@ -533,12 +559,26 @@ let process_eq ({ eq_lhs = pat; eq_rhs = e } as eq) = (** Add the special init and return equations to the dependency graph (resp at the bottom and top) *) let add_init_return_eq f = + let pat_from_dec_list decs = + Etuplepat (List.map (fun vd -> Evarpat vd.v_ident) decs) + in + + let tuple_from_dec_and_mem_list decs = + let exp_of_vd vd = + mk_extvalue ~clock:vd.v_clock ~ty:vd.v_type ~linearity:vd.v_linearity (Wvar vd.v_ident) + in + let exp_of_mem x = exp_of_vd (World.vd_from_ident x) in + let decs = List.map exp_of_vd decs in + let mems = IdentSet.fold (fun iv acc -> (exp_of_mem iv)::acc) !World.memories [] in + Eapp(mk_app Earray, decs@mems, None) + in + (** a_1,..,a_p = __init__ *) - let eq_init = mk_equation false (Mls_utils.pat_from_dec_list f.n_input) + let eq_init = mk_equation false (pat_from_dec_list f.n_input) (mk_extvalue_exp Cbase Initial.tint Ltop (Wconst (Initial.mk_static_int 0))) in - (** __return__ = o_1,..,o_q *) + (** __return__ = o_1,..,o_q, mem_1, ..., mem_k *) let eq_return = mk_equation false (Etuplepat []) - (mk_exp Cbase Tinvalid Ltop (Mls_utils.tuple_from_dec_list f.n_output)) in + (mk_exp Cbase Tinvalid Ltop (tuple_from_dec_and_mem_list f.n_output)) in (eq_init::f.n_equs)@[eq_return] diff --git a/compiler/minils/mls_utils.ml b/compiler/minils/mls_utils.ml index 3297f06..afcfc8f 100644 --- a/compiler/minils/mls_utils.ml +++ b/compiler/minils/mls_utils.ml @@ -65,15 +65,6 @@ let is_record_type ty = match ty with let is_op = function | { qual = Pervasives; name = _ } -> true | _ -> false -let pat_from_dec_list decs = - Etuplepat (List.map (fun vd -> Evarpat vd.v_ident) decs) - -let tuple_from_dec_list decs = - let aux vd = - mk_extvalue ~clock:vd.v_clock ~ty:vd.v_type ~linearity:vd.v_linearity (Wvar vd.v_ident) - in - Eapp(mk_app Earray, List.map aux decs, None) - module Vars = struct let add x acc = if List.mem x acc then acc else x :: acc diff --git a/compiler/minils/transformations/schedule_interf.ml b/compiler/minils/transformations/schedule_interf.ml index 52ae38b..7af8e13 100644 --- a/compiler/minils/transformations/schedule_interf.ml +++ b/compiler/minils/transformations/schedule_interf.ml @@ -5,6 +5,8 @@ open Minils open Mls_utils open Misc open Sgraph +open Interference +open Interference_graph (** In order to put together equations with the same control structure, we have to take into account merge equations, that will to be translated to two instructions on slow clocks @@ -14,13 +16,44 @@ let control_ck eq = | Emerge (_, (_, w)::_) -> w.w_ck | _ -> Mls_utils.Vars.clock eq +(** Returns a map giving the number of uses of each ivar in the equations [eqs]. *) +let compute_uses eqs = + let aux env eq = + let incr_uses env iv = + if IvarEnv.mem iv env then + IvarEnv.add iv ((IvarEnv.find iv env) + 1) env + else + IvarEnv.add iv 1 env + in + let ivars = all_ivars_list (InterfRead.read eq) in + List.fold_left incr_uses env ivars + in + List.fold_left aux IvarEnv.empty eqs + +let number_uses iv uses = + try + IvarEnv.find iv uses + with + | Not_found -> + (* add one use for memories without any use to make sure they interfere + with other memories and outputs. *) + (match iv with + | Ivar x when World.is_memory x -> 1 + | _ -> 0) + +let add_uses uses env iv = + let ivars = all_ivars [] iv None (World.ivar_type iv) in + List.fold_left (fun env iv -> IvarEnv.add iv (number_uses iv uses) env) env ivars + +let decr_uses env iv = + try + IvarEnv.add iv ((IvarEnv.find iv env) - 1) env + with + | Not_found -> + print_debug "Cannot decrease; var not found : %a@." print_ivar iv; assert false + module Cost = struct - open Interference_graph - open Interference - - - (** Remove from the elements the elements whose value is zero or negative. *) let remove_null m = let check_not_null k d m = @@ -31,38 +64,40 @@ struct (** Returns the list of variables killed by an equation (ie vars used by the equation and with use count equal to 1). *) let killed_vars eq env = - let is_killed iv acc = + let is_killed acc iv = try if IvarEnv.find iv env = 1 then acc + 1 else acc with | Not_found -> - Format.printf "Var not found in kill_vars %s@." (ivar_to_string iv); assert false + Format.printf "Var not found in kill_vars %a@." print_ivar iv; assert false in - IvarSet.fold is_killed (all_ivars_set (InterfRead.read eq)) 0 + let used_ivars = List.map remove_iwhen (all_ivars_list (InterfRead.read eq)) in + List.fold_left is_killed 0 used_ivars (** Initialize the costs data structure. *) let init_cost uses inputs = - let env = IvarSet.fold (add_uses uses) !World.memories IvarEnv.empty in + let env = IdentSet.fold (fun x env -> add_uses uses env (Ivar x)) !World.memories IvarEnv.empty in let inputs = List.map (fun vd -> Ivar vd.v_ident) inputs in - List.fold_left (fun env iv -> add_uses uses iv env) env inputs + List.fold_left (add_uses uses) env inputs (** [update_cost eq uses env] updates the costs data structure after eq has been chosen as the next equation to be scheduled. It updates uses and adds the new variables defined by this equation. *) let update_cost eq uses env = - let env = IvarSet.fold decr_uses (all_ivars_set (InterfRead.read eq)) env in - IvarSet.fold (add_uses uses) (InterfRead.def eq) env + let used_ivars = List.map remove_iwhen (all_ivars_list (InterfRead.read eq)) in + let env = List.fold_left decr_uses env used_ivars in + List.fold_left (add_uses uses) env (InterfRead.def_ivars eq) (** Returns the next equation, chosen from the list of equations rem_eqs *) let next_equation rem_eqs ck env = let bonus eq = match eq.eq_rhs.e_desc with - | Eapp ({a_op = (Eupdate _ | Efield_update _) },_,_) -> 1 + | Eapp ({a_op = (Eupdate | Efield_update) },_,_) -> 1 | _ -> 0 in let cost eq = let nb_killed_vars = killed_vars eq env in - let nb_def_vars = IvarSet.cardinal (all_ivars_set (InterfRead.def eq)) in + let nb_def_vars = List.length (all_ivars_list (InterfRead.def_ivars eq)) in let b = bonus eq in if verbose_mode then Format.eprintf "(%d,%d,%d)%a@." nb_killed_vars nb_def_vars b Mls_printer.print_eq eq; @@ -114,7 +149,7 @@ let remove_eq eq node_list = (** Main function to schedule a node. *) let schedule eq_list inputs node_list = - let uses = Interference.compute_uses eq_list in + let uses = compute_uses eq_list in Interference.print_debug_ivar_env "uses" uses; let rec schedule_aux rem_eqs sched_eqs node_list ck costs = match rem_eqs with @@ -140,7 +175,7 @@ let schedule eq_list inputs node_list = let schedule_contract contract c_inputs = match contract with None -> None, [] - | Some c -> + | Some c -> let node_list, _ = DataFlowDep.build c.c_eq in (Some { c with c_eq = schedule c.c_eq c_inputs node_list; }), c.c_controllables @@ -150,7 +185,7 @@ let node _ () f = let contract,controllables = schedule_contract f.n_contract (f.n_input@f.n_output) in let node_list, _ = DataFlowDep.build f.n_equs in (* Controllable variables are considered as inputs *) - let f = { f with + let f = { f with n_equs = schedule f.n_equs (f.n_input@controllables) node_list; n_contract = contract } in f, () diff --git a/compiler/obc/transformations/memalloc_apply.ml b/compiler/obc/transformations/memalloc_apply.ml index 78f3b25..735bc30 100644 --- a/compiler/obc/transformations/memalloc_apply.ml +++ b/compiler/obc/transformations/memalloc_apply.ml @@ -34,11 +34,13 @@ let rec repr_from_ivar env iv = let ty = Tid (Modules.find_field f) in let lhs = mk_pattern ty (repr_from_ivar env iv) in Lfield(lhs, f) + | Iwhen _ -> assert false let rec choose_record_field env l = match l with | [iv] -> repr_from_ivar env iv | (Ivar _)::l -> choose_record_field env l | (Ifield(iv,f))::_ -> repr_from_ivar env (Ifield(iv,f)) + | (Iwhen _ )::_ -> assert false | [] -> assert false (** Chooses from a list of vars (with the same color in the interference graph) @@ -56,14 +58,10 @@ let choose_representative m inputs outputs mems ty vars = | [], [Ivar vout], [] -> Lvar vout | [Ivar vin], [Ivar _], [] -> Lvar vin | _, _, _ -> - Interference.print_debug0 "@.Something is wrong with the coloring : "; - Interference.print_debug1 "%s@." (String.concat " " (List.map ivar_to_string vars)); - Interference.print_debug0 "\tInputs : "; - Interference.print_debug1 "%s@." (String.concat " " (List.map ivar_to_string inputs)); - Interference.print_debug0 "\tOutputs : "; - Interference.print_debug1 "%s@." (String.concat " " (List.map ivar_to_string outputs)); - Interference.print_debug0 "\tMem : "; - Interference.print_debug1 "%s@." (String.concat " " (List.map ivar_to_string mems)); + Interference.print_debug "@.Something is wrong with the coloring : %a@." print_ivar_list vars; + Interference.print_debug "\tInputs : %a@." print_ivar_list inputs; + Interference.print_debug "\tOutputs : %a@." print_ivar_list outputs; + Interference.print_debug "\tMem : %a@." print_ivar_list mems; assert false (*something went wrong in the coloring*) in mk_pattern ty desc diff --git a/compiler/utilities/global/compiler_options.ml b/compiler/utilities/global/compiler_options.ml index 7f0e549..5def962 100644 --- a/compiler/utilities/global/compiler_options.ml +++ b/compiler/utilities/global/compiler_options.ml @@ -116,6 +116,13 @@ let do_mem_alloc_and_typing () = let use_old_scheduler = ref false let strict_ssa = ref false +(* if this option is on, generate code that first copies the whole array and then modifies one element. + Otherwise, generate two loops so that each element in the array is only assigned once. *) +let memcpy_array_and_struct = ref true + +let set_strict_ssa () = + strict_ssa := true; + memcpy_array_and_struct := false let unroll_loops = ref false diff --git a/compiler/utilities/minils/interference2dot.ml b/compiler/utilities/minils/interference2dot.ml index a6aedf2..8ac0cb5 100644 --- a/compiler/utilities/minils/interference2dot.ml +++ b/compiler/utilities/minils/interference2dot.ml @@ -25,11 +25,13 @@ module DotG = struct match iv with | Ivar id -> Idents.name id | Ifield(ivar, f) -> (ivar_name ivar)^"_"^(Names.shortname f) + | Iwhen _ -> assert false in Misc.sanitize_string (ivar_name (List.hd !(V.label v))) let vertex_attributes v = - let s = String.concat ", " (List.map (fun iv -> ivar_to_string iv) !(V.label v)) in + Format.fprintf Format.str_formatter "%a" print_ivar_list !(V.label v); + let s = Format.flush_str_formatter () in [`Label s; `Color (color_to_graphviz_color (Mark.get v))] let edge_attributes e = diff --git a/compiler/utilities/minils/interference_graph.ml b/compiler/utilities/minils/interference_graph.ml index 6ceadd0..a9887d2 100644 --- a/compiler/utilities/minils/interference_graph.ml +++ b/compiler/utilities/minils/interference_graph.ml @@ -1,3 +1,6 @@ +open Format +open Pp_tools +open Global_printer open Graph type ilink = @@ -8,22 +11,59 @@ type ilink = type ivar = | Ivar of Idents.var_ident | Ifield of ivar * Names.field_name + | Iwhen of ivar * Clocks.ck + +let rec ivar_compare iv1 iv2 = match iv1, iv2 with + | Ivar x1, Ivar x2 -> Idents.ident_compare x1 x2 + | Iwhen (iiv1, ck1), Iwhen (iiv2, ck2) -> + let cr = Global_compare.clock_compare ck1 ck2 in + if cr <> 0 then cr else ivar_compare iiv1 iiv2 + | Ifield (iiv1, f1), Ifield (iiv2, f2) -> + let cr = Pervasives.compare f1 f2 in + if cr <> 0 then cr else ivar_compare iiv1 iiv2 + + | Ivar _, _ -> 1 + | Iwhen _, Ivar _ -> -1 + | Iwhen _, _ -> 1 + | Ifield _, _ -> -1 module IvarEnv = Map.Make (struct type t = ivar - let compare = compare + let compare = ivar_compare end) module IvarSet = Set.Make (struct type t = ivar - let compare = compare + let compare = ivar_compare end) -let rec ivar_to_string = function - | Ivar n -> Idents.name n - | Ifield(iv,f) -> (ivar_to_string iv)^"."^(Names.shortname f) +let rec print_ivar ff iv = match iv with + | Ivar n -> print_ident ff n + | Ifield(iv,f) -> fprintf ff "%a.%a" print_ivar iv print_qualname f + | Iwhen(iv, ck) -> fprintf ff "%a::%a" print_ivar iv print_ck ck + +let print_ivar_list ff l = + fprintf ff "@[<2>%a@]" (print_list_r print_ivar "("","")") l + +let rec var_ident_of_ivar iv = match iv with + | Iwhen (iv, _) -> var_ident_of_ivar iv + | Ifield (iv, _) -> var_ident_of_ivar iv + | Ivar x -> x + +let rec remove_iwhen iv = match iv with + | Iwhen (iv, _) -> remove_iwhen iv + | Ifield (iv, f) -> Ifield (remove_iwhen iv, f) + | _ -> iv + +let remove_inner_iwhen iv = match iv with + | Iwhen (iv, ck) -> Iwhen (remove_iwhen iv, ck) + | _ -> remove_iwhen iv + +let is_when_ivar iv = match iv with + | Iwhen _ -> true + | _ -> false module VertexValue = struct type t = ivar list ref diff --git a/test/good/memalloc_clocks.ept b/test/good/memalloc_clocks.ept new file mode 100644 index 0000000..89ee750 --- /dev/null +++ b/test/good/memalloc_clocks.ept @@ -0,0 +1,6 @@ +node f(c:bool) = (o:int) +var last t:int^100 = 1^100; +let + t = merge c ((last t) when c) ([((last t) whenot c) with [0] = 0]); + o = t[0]; +tel \ No newline at end of file