diff options
Diffstat (limited to 'src/slice.ml')
| -rw-r--r-- | src/slice.ml | 194 |
1 files changed, 168 insertions, 26 deletions
diff --git a/src/slice.ml b/src/slice.ml index f50104c4..a38a207c 100644 --- a/src/slice.ml +++ b/src/slice.ml @@ -104,7 +104,7 @@ let builtins = let rec constraint_ids' (NC_aux (aux, _)) = match aux with - | NC_equal (n1, n2) | NC_bounded_le (n1, n2) | NC_bounded_ge (n1, n2) | NC_not_equal (n1, n2) -> + | NC_equal (n1, n2) | NC_bounded_le (n1, n2) | NC_bounded_ge (n1, n2) | NC_bounded_lt (n1, n2) | NC_bounded_gt (n1, n2) | NC_not_equal (n1, n2) -> IdSet.union (nexp_ids' n1) (nexp_ids' n2) | NC_or (nc1, nc2) | NC_and (nc1, nc2) -> IdSet.union (constraint_ids' nc1) (constraint_ids' nc2) @@ -157,9 +157,9 @@ let add_def_to_graph graph def = let env = env_of_annot annot in begin match p_aux with | P_app (id, _) -> - graph := G.add_edge' self (Constructor id) !graph + graph := G.add_edge self (Constructor id) !graph | P_typ (typ, _) -> - IdSet.iter (fun id -> graph := G.add_edge' self (Type id) !graph) (typ_ids typ) + IdSet.iter (fun id -> graph := G.add_edge self (Type id) !graph) (typ_ids typ) | _ -> () end; P_aux (p_aux, annot) @@ -169,10 +169,29 @@ let add_def_to_graph graph def = let scan_lexp self lexp_aux annot = let env = env_of_annot annot in begin match lexp_aux with - | LEXP_cast (typ, _) -> - IdSet.iter (fun id -> graph := G.add_edge' self (Type id) !graph) (typ_ids typ) + | LEXP_cast (typ, id) -> + IdSet.iter (fun id -> graph := G.add_edge self (Type id) !graph) (typ_ids typ); + begin match Env.lookup_id id env with + | Register _ -> + graph := G.add_edge self (Register id) !graph + | Enum _ -> graph := G.add_edge self (Constructor id) !graph + | _ -> + if IdSet.mem id (Env.get_toplevel_lets env) then + graph := G.add_edge self (Letbind id) !graph + else () + end | LEXP_memory (id, _) -> - graph := G.add_edge' self (Function id) !graph + graph := G.add_edge self (Function id) !graph + | LEXP_id id -> + begin match Env.lookup_id id env with + | Register _ -> + graph := G.add_edge self (Register id) !graph + | Enum _ -> graph := G.add_edge self (Constructor id) !graph + | _ -> + if IdSet.mem id (Env.get_toplevel_lets env) then + graph := G.add_edge self (Letbind id) !graph + else () + end | _ -> () end; LEXP_aux (lexp_aux, annot) @@ -183,26 +202,28 @@ let add_def_to_graph graph def = begin match e_aux with | E_id id -> begin match Env.lookup_id id env with - | Register _ -> graph := G.add_edge' self (Register id) !graph + | Register _ -> graph := G.add_edge self (Register id) !graph + | Enum _ -> graph := G.add_edge self (Constructor id) !graph | _ -> if IdSet.mem id (Env.get_toplevel_lets env) then - graph := G.add_edge' self (Letbind id) !graph + graph := G.add_edge self (Letbind id) !graph else () end | E_app (id, _) -> if Env.is_union_constructor id env then - graph := G.add_edge' self (Constructor id) !graph + graph := G.add_edge self (Constructor id) !graph else - graph := G.add_edge' self (Function id) !graph + graph := G.add_edge self (Function id) !graph | E_ref id -> - graph := G.add_edge' self (Register id) !graph + graph := G.add_edge self (Register id) !graph | E_cast (typ, _) -> - IdSet.iter (fun id -> graph := G.add_edge' self (Type id) !graph) (typ_ids typ) + IdSet.iter (fun id -> graph := G.add_edge self (Type id) !graph) (typ_ids typ) | _ -> () end; E_aux (e_aux, annot) in let rw_exp self = { id_exp_alg with e_aux = (fun (e_aux, annot) -> scan_exp self e_aux annot); + lEXP_aux = (fun (l_aux, annot) -> scan_lexp self l_aux annot); pat_alg = rw_pat self } in let rewriters self = @@ -216,8 +237,9 @@ let add_def_to_graph graph def = let scan_quant_item self (QI_aux (aux, _)) = match aux with | QI_id _ -> () - | QI_const nc -> - IdSet.iter (fun id -> graph := G.add_edge' self (Type id) !graph) (constraint_ids nc) + | QI_constraint nc -> + IdSet.iter (fun id -> graph := G.add_edge self (Type id) !graph) (constraint_ids nc) + | QI_constant _ -> () in let scan_typquant self (TypQ_aux (aux, _)) = @@ -229,7 +251,7 @@ let add_def_to_graph graph def = let add_type_def_to_graph (TD_aux (aux, (l, _))) = match aux with | TD_abbrev (id, typq, arg) -> - graph := G.add_edges' (Type id) (List.map (fun id -> Type id) (IdSet.elements (typ_arg_ids arg))) !graph; + graph := G.add_edges (Type id) (List.map (fun id -> Type id) (IdSet.elements (typ_arg_ids arg))) !graph; scan_typquant (Type id) typq | TD_record (id, typq, fields, _) -> let field_nodes = @@ -238,40 +260,44 @@ let add_def_to_graph graph def = |> IdSet.elements |> List.map (fun id -> Type id) in - graph := G.add_edges' (Type id) field_nodes !graph; + graph := G.add_edges (Type id) field_nodes !graph; scan_typquant (Type id) typq | TD_variant (id, typq, ctors, _) -> let ctor_nodes = List.map (fun (Tu_aux (Tu_ty_id (typ, id), _)) -> (typ_ids typ, id)) ctors |> List.fold_left (fun (ids, ctors) (ids', ctor) -> (IdSet.union ids ids', IdSet.add ctor ctors)) (IdSet.empty, IdSet.empty) in - IdSet.iter (fun ctor_id -> graph := G.add_edge' (Constructor ctor_id) (Type id) !graph) (snd ctor_nodes); - IdSet.iter (fun typ_id -> graph := G.add_edge' (Type id) (Type typ_id) !graph) (fst ctor_nodes); + IdSet.iter (fun ctor_id -> graph := G.add_edge (Constructor ctor_id) (Type id) !graph) (snd ctor_nodes); + IdSet.iter (fun typ_id -> graph := G.add_edge (Type id) (Type typ_id) !graph) (fst ctor_nodes); scan_typquant (Type id) typq - | TD_enum (id, _, _) -> - graph := G.add_edges' (Type id) [] !graph + | TD_enum (id, ctors, _) -> + List.iter (fun ctor_id -> graph := G.add_edge (Constructor ctor_id) (Type id) !graph) ctors | TD_bitfield _ -> Reporting.unreachable l __POS__ "Bitfield should be re-written" in begin match def with | DEF_spec (VS_aux (VS_val_spec (TypSchm_aux (TypSchm_ts (typq, typ), _), id, _, _), _)) -> - graph := G.add_edges' (Function id) [] !graph; - IdSet.iter (fun typ_id -> graph := G.add_edge' (Function id) (Type typ_id) !graph) (typ_ids typ) + graph := G.add_edges (Function id) [] !graph; + IdSet.iter (fun typ_id -> graph := G.add_edge (Function id) (Type typ_id) !graph) (typ_ids typ) | DEF_fundef fdef -> let id = id_of_fundef fdef in - graph := G.add_edges' (Function id) [] !graph; + graph := G.add_edges (Function id) [] !graph; ignore (rewrite_fun (rewriters (Function id)) fdef) | DEF_val (LB_aux (LB_val (pat, exp), _) as lb) -> let ids = pat_ids pat in - IdSet.iter (fun id -> graph := G.add_edges' (Letbind id) [] !graph) ids; + IdSet.iter (fun id -> graph := G.add_edges (Letbind id) [] !graph) ids; IdSet.iter (fun id -> ignore (rewrite_let (rewriters (Letbind id)) lb)) ids | DEF_type tdef -> add_type_def_to_graph tdef - | DEF_pragma _ -> () + | DEF_reg_dec (DEC_aux (DEC_reg (_, _, typ, id), _)) -> + IdSet.iter (fun typ_id -> graph := G.add_edge (Register id) (Type typ_id) !graph) (typ_ids typ) + | DEF_reg_dec (DEC_aux (DEC_config (id, typ, exp), _)) -> + ignore (rewrite_exp (rewriters (Register id)) exp); + IdSet.iter (fun typ_id -> graph := G.add_edge (Register id) (Type typ_id) !graph) (typ_ids typ) | _ -> () end; - G.fix_leaves !graph + !graph let rec graph_of_ast (Defs defs) = let module G = Graph.Make(Node) in @@ -283,8 +309,124 @@ let rec graph_of_ast (Defs defs) = | [] -> G.empty +let id_of_typedef (TD_aux (aux, _)) = + match aux with + | TD_abbrev (id, _, _) -> id + | TD_record (id, _, _, _) -> id + | TD_variant (id, _, _, _) -> id + | TD_enum (id, _, _) -> id + | TD_bitfield (id, _, _) -> id + +let id_of_reg_dec (DEC_aux (aux, _)) = + match aux with + | DEC_reg (_, _, _, id) -> id + | DEC_config (id, _, _) -> id + | _ -> assert false + + +let filter_ast cuts g (Defs defs) = + let rec filter_ast' g = + let module NS = Set.Make(Node) in + let module NM = Map.Make(Node) in + function + | DEF_fundef fdef :: defs when NS.mem (Function (id_of_fundef fdef)) cuts -> filter_ast' g defs + | DEF_fundef fdef :: defs when NM.mem (Function (id_of_fundef fdef)) g -> DEF_fundef fdef :: filter_ast' g defs + | DEF_fundef _ :: defs -> filter_ast' g defs + + | DEF_reg_dec rdec :: defs when NM.mem (Register (id_of_reg_dec rdec)) g -> DEF_reg_dec rdec :: filter_ast' g defs + | DEF_reg_dec _ :: defs -> filter_ast' g defs + + | DEF_spec vs :: defs when NM.mem (Function (id_of_val_spec vs)) g -> DEF_spec vs :: filter_ast' g defs + | DEF_spec _ :: defs -> filter_ast' g defs + + | DEF_val (LB_aux (LB_val (pat, exp), _) as lb) :: defs -> + let ids = pat_ids pat |> IdSet.elements in + if List.exists (fun id -> NM.mem (Letbind id) g) ids then + DEF_val lb :: filter_ast' g defs + else + filter_ast' g defs + + | DEF_type tdef :: defs when NM.mem (Type (id_of_typedef tdef)) g -> DEF_type tdef :: filter_ast' g defs + | DEF_type _ :: defs -> filter_ast' g defs + + | DEF_measure (id,_,_) :: defs when NS.mem (Function id) cuts -> filter_ast' g defs + | (DEF_measure (id,_,_) as def) :: defs when NM.mem (Function id) g -> def :: filter_ast' g defs + | DEF_measure _ :: defs -> filter_ast' g defs + + | def :: defs -> def :: filter_ast' g defs + + | [] -> [] + in + Defs (filter_ast' g defs) + let dot_of_ast out_chan ast = let module G = Graph.Make(Node) in let module NodeSet = Set.Make(Node) in let g = graph_of_ast ast in G.make_dot (node_color NodeSet.empty) edge_color node_string out_chan g + +let () = + let open Printf in + let open Interactive in + let slice_roots = ref IdSet.empty in + let slice_cuts = ref IdSet.empty in + + ArgString ("identifiers", fun arg -> Action (fun () -> + let args = Str.split (Str.regexp " +") arg in + let ids = List.map mk_id args |> IdSet.of_list in + Specialize.add_initial_calls ids; + slice_roots := IdSet.union ids !slice_roots + )) |> register_command ~name:"slice_roots" ~help:"Set the roots for :slice"; + + ArgString ("identifiers", fun arg -> Action (fun () -> + let args = Str.split (Str.regexp " +") arg in + let ids = List.map mk_id args |> IdSet.of_list in + slice_cuts := IdSet.union ids !slice_cuts + )) |> register_command ~name:"slice_cuts" ~help:"Set the cuts for :slice"; + + Action (fun () -> + let module NodeSet = Set.Make(Node) in + let module G = Graph.Make(Node) in + let g = graph_of_ast !ast in + let roots = !slice_roots |> IdSet.elements |> List.map (fun id -> Function id) |> NodeSet.of_list in + let cuts = !slice_cuts |> IdSet.elements |> List.map (fun id -> Function id) |> NodeSet.of_list in + let g = G.prune roots cuts g in + ast := filter_ast cuts g !ast + ) |> register_command + ~name:"slice" + ~help:"Slice AST to the definitions which the functions given \ + by :slice_roots depend on, up to the functions given \ + by :slice_cuts"; + + Action (fun () -> + let module NodeSet = Set.Make(Node) in + let module NodeMap = Map.Make(Node) in + let module G = Graph.Make(Node) in + let g = graph_of_ast !ast in + let roots = !slice_roots |> IdSet.elements |> List.map (fun id -> Function id) |> NodeSet.of_list in + let keep = function + | (Function id,_) when IdSet.mem id (!slice_roots) -> None + | (Function id,_) -> Some (Function id) + | _ -> None + in + let cuts = NodeMap.bindings g |> Util.map_filter keep |> NodeSet.of_list in + let g = G.prune roots cuts g in + ast := filter_ast cuts g !ast + ) |> register_command + ~name:"thin_slice" + ~help:(sprintf ":thin_slice - Slice AST to the function definitions given with %s" (command "slice_roots")); + + ArgString ("format", fun arg -> Action (fun () -> + let format = if arg = "" then "svg" else arg in + let dotfile, out_chan = Filename.open_temp_file "sail_graph_" ".gz" in + let image = Filename.temp_file "sail_graph_" ("." ^ format) in + dot_of_ast out_chan !ast; + close_out out_chan; + let _ = Unix.system (Printf.sprintf "dot -T%s %s -o %s" format dotfile image) in + let _ = Unix.system (Printf.sprintf "xdg-open %s" image) in + () + )) |> register_command + ~name:"graph" + ~help:"Draw a callgraph using dot in :0 (e.g. svg), and open with xdg-open" + + |
