2024-12-12 16:37:36 +01:00
|
|
|
module type C = sig
|
|
|
|
|
type elt
|
|
|
|
|
type internal
|
|
|
|
|
|
2025-01-27 16:28:23 +01:00
|
|
|
type internal_node = {
|
|
|
|
|
internal_in: internal list;
|
|
|
|
|
internal_out: internal list;
|
|
|
|
|
internal_between: (internal list * internal list) list;
|
2024-12-12 16:37:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type cfgt = elt Cfg.cfginternal
|
|
|
|
|
|
|
|
|
|
type t = {
|
|
|
|
|
t: cfgt;
|
2025-01-27 16:28:23 +01:00
|
|
|
internal_var: internal_node Cfg.NodeMap.t;
|
2024-12-12 16:37:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val from_cfg : cfgt -> t
|
|
|
|
|
val to_cfg : t -> cfgt
|
|
|
|
|
|
2025-01-11 20:32:11 +01:00
|
|
|
val fixed_point :
|
2025-01-27 16:28:23 +01:00
|
|
|
?init : (elt list -> internal_node) ->
|
|
|
|
|
?update : (t -> Cfg.Node.t -> internal_node) ->
|
2025-01-11 20:32:11 +01:00
|
|
|
t ->
|
|
|
|
|
t
|
2024-12-12 16:37:36 +01:00
|
|
|
|
|
|
|
|
val pp : out_channel -> t -> unit
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
module Make (M: Cfg.PrintableType) (I: Cfg.PrintableType) = struct
|
|
|
|
|
type elt = M.t
|
|
|
|
|
type internal = I.t
|
|
|
|
|
|
2025-01-27 16:28:23 +01:00
|
|
|
type internal_node = {
|
|
|
|
|
internal_in: internal list;
|
|
|
|
|
internal_out: internal list;
|
|
|
|
|
internal_between: (internal list * internal list) list;
|
2024-12-12 16:37:36 +01:00
|
|
|
}
|
|
|
|
|
|
2025-01-27 16:28:23 +01:00
|
|
|
let compare_internal_node (a:internal_node) (b:internal_node) : bool =
|
|
|
|
|
match Utility.equality a.internal_in b.internal_in,
|
|
|
|
|
Utility.equality a.internal_out b.internal_out,
|
2024-12-27 21:11:38 +01:00
|
|
|
(List.fold_left2 (fun acc (ain, aout) (bin, bout)
|
2025-01-15 00:10:44 +01:00
|
|
|
-> acc &&
|
|
|
|
|
(Utility.equality ain bin) &&
|
|
|
|
|
(Utility.equality aout bout)
|
2025-01-27 16:28:23 +01:00
|
|
|
) true a.internal_between b.internal_between)
|
2024-12-27 21:11:38 +01:00
|
|
|
with
|
|
|
|
|
| true, true, true -> true
|
|
|
|
|
| _, _, _ -> false
|
|
|
|
|
|
2024-12-12 16:37:36 +01:00
|
|
|
type cfgt = elt Cfg.cfginternal
|
|
|
|
|
|
|
|
|
|
type t = {
|
|
|
|
|
t: cfgt;
|
2025-01-27 16:28:23 +01:00
|
|
|
internal_var: internal_node Cfg.NodeMap.t;
|
2024-12-12 16:37:36 +01:00
|
|
|
}
|
|
|
|
|
|
2025-01-27 16:28:23 +01:00
|
|
|
let compare_internal a b =
|
2024-12-27 21:11:38 +01:00
|
|
|
Cfg.NodeMap.fold
|
|
|
|
|
(fun node bi acc ->
|
|
|
|
|
match Cfg.NodeMap.find_opt node a with
|
|
|
|
|
None -> false
|
2025-01-27 16:28:23 +01:00
|
|
|
| Some ai -> acc && compare_internal_node ai bi
|
2024-12-27 21:11:38 +01:00
|
|
|
) b true
|
|
|
|
|
|
2024-12-12 16:37:36 +01:00
|
|
|
let from_cfg (cfg: cfgt) : t =
|
2025-01-27 16:28:23 +01:00
|
|
|
{t = cfg; internal_var = Cfg.NodeMap.empty}
|
2024-12-12 16:37:36 +01:00
|
|
|
|
|
|
|
|
let to_cfg ({t; _}: t) : cfgt =
|
|
|
|
|
t
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
open Cfg
|
2024-12-27 21:11:38 +01:00
|
|
|
let pp (ppf: out_channel) (c: t) : unit = (
|
2024-12-12 16:37:36 +01:00
|
|
|
Printf.fprintf ppf "Cfg:\n";
|
|
|
|
|
Printf.fprintf ppf "Nodes' ids: ";
|
2025-01-26 23:03:20 +01:00
|
|
|
List.iter (fun (x : Node.t) ->
|
|
|
|
|
Printf.fprintf ppf "%d " x.id) (NodeSet.to_list c.t.nodes);
|
2024-12-12 16:37:36 +01:00
|
|
|
Printf.fprintf ppf "\n";
|
|
|
|
|
|
|
|
|
|
Printf.fprintf ppf "Nodes' edges:\n";
|
|
|
|
|
List.iter (fun ((n, (a, b)) : (Node.t * (Node.t * Node.t option))) : unit ->
|
2025-01-26 23:03:20 +01:00
|
|
|
match b with
|
|
|
|
|
None -> Printf.fprintf ppf "\t%d -> %d\n" n.id a.id
|
|
|
|
|
| Some b -> Printf.fprintf ppf "\t%d -> %d, %d\n" n.id a.id b.id
|
2024-12-12 16:37:36 +01:00
|
|
|
) (NodeMap.to_list c.t.edges);
|
|
|
|
|
Printf.fprintf ppf "\n";
|
|
|
|
|
|
|
|
|
|
Printf.fprintf ppf "Nodes' back edges:\n";
|
|
|
|
|
List.iter (fun ((n, xs) : (Node.t * (Node.t list))) : unit ->
|
|
|
|
|
Printf.fprintf ppf "\t%d -> " n.id;
|
|
|
|
|
List.iter (fun (x: Node.t) -> Printf.fprintf ppf "%d, " x.id) xs;
|
|
|
|
|
Printf.fprintf ppf "\n"
|
2025-01-27 16:28:23 +01:00
|
|
|
) (NodeMap.to_list c.t.reverse_edges);
|
2024-12-12 16:37:36 +01:00
|
|
|
Printf.fprintf ppf "\n";
|
|
|
|
|
|
|
|
|
|
Printf.fprintf ppf "Input Value: ";
|
2025-01-27 16:28:23 +01:00
|
|
|
(match c.t.input_val with
|
2024-12-12 16:37:36 +01:00
|
|
|
Some i -> Printf.fprintf ppf "%d" i;
|
|
|
|
|
| None -> Printf.fprintf ppf "None";);
|
|
|
|
|
Printf.fprintf ppf "\n";
|
|
|
|
|
|
|
|
|
|
Printf.fprintf ppf "Input and Output Vars: ";
|
2025-01-27 16:28:23 +01:00
|
|
|
(match c.t.input_output_var with
|
2024-12-12 16:37:36 +01:00
|
|
|
Some (i, o) -> Printf.fprintf ppf "(in: %s, out: %s)" i o;
|
|
|
|
|
| None -> Printf.fprintf ppf "None";);
|
|
|
|
|
Printf.fprintf ppf "\n";
|
|
|
|
|
|
|
|
|
|
Printf.fprintf ppf "Initial node's id: ";
|
|
|
|
|
(match c.t.initial with
|
|
|
|
|
Some i -> Printf.fprintf ppf "%d" (i.id);
|
|
|
|
|
| None -> Printf.fprintf ppf "None";);
|
|
|
|
|
Printf.fprintf ppf "\n";
|
|
|
|
|
|
|
|
|
|
Printf.fprintf ppf "Terminal node's id: ";
|
|
|
|
|
(match c.t.terminal with
|
|
|
|
|
Some i -> Printf.fprintf ppf "%d" (i.id);
|
|
|
|
|
| None -> Printf.fprintf ppf "None";);
|
|
|
|
|
Printf.fprintf ppf "\n";
|
|
|
|
|
|
|
|
|
|
Printf.fprintf ppf "Code:\n";
|
|
|
|
|
List.iter (fun ((n, stms) : Node.t * elt list) : unit ->
|
2025-01-27 16:28:23 +01:00
|
|
|
Printf.fprintf ppf "\tid %d --> %a\n%!" n.id M.pp_list stms
|
2024-12-12 16:37:36 +01:00
|
|
|
) (NodeMap.to_list c.t.content);
|
|
|
|
|
Printf.fprintf ppf "\n";
|
|
|
|
|
|
|
|
|
|
Printf.fprintf ppf "Analysis structure:\n";
|
2025-01-27 16:28:23 +01:00
|
|
|
List.iter (fun ((n, {internal_in; internal_out; internal_between})
|
|
|
|
|
: (Node.t * internal_node)) : unit ->
|
2024-12-12 16:37:36 +01:00
|
|
|
Printf.fprintf ppf "Node: %d\n" n.id;
|
|
|
|
|
Printf.fprintf ppf "Internal Input: ";
|
2025-01-27 16:28:23 +01:00
|
|
|
Printf.fprintf ppf "%a\n" I.pp_list internal_in;
|
2024-12-12 16:37:36 +01:00
|
|
|
Printf.fprintf ppf "Internal Output: ";
|
2025-01-27 16:28:23 +01:00
|
|
|
Printf.fprintf ppf "%a\n" I.pp_list internal_out;
|
2024-12-12 16:37:36 +01:00
|
|
|
Printf.fprintf ppf "Internal Between: ";
|
2024-12-16 05:15:33 +01:00
|
|
|
List.iter (fun (i, o) ->
|
2025-01-27 16:28:23 +01:00
|
|
|
Printf.fprintf ppf "IN: %a;" I.pp_list i;
|
|
|
|
|
Printf.fprintf ppf "OUT: %a;" I.pp_list o;)
|
|
|
|
|
internal_between;
|
2024-12-12 16:37:36 +01:00
|
|
|
Printf.fprintf ppf "\n";
|
2025-01-27 16:28:23 +01:00
|
|
|
) (NodeMap.to_list c.internal_var);
|
2024-12-16 05:15:33 +01:00
|
|
|
Printf.fprintf ppf "\n";
|
2024-12-27 21:11:38 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let fixed_point
|
2025-01-27 16:28:23 +01:00
|
|
|
?(init : (elt list -> internal_node) =
|
|
|
|
|
(fun _ -> {internal_in = [];
|
|
|
|
|
internal_out = [];
|
|
|
|
|
internal_between = []}))
|
|
|
|
|
?(update : (t -> Cfg.Node.t -> internal_node) =
|
|
|
|
|
(fun t n -> Cfg.NodeMap.find n t.internal_var))
|
2024-12-27 21:11:38 +01:00
|
|
|
(t: t)
|
|
|
|
|
: t =
|
|
|
|
|
(* init function is applied only once to each node content,
|
|
|
|
|
the update function takes the node and the whole structure and is
|
|
|
|
|
expected to return the updated structure for the appropriate node,
|
|
|
|
|
update function is applied to the resulting structure until no change is
|
2025-01-15 00:10:44 +01:00
|
|
|
observed with compareinternal function
|
2024-12-27 21:11:38 +01:00
|
|
|
*)
|
2025-01-27 16:28:23 +01:00
|
|
|
let rec aux t =
|
2024-12-27 21:11:38 +01:00
|
|
|
let newt =
|
|
|
|
|
{t with
|
2025-01-27 16:28:23 +01:00
|
|
|
internal_var = Cfg.NodeMap.mapi (fun n _ -> update t n) t.internal_var}
|
2024-12-27 21:11:38 +01:00
|
|
|
in
|
2025-01-27 16:28:23 +01:00
|
|
|
if compare_internal newt.internal_var t.internal_var
|
2024-12-27 21:11:38 +01:00
|
|
|
then newt
|
2025-01-27 16:28:23 +01:00
|
|
|
else aux newt
|
2024-12-27 21:11:38 +01:00
|
|
|
in
|
|
|
|
|
|
|
|
|
|
let content =
|
|
|
|
|
List.fold_left
|
2025-01-27 16:28:23 +01:00
|
|
|
(fun cfg node -> Cfg.NodeMap.add node {internal_in = [];
|
|
|
|
|
internal_out = [];
|
|
|
|
|
internal_between = []} cfg)
|
2024-12-27 21:11:38 +01:00
|
|
|
Cfg.NodeMap.empty
|
|
|
|
|
(Cfg.NodeSet.to_list t.t.nodes)
|
|
|
|
|
in
|
|
|
|
|
|
|
|
|
|
let code = (* we add back in the nodes with no code (there is no binding
|
|
|
|
|
in the t.t.content map) *)
|
|
|
|
|
Cfg.NodeMap.union (fun _n c _empty -> Some c)
|
|
|
|
|
t.t.content
|
|
|
|
|
(Cfg.NodeMap.of_list
|
|
|
|
|
(Cfg.NodeSet.to_list t.t.nodes |> List.map (fun c -> (c, []))))
|
|
|
|
|
in
|
|
|
|
|
|
|
|
|
|
let content = Cfg.NodeMap.union
|
|
|
|
|
(fun _key _empty code -> Some code)
|
|
|
|
|
content
|
|
|
|
|
(Cfg.NodeMap.map init code)
|
|
|
|
|
in
|
2025-01-27 16:28:23 +01:00
|
|
|
aux { t with internal_var = content }
|
2024-12-27 21:11:38 +01:00
|
|
|
|
2024-12-12 16:37:36 +01:00
|
|
|
end
|