Fixed interference of fast memories

A fast memory should be considered alive during
the whole step function when its clock is false.
This commit is contained in:
Cédric Pasteur 2013-05-06 11:47:05 +02:00
parent 99dc7820c7
commit a00620ca19
5 changed files with 98 additions and 27 deletions

View file

@ -164,11 +164,12 @@ let rec first_ck ct = match ct with
| Cprod [] -> assert false
| Cprod (ct::_) -> first_ck ct
let rec list_of_samplers acc ck = match ck with
| Cbase | Cvar { contents = Cindex _ } -> acc
| Con(ck, c, x) -> list_of_samplers ((c, x)::acc) ck
| Cvar { contents = Clink ck } -> list_of_samplers acc ck
let are_disjoint ck1 ck2 =
let rec list_of_samplers acc ck = match ck with
| Cbase | Cvar _ -> acc
| Con(ck, c, x) -> list_of_samplers ((c, x)::acc) ck
in
let rec disjoint_samplers s_ck1 s_ck2 = match s_ck1, s_ck2 with
| [], _ -> false
| _ , [] -> false
@ -179,3 +180,16 @@ let are_disjoint ck1 ck2 =
c1 <> c2 || disjoint_samplers s_ck1 s_ck2
in
disjoint_samplers (list_of_samplers [] ck1) (list_of_samplers [] ck2)
(* returns whether ck1 is included in ck2. *)
let is_subclock ck1 ck2 =
let rec sub_samplers s_ck1 s_ck2 = match s_ck1, s_ck2 with
| _, [] -> true
| [], _ -> false
| (c1, x1)::s_ck1, (c2, x2)::s_ck2 ->
if Idents.ident_compare x1 x2 <> 0 then
false
else
c1 = c2 && sub_samplers s_ck1 s_ck2
in
sub_samplers (list_of_samplers [] ck1) (list_of_samplers [] ck2)

View file

