1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
module Vertex = struct
(** A node of the control flow graph is an expression. The invariant is that
it should not contain any "block". *)
type t =
{ expr : Types.binary Types.expr
; idx : int
}
let compare n1 n2 = Int.compare n1.idx n2.idx
let hash n = Int.hash n.idx
let equal n1 n2 = Int.equal n1.idx n2.idx
end
module Edge = struct
(** An edge is a value on which we will branch. The option is used for the
"default" case. *)
type t = Int32.t option
let compare n1 n2 = Option.compare Int32.compare n1 n2
let default = None
end
module G = Graph.Persistent.Digraph.ConcreteLabeled (Vertex) (Edge)
include G
let init nodes edges =
let graph = empty in
let tbl = Hashtbl.create 512 in
(* adding all vertices *)
let graph =
List.fold_left
(fun graph (idx, expr) ->
let vertex = { Vertex.expr; idx } in
Hashtbl.add tbl idx vertex;
add_vertex graph vertex )
graph nodes
in
(* adding all edges *)
List.fold_left
(fun graph (parent, child, branch) ->
let parent =
match Hashtbl.find_opt tbl parent with
| None -> assert false
| Some parent -> parent
in
let child =
match Hashtbl.find_opt tbl child with
| None -> assert false
| Some child -> child
in
let edge = E.create parent branch child in
add_edge_e graph edge )
graph edges
let length g = G.nb_vertex g
let pp_sep fmt () = Fmt.pf fmt "@,"
let pp_label fmt = function
| None -> Fmt.pf fmt {|[label="default"]|}
| Some v -> Fmt.pf fmt {|[label="%ld"]|} v
let pp_edge fmt edge =
let src = E.src edge in
let dst = E.dst edge in
let lbl = E.label edge in
Fmt.pf fmt "%d -> %d%a" src.Vertex.idx dst.Vertex.idx pp_label lbl
let pp_edges g fmt vertex =
iter_succ_e
(fun edge ->
pp_edge fmt edge;
pp_sep fmt () )
g vertex;
pp_sep fmt ()
let pp_inst fmt i = Fmt.pf fmt "%a" (Types.pp_instr ~short:true) i.Annotated.raw
let pp_exp fmt l =
Fmt.list ~sep:(fun fmt () -> Fmt.string fmt " | ") pp_inst fmt l
let pp_vertex g fmt (vertex : Vertex.t) =
let idx = vertex.idx in
(* TODO: why do we have to use `List.rev` here ?! *)
let expr = List.rev vertex.expr in
Fmt.pf fmt {|%d [label="%a"]%a%a|} idx pp_exp expr pp_sep () (pp_edges g)
vertex
let pp_vertices fmt g = Fmt.iter ~sep:pp_sep iter_vertex (pp_vertex g) fmt g
let pp fmt (g : t) =
Fmt.pf fmt "@[<v 2>digraph cfg {@,rankdir=LR;@,node [shape=record];@,%a}@]"
pp_vertices g