diff --git a/dune-project b/dune-project index 48fa80dcef22b2e18c0772b6653cb27cd8fe0df3..ee105403ac7fb6420d212d0f640a8c3659652002 100644 --- a/dune-project +++ b/dune-project @@ -7,7 +7,7 @@ (using menhir 2.0) (generate_opam_files true) -(license LGPL) +(license LGPL-2.0-or-later) (authors "Pierre-Loic Garoche <ploc@garoche.net>" "Xavier Thirioux <thirioux@enseeiht.fr>") (maintainers "Pierre-Loic Garoche <ploc@garoche.net>" diff --git a/lustrec.opam b/lustrec.opam index c6305e6fd95ded6943fa7cb99cb17a9726eca931..a08dfd63d4a6ef511f00aab4da21fedbdd3f6d12 100644 --- a/lustrec.opam +++ b/lustrec.opam @@ -12,7 +12,7 @@ authors: [ "Pierre-Loic Garoche <ploc@garoche.net>" "Xavier Thirioux <thirioux@enseeiht.fr>" ] -license: "LGPL" +license: "LGPL-2.0-or-later" homepage: "https://gitlab.isae-supaero.fr/lustrec/lustrec" bug-reports: "https://gitlab.isae-supaero.fr/lustrec/lustrec/-/issues" depends: [ diff --git a/src/backends/C/c_backend_spec.ml b/src/backends/C/c_backend_spec.ml index d7f96b3e3f625aa80782c9432e5d74ccb9a983db..d02de9f4916ff54cdb77b14cebb7836d8f1da207 100644 --- a/src/backends/C/c_backend_spec.ml +++ b/src/backends/C/c_backend_spec.ml @@ -447,7 +447,7 @@ module PrintSpec = struct fmt (f, mem_in', mem_out, mem_in)) | GhostAssign (v1, v2) -> - pp_ghost (pp_assign m mem_in (pp_c_var_read m)) fmt (v1, vdecl_to_val v2) + pp_ghost (pp_assign m mem_in (pp_c_var_read m)) fmt (v1, v2) let reset_flag = dummy_var_decl "_reset" Type_predef.type_bool diff --git a/src/machine_code_common.ml b/src/machine_code_common.ml index b6cc3e8cff6aa7c9250c5cbbf01028f5515900a3..4da14354099a1c63d6612a08e4a7aee65496d7c3 100644 --- a/src/machine_code_common.ml +++ b/src/machine_code_common.ml @@ -88,8 +88,8 @@ module PrintSpec = struct inst (pp_print_option pp_print_int) i - | GhostAssign (v1, v2) -> - fprintf fmt "Ghost %s = %s" v1.var_id v2.var_id + | GhostAssign (v, e) -> + fprintf fmt "Ghost %s = %a" v.var_id (pp_val m) e let pp_spec m = let pp_expr fmt e = pp_expr m fmt e in diff --git a/src/optimize_machine.ml b/src/optimize_machine.ml index 93e430cd407d2d52b732966f710d800b9c3a3a47..d0adaa3677959c5a17cbce9f886e06c7e059d598 100644 --- a/src/optimize_machine.ml +++ b/src/optimize_machine.ml @@ -142,15 +142,8 @@ let rec eliminate_formula m elim = | f -> f -let eliminate_spec m elim = - List.map (fun (f, asrt) -> eliminate_formula m elim f, asrt) - -let eliminate_spec_instr m elim instr = - { instr with instr_spec = eliminate_spec m elim instr.instr_spec } - let rec eliminate m elim instr = let e_val = eliminate_val m elim in - let instr = eliminate_spec_instr m elim instr in match get_instr_desc instr with | MLocalAssign (i, v) -> update_instr_desc instr (MLocalAssign (i, e_val v)) @@ -411,6 +404,13 @@ let merge_elim elim1 elim2 = let get_exprs elim = IMap.map (fun (_, e, _) -> e) elim +let add_ghost_assign_spec i v spec = + (Predicate (GhostAssign (i, v)), false) :: spec + +let assign_comment m v e = + Format.(fprintf str_formatter "%s := %a" v.var_id (pp_val m) e); + MComment (Format.flush_str_formatter ()) + (* see if elim has to take in account the provided instr: if so, update elim and return the remove flag, otherwise, the expression should be kept and elim is left untouched *) @@ -472,9 +472,9 @@ let instrs_unfold m fanin elim instrs = IMap.mem v.var_id elim -> (* we transform the assignment into a comment in order to keep its spec *) - Format.(fprintf str_formatter "%s := %a" v.var_id (pp_val m) e); - let instr = eliminate_spec_instr m elim_exprs instr in - update_instr_desc instr (MComment (Format.flush_str_formatter ())) + { instr with + instr_spec = add_ghost_assign_spec v e instr.instr_spec; + instr_desc = assign_comment m v e } | MBranch (g, hl) -> let instr = update_instr_desc @@ -829,165 +829,166 @@ let predicate_spec_replace fvar = function | p -> p -let is_reused_reassigned m fvar asg v = - let r_asg = IMap.filter (fun _ n -> n > 1) asg in - List.exists (fun v' -> v.var_id = v'.var_id) m.mstep.step_locals - && List.exists (fun v' -> fvar v' = v && v <> v') m.mstep.step_locals - && IMap.mem v.var_id r_asg - -let ghost_vd v = { v with var_id = "__" ^ v.var_id } - -let rec instr_spec_replace m fvar asg t = - let aux instr = instr_spec_replace m fvar asg instr in - (* rename reused vars that appears freely in the formula before - substitution, *) - (* to handle the fact that those vars can be modified in a way that the - formula does not hold anymore *) - let fv_m = - VSet.fold - (fun v fv_m -> - if is_reused_reassigned m fvar asg v then - IMap.add v.var_id (ghost_vd v) fv_m - else fv_m) - (fv_formula m VSet.empty t) - IMap.empty - in - let fvar v = try IMap.find v.var_id fv_m with Not_found -> fvar v in - let t' = - match t with - | Equal (e1, e2) -> - Equal (expr_spec_replace fvar e1, expr_spec_replace fvar e2) - | GEqual (e1, e2) -> - GEqual (expr_spec_replace fvar e1, expr_spec_replace fvar e2) - | And f -> - And (List.map aux f) - | Or f -> - Or (List.map aux f) - | Imply (a, b) -> - Imply (aux a, aux b) - | Exists (xs, a) -> - let fvar v = if List.mem v xs then v else fvar v in - Exists (xs, instr_spec_replace m fvar asg a) - | Forall (xs, a) -> - let fvar v = if List.mem v xs then v else fvar v in - Forall (xs, instr_spec_replace m fvar asg a) - | Ternary (e, a, b) -> - Ternary (expr_spec_replace fvar e, aux a, aux b) - | Predicate p -> - Predicate (predicate_spec_replace fvar p) - | ExistsMem (f, a, b) -> - ExistsMem (f, aux a, aux b) - | f -> - f - in - (* let fv_t = VSet.of_list (IMap.bindings fv_m |> List.split |> snd) in *) - (* let fv = VSet.(elements (inter fv_t (fv_formula m empty t'))) in *) - (* Exists (fv, t') *) - t' - -let add_assigned v = - IMap.update v.var_id (function Some n -> Some (n + 1) | None -> Some 1) - -let silly_asg i v = - match v.value_desc with Var w -> w.var_id = i.var_id | _ -> false +let rec instr_spec_replace fvar t = + let aux t = instr_spec_replace fvar t in + match t with + | Equal (e1, e2) -> + Equal (expr_spec_replace fvar e1, expr_spec_replace fvar e2) + | GEqual (e1, e2) -> + GEqual (expr_spec_replace fvar e1, expr_spec_replace fvar e2) + | And f -> + And (List.map aux f) + | Or f -> + Or (List.map aux f) + | Imply (a, b) -> + Imply (aux a, aux b) + | Exists (xs, a) -> + let fvar v = if List.mem v xs then v else fvar v in + Exists (xs, instr_spec_replace fvar a) + | Forall (xs, a) -> + let fvar v = if List.mem v xs then v else fvar v in + Forall (xs, instr_spec_replace fvar a) + | Ternary (e, a, b) -> + Ternary (expr_spec_replace fvar e, aux a, aux b) + | Predicate p -> + Predicate (predicate_spec_replace fvar p) + | ExistsMem (f, a, b) -> + ExistsMem (f, aux a, aux b) + | f -> + f -let rec instr_replace_var m fvar (asg, instrs) instr = - let asg, instr_desc = +let rec instr_replace_var m fvar instrs instr = + let instr_desc = match instr.instr_desc with | MLocalAssign (i, v) -> let v = value_replace_var fvar v in let i = fvar i in - (if silly_asg i v then asg else add_assigned i asg), MLocalAssign (i, v) + MLocalAssign (i, v) | MStateAssign (i, v) -> - asg, MStateAssign (i, value_replace_var fvar v) + MStateAssign (i, value_replace_var fvar v) | MStep (il, i, vl) -> let il = List.map fvar il in - ( List.fold_right add_assigned il asg, - MStep (il, i, List.map (value_replace_var fvar) vl) ) + MStep (il, i, List.map (value_replace_var fvar) vl) | MBranch (g, hl) -> - let asg, hl = + let hl = List.fold_left - (fun (asg', hl) (h, il) -> - let asg'', il = instrs_replace_var m fvar asg il in + (fun hl (h, il) -> + let il = instrs_replace_var m fvar il in (* Format.(printf "%s: before %a after %a@." h (IMap.pp pp_print_int) asg (IMap.pp pp_print_int) asg''); *) - ( IMap.union (fun _ n1 n2 -> Some (max n1 n2)) asg' asg'', - (h, il) :: hl )) - (IMap.empty, []) + (h, il) :: hl ) + [] hl in (* Format.(printf "%a@." (IMap.pp pp_print_int) asg); *) - asg, MBranch (value_replace_var fvar g, List.rev hl) + MBranch (value_replace_var fvar g, List.rev hl) | MSetReset _ | MNoReset _ | MClearReset | MResetAssign _ | MSpec _ | MComment _ -> - asg, instr.instr_desc + instr.instr_desc in - let instr_spec = - List.map - (fun (f, asrt) -> instr_spec_replace m fvar asg f, asrt) - instr.instr_spec + instr_cons { instr with instr_desc } instrs + +and instrs_replace_var m fvar instrs = + let instrs = + List.fold_left (instr_replace_var m fvar) [] instrs + in + List.rev instrs + +let add_ghost_assigns reuse instrs = + let is_reused_def v = Hashtbl.find_opt reuse v.var_id in + let add_reused vars i = + match is_reused_def i with + | None -> vars + | Some v -> VMap.add i v vars + in + let rec is_defining_reused vars instr = + match instr.instr_desc with + | MLocalAssign (i, _) -> add_reused vars i + | MStep (il, _, _) -> + List.fold_left add_reused vars il + | MBranch (_, hl) -> + List.fold_left (fun vars (_, instrs) -> + List.fold_left is_defining_reused vars instrs) + vars hl + | _ -> vars in - asg, instr_cons { instr with instr_desc; instr_spec } instrs + List.map (fun instr -> + let vars = is_defining_reused VMap.empty instr in + let instr_spec = VMap.fold (fun i v -> + add_ghost_assign_spec i (vdecl_to_val v)) + vars instr.instr_spec + in + { instr with instr_spec }) instrs + +let ghost_vd v = { v with var_id = "__" ^ v.var_id } -and instrs_replace_var m fvar asg instrs = - let asg, instrs = - List.fold_left (instr_replace_var m fvar) (asg, []) instrs +let add_ghost_assigns_reassigned rasg instrs = + let _, instrs, _ = + List.fold_left (fun (rasg, instrs, fvar) instr -> + let rec aux rasg instr fvar = + match instr.instr_desc with + | MLocalAssign (i, _) when VSet.mem i rasg -> + VSet.remove i rasg, + add_ghost_assign_spec (ghost_vd i) (vdecl_to_val i) instr.instr_spec, + fun v -> if v = i then ghost_vd i else fvar v + | MStep (il, _, _) -> + let il = List.filter (fun i -> VSet.mem i rasg) il in + List.fold_left (fun (rasg, spec, fvar) i -> + VSet.remove i rasg, + add_ghost_assign_spec (ghost_vd i) (vdecl_to_val i) spec, + fun v -> if v = i then ghost_vd i else fvar v) + (rasg, instr.instr_spec, fvar) il + | MBranch (_, hl) -> + let rasg' = List.fold_left (fun rasg (_, instrs) -> + List.fold_left (fun rasg instr -> + let rasg, _, _ = aux rasg instr fvar in + rasg) rasg instrs) rasg hl + in + let rasg'' = VSet.diff rasg rasg' in + rasg', + VSet.fold (fun i spec -> + add_ghost_assign_spec (ghost_vd i) (vdecl_to_val i) spec) + rasg'' + instr.instr_spec, + fun v -> if VSet.mem v rasg'' then ghost_vd v else fvar v + | _ -> rasg, instr.instr_spec, fvar + in + let rasg, instr_spec, fvar = aux rasg instr fvar in + let instr_spec = List.map (fun (t, b) -> + instr_spec_replace fvar t, b) instr_spec + in + rasg, + { instr with instr_spec } :: instrs, + fvar) + (rasg, [], fun v -> v) instrs in - asg, List.rev instrs - -let add_ghost_assign (firsts, spec) v = - ( ISet.add v.var_id firsts, - (Predicate (GhostAssign (ghost_vd v, v)), false) :: spec ) - -let add_ghost_assigns m fvar asg instrs = - let rec aux (firsts, instrs) instr = - let firsts, instr = - match instr.instr_desc with - | MLocalAssign (i, _) - when is_reused_reassigned m fvar asg i && not (ISet.mem i.var_id firsts) - -> - let firsts, instr_spec = - add_ghost_assign (firsts, instr.instr_spec) i - in - firsts, { instr with instr_spec } - | MStep (il, _, _) -> - let firsts, instr_spec = - List.fold_left - (fun ((firsts, _) as acc) i -> - if - is_reused_reassigned m fvar asg i - && not (ISet.mem i.var_id firsts) - then add_ghost_assign acc i - else acc) - (firsts, instr.instr_spec) - il - in - firsts, { instr with instr_spec } - | MBranch (g, hl) -> - let firsts, hl = - List.fold_left - (fun (firsts', hl) (h, il) -> - let firsts, il = aux' firsts il in - ISet.union firsts firsts', (h, il) :: hl) - (ISet.empty, []) - hl - in - firsts, { instr with instr_desc = MBranch (g, List.rev hl) } - | _ -> - firsts, instr + List.rev instrs + +module IntS = Set.Make(Int) + +let add_assigned k v = + VMap.update v (function + | Some (n, ks) as b -> + if k > IntS.max_elt ks then Some (n + 1, IntS.add k ks) else b + | None -> Some (1, IntS.singleton k)) + +let silly_asg i v = + match v.value_desc with Var w -> w.var_id = i.var_id | _ -> false + +let step_replace_var m reuse step = + let fvar v = try Hashtbl.find reuse v.var_id with Not_found -> v in + let fvar v = + let f v = + let v' = fvar v in + let v'' = fvar v' in + v', v'.var_id <> v''.var_id in - firsts, instr :: instrs - and aux' firsts instrs = - let firsts, instrs = List.fold_left aux (firsts, []) instrs in - firsts, List.rev instrs + fixpoint f v in - aux' ISet.empty instrs |> snd - -let step_replace_var m fvar step = let step_locals = List.fold_left (fun res l -> @@ -1001,21 +1002,58 @@ let step_replace_var m fvar step = let step_checks = List.map (fun (l, v) -> l, value_replace_var fvar v) step.step_checks in - let asg, step_instrs = - instrs_replace_var m fvar IMap.empty step.step_instrs + let rec asg_instr k asg instr = + match instr.instr_desc with + | MLocalAssign (i, v) -> + if silly_asg i v then asg else add_assigned k i asg + | MStep (il, _, _) -> + List.fold_right (add_assigned k) il asg + | MBranch (_, hl) -> + List.fold_left + (fun asg' (_, il) -> + let asg'' = List.fold_left (asg_instr k) asg il in + VMap.union (fun _ n1 n2 -> Some (max n1 n2)) asg' asg'') + VMap.empty + hl + | _ -> asg + in + let assigned asg instrs = + let asg, _ = List.fold_left (fun (asg, k) instr -> + asg_instr k asg instr, k + 1) + (asg, 0) instrs + in + asg + in + (* SSA *) + let step_instrs = add_ghost_assigns reuse step.step_instrs in + (* register the locations of assignments *) + let asg = assigned VMap.empty step_instrs in + (* let pp fmt (k, s) = *) + (* Format.(fprintf fmt "%n{@[%a}@]" k (pp_comma_list pp_print_int) (IntS.elements s)) *) + (* in *) + (* Format.printf "AVANT %a@." (VMap.pp pp) asg; *) + (* SSA *) + let step_instrs = instrs_replace_var m fvar step_instrs in + (* update the locations of assignments, consider as reassignments only the + ones appearing *after* the original one *) + let asg = assigned asg step_instrs in + (* Format.printf "APRES %a@." (VMap.pp pp) asg; *) + let rasg = VMap.fold (fun v (n, _) rasg -> + if n > 1 then VSet.add v rasg else rasg) asg VSet.empty in - let step_instrs = add_ghost_assigns m fvar asg step_instrs in + (* not SSA anymore *) + let step_instrs = add_ghost_assigns_reassigned rasg step_instrs in + (* not SSA anymore *) { step with step_checks; step_locals; step_instrs } -let machine_replace_variables fvar m = - { m with mstep = step_replace_var m fvar m.mstep } +let machine_replace_variables reuse m = + { m with mstep = step_replace_var m reuse m.mstep } let pp_reuse fmt reuse = - Format.fprintf fmt "{ @[<hv>"; - Hashtbl.iter - (fun v1 v2 -> Format.fprintf fmt "%s --> %s@ " v1 v2.var_id) - reuse; - Format.fprintf fmt "@]@;}" + let l = Hashtbl.to_seq reuse |> List.of_seq in + let pp_fun fmt (x, v) = Format.fprintf fmt "%s --> %s" x v.var_id in + Format.(fprintf fmt "{ @[<v 2>%a@] }" + (pp_print_list ~pp_sep:pp_print_comma pp_fun) l) let machine_reuse_variables reuse m = (* Some outputs may have been replaced by locals. We reverse such bindings. *) @@ -1035,16 +1073,7 @@ let machine_reuse_variables reuse m = m.mname.node_id pp_reuse reuse); - let fvar v = try Hashtbl.find reuse v.var_id with Not_found -> v in - let fvar v = - let f v = - let v' = fvar v in - let v'' = fvar v' in - v', v'.var_id <> v''.var_id - in - fixpoint f v - in - machine_replace_variables fvar m + machine_replace_variables reuse m let machines_reuse_variables reuse_tables prog = Log.report ~level:1 (fun fmt -> @@ -1105,29 +1134,33 @@ and instrs_constant_assign var instrs = false instrs -let rec instr_reduce branches instr1 cont = +let rec instr_reduce m v branches instr1 cont = match get_instr_desc instr1 with - | MLocalAssign (_, { value_desc = Cst (Const_tag c); _ }) - | MStateAssign (_, { value_desc = Cst (Const_tag c); _ }) -> + | MLocalAssign (_, ({ value_desc = Cst (Const_tag c); _ } as t) ) + | MStateAssign (_, ({ value_desc = Cst (Const_tag c); _ } as t) ) -> + mkinstr ~instr_spec:(add_ghost_assign_spec v t []) (assign_comment m v t) + :: instr1 :: (List.assoc c branches @ cont) | MBranch (g, hl) -> update_instr_desc instr1 - (MBranch (g, List.map (fun (h, b) -> h, instrs_reduce branches b []) hl)) + (MBranch (g, List.map (fun (h, b) -> + h, + instrs_reduce m v branches b []) hl)) :: cont | _ -> instr1 :: cont -and instrs_reduce branches instrs cont = +and instrs_reduce m v branches instrs cont = match instrs with | [] -> cont | [ i ] -> - instr_reduce branches i cont + instr_reduce m v branches i cont | i1 :: i2 :: q -> - i1 :: instrs_reduce branches (i2 :: q) cont + i1 :: instrs_reduce m v branches (i2 :: q) cont -let rec instrs_fusion instrs = +let rec instrs_fusion m instrs = match instrs with | [] | [ _ ] -> false, instrs @@ -1136,19 +1169,20 @@ let rec instrs_fusion instrs = | MBranch ({ value_desc = Var v; _ }, hl) when instr_constant_assign v i1 -> ( true, instr_reduce - (List.map (fun (h, b) -> h, snd (instrs_fusion b)) hl) + m v + (List.map (fun (h, b) -> h, snd (instrs_fusion m b)) hl) { i1 with instr_spec = i1.instr_spec @ i2.instr_spec } - (snd (instrs_fusion q)) ) + (snd (instrs_fusion m q)) ) | _ -> - let b, instrs = instrs_fusion (i2 :: q) in + let b, instrs = instrs_fusion m (i2 :: q) in b, i1 :: instrs) -let step_fusion step = - let b, step_instrs = instrs_fusion step.step_instrs in +let step_fusion m step = + let b, step_instrs = instrs_fusion m step.step_instrs in b, { step with step_instrs } let machine_fusion m = - let b, mstep = step_fusion m.mstep in + let b, mstep = step_fusion m m.mstep in b, { m with mstep } let machines_fusion prog = @@ -1194,19 +1228,6 @@ let machine_clean m = let rec filter_instrs instrs = List.filter_map (fun instr -> - let instr = - { - instr with - instr_spec = - List.map - (fun (t, asrt) -> - let fv = - VSet.(elements (filter is_unused (fv_formula m empty t))) - in - Exists (fv, t), asrt) - instr.instr_spec; - } - in match get_instr_desc instr with | MLocalAssign (v, _) -> if is_used v then Some instr else None diff --git a/src/spec_types.ml b/src/spec_types.ml index bdfcb53bf4351961ab1b18aad7d298129f37e75c..3651b51a80ffaf975585a81ffa4eede105b46034 100644 --- a/src/spec_types.ml +++ b/src/spec_types.ml @@ -25,7 +25,7 @@ type 'a predicate_t = | Reset of ident * ident * 'a | MemoryPack of ident * ident option * int option | MemoryPackBase of ident - | GhostAssign of var_decl * var_decl + | GhostAssign of var_decl * 'a type 'a formula_t = | True diff --git a/src/spec_types.mli b/src/spec_types.mli index 41749288a07f70d7cd33fa084e28dbca562eb1e1..c4c43a89daeeb2a07d77d5a6c39b38d41fcdf768 100644 --- a/src/spec_types.mli +++ b/src/spec_types.mli @@ -25,7 +25,7 @@ type 'a predicate_t = | Reset of ident * ident * 'a | MemoryPack of ident * ident option * int option | MemoryPackBase of ident - | GhostAssign of var_decl * var_decl + | GhostAssign of var_decl * 'a type 'a formula_t = | True diff --git a/strategy.ml b/strategy.ml index c26cf0bf930219174e5821f708d842ffd030bdbd..b1cc5fea0f376d05117a06046c7db3defd1646a0 100644 --- a/strategy.ml +++ b/strategy.ml @@ -29,16 +29,6 @@ let is_pack (f : Lang.lfun) : bool = true with Not_found -> false -(* (\* check that a given predicate name is a reset_cleared relation *\) *) -(* let is_reset_cleared (f : Lang.lfun) : bool = *) -(* let open Str in *) -(* let r = regexp "_reset_cleared$" in *) -(* let s = Repr.lfun f in *) -(* try *) -(* ignore (search_forward r s 0); *) -(* true *) -(* with Not_found -> false *) - (* tactical selection of the goal *) let select_g (g : Lang.F.pred) : Tactical.selection = let open Tactical in @@ -161,24 +151,6 @@ class lustrec_transitions : Strategy.heuristic = () end -(* (\* Reset Cleared heuristic *\) *) -(* class lustrec_reset_cleared : Strategy.heuristic = *) -(* object *) -(* method id = "LustreC:ResetCleared" (\* required, must be unique *\) *) -(* method title = "LustreC ResetCleared" *) -(* method descr = "Custom goal transformations for reset_cleared relations" *) - -(* method search (push : Strategy.strategy -> unit) *) -(* (sequent : Conditions.sequent) : unit = *) -(* let goal = snd sequent in *) -(* match Repr.pred goal with *) -(* (\* if the goal is only a reset_cleared relation, unfold it *\) *) -(* | Call (p, _) when is_reset_cleared p -> *) -(* push (Auto.definition (select_g goal)) *) -(* | _ -> *) -(* () *) -(* end *) - (* unfold f(es) in the given context (context is handled with side-effects) *) let definition (context : WpContext.context) (f : Lang.lfun) (es : Lang.F.term list) : Lang.F.term = @@ -274,5 +246,4 @@ class lustrec_memory_packs : Strategy.heuristic = (* Register the strategies *) let () = Strategy.register (new lustrec_transitions); - (* Strategy.register (new lustrec_reset_cleared); *) Strategy.register (new lustrec_memory_packs)