@ -54,6 +54,15 @@ module VarEnv = struct
add x (IvarSet.add iv (find x env)) env
else
add x (IvarSet.singleton iv) env
let remove_except_mem x env =
if mem x env then (
let s = IvarSet.filter is_mem_ivar (find x env) in
if IvarSet.is_empty s then
remove x env
else
add x s env
) else env
end
let print_debug fmt =
@ -214,7 +223,7 @@ module World = struct
Misc.internal_error "interference"
let rec ivar_type iv = match iv with
| Ivar x ->
| Ivar x | Imem x ->
let vd = vd_from_ident x in
vd.v_type
| Ifield(_, f) ->
@ -333,6 +342,11 @@ let all_ivars_list ivs =
in
List.fold_left add_one [] ivs
let is_fast_memory x =
match ck_repr (World.ivar_clock (Imem x)) with
| Cbase -> false
| _ -> true
(* TODO: variables with no use ?? *)
let compute_live_vars eqs =
let aux (alive_vars, res) eq =
@ -342,7 +356,7 @@ let compute_live_vars eqs =
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
List.fold_left (fun alive_vars id -> VarEnv.remove_except_mem id alive_vars) alive_vars def_ivars
in
print_debug "%a@," Mls_printer.print_eq eq;
print_debug_var_env "alive" alive_vars;
@ -350,7 +364,12 @@ let compute_live_vars eqs =
let res = (eq, alive_vars_list)::res in
alive_vars, res
in
let _, res = List.fold_left aux (VarEnv.empty, []) (List.rev eqs) in
let add_mem x env =
if is_fast_memory x then VarEnv.add_ivar env (Imem x) else env
in
(* Adds all ivars representing memories *)
let env = IdentSet.fold add_mem !World.memories VarEnv.empty in
let _, res = List.fold_left aux (env, []) (List.rev eqs) in
res
(** [should_interfere x y] returns whether variables x and y
@ -361,22 +380,33 @@ let should_interfere (ivx, ivy) =
if Global_compare.type_compare tyx tyy <> 0 then
false
else (
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)) && Clocks.are_disjoint ckx cky
in
not (disjoint_clocks or are_copies)
match ivx, ivy with
| Imem _, Imem _ ->
let ckx = World.ivar_clock ivx in
let cky = World.ivar_clock ivy in
Global_compare.clock_compare ckx cky <> 0
| Imem x, iv | iv, Imem x ->
let ckx = World.ivar_clock (Imem x) in
let ck = World.ivar_clock iv in
not (Clocks.is_subclock ck ckx)
| _, _ ->
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)) && Clocks.are_disjoint ckx cky
in
not (disjoint_clocks or are_copies)
)
let should_interfere = Misc.memoize_couple should_interfere
@ -397,7 +427,13 @@ let init_interference_graph () =
in
let env = Env.fold
(fun _ vd env -> add_ivar env (Ivar vd.v_ident) vd.v_type) !World.vds TyEnv.empty in
World.igs := TyEnv.fold (fun ty l acc -> (mk_graph l ty)::acc) env []
(* add special nodes for fast memories *)
let env =
IdentSet.fold
(fun x env -> if is_fast_memory x then add_tyenv env (Imem x) else env)
!World.memories env
in
World.igs := TyEnv.fold (fun ty l acc -> (mk_graph l ty)::acc) env []
(** Adds interferences between all the variables in
@ -599,6 +635,12 @@ let add_init_return_eq f =
(mk_exp Cbase Tinvalid Ltop (tuple_from_dec_and_mem_list f.n_output)) in
(eq_init::f.n_equs)@[eq_return]
(** Coalesce Imem x and Ivar x *)
let coalesce_mems () =
let coalesce_mem x =
if is_fast_memory x then coalesce_from_ivar (Imem x) (Ivar x)
in
IdentSet.iter coalesce_mem !World.memories
let build_interf_graph f =
World.init f;
@ -616,6 +658,8 @@ let build_interf_graph f =
add_interferences live_vars;
(* Add interferences between records implied by IField values*)
add_records_field_interferences ();
(* Coalesce all Imem x and Ivar x *)
coalesce_mems ();
(* Splill inputs that are not modified *)
spill_inputs f;
(* Spill outputs and memories that are not arrays or struts*)

View file

@ -53,7 +53,7 @@ let rec ivar_of_ext_value w = match w.w_desc with
let rec repr_from_ivar env iv =
match iv with
| Ivar x ->
| Ivar x | Imem x ->
(try
let lhs = Env.find x env in lhs.pat_desc
with
@ -66,7 +66,7 @@ let rec repr_from_ivar env iv =
let rec choose_record_field env l = match l with
| [iv] -> repr_from_ivar env iv
| (Ivar _)::l -> choose_record_field env l
| (Ivar _)::l | (Imem _)::l -> choose_record_field env l
| (Ifield(iv,f))::_ -> repr_from_ivar env (Ifield(iv,f))
| (Iwhen _ )::_ -> assert false
| [] -> assert false

View file

@ -53,6 +53,7 @@ module DotG = struct
match iv with
| Ivar id -> Idents.name id
| Ifield(ivar, f) -> (ivar_name ivar)^"_"^(Names.shortname f)
| Imem id -> "mem("^Idents.name id^")"
| Iwhen _ -> assert false
in
Misc.sanitize_string (ivar_name (List.hd !(V.label v)))

View file

@ -40,6 +40,7 @@ type ivar =
| Ivar of Idents.var_ident
| Ifield of ivar * Names.field_name
| Iwhen of ivar * Clocks.ck
| Imem of Idents.var_ident
let rec ivar_compare iv1 iv2 = match iv1, iv2 with
| Ivar x1, Ivar x2 -> Idents.ident_compare x1 x2
@ -49,11 +50,17 @@ let rec ivar_compare iv1 iv2 = match iv1, iv2 with
| Ifield (iiv1, f1), Ifield (iiv2, f2) ->
let cr = Pervasives.compare f1 f2 in
if cr <> 0 then cr else ivar_compare iiv1 iiv2
| Imem x1, Imem x2 -> Idents.ident_compare x1 x2
| Ivar _, _ -> 1
| Iwhen _, Ivar _ -> -1
| Iwhen _, _ -> 1
| Ifield _, _ -> -1
| Ifield _, (Ivar _ | Iwhen _) -> -1
| Ifield _, _ -> 1
| Imem _, _ -> -1
module IvarEnv =
Map.Make (struct
@ -71,6 +78,7 @@ 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
| Imem n -> fprintf ff "mem(%a)" print_ident n
let print_ivar_list ff l =
fprintf ff "@[<2>%a@]" (print_list_r print_ivar "("","")") l
@ -79,6 +87,7 @@ 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
| Imem x -> x
let rec remove_iwhen iv = match iv with
| Iwhen (iv, _) -> remove_iwhen iv
@ -92,6 +101,9 @@ let remove_inner_iwhen iv = match iv with
let is_when_ivar iv = match iv with
| Iwhen _ -> true
| _ -> false
let is_mem_ivar iv = match iv with
| Imem _ -> true
| _ -> false
module VertexValue = struct
type t = ivar list ref