1 (********************************************************************)
3 (* The Why3 Verification Platform / The Why3 Development Team *)
4 (* Copyright 2010-2023 -- Inria - CNRS - Paris-Saclay University *)
6 (* This software is distributed under the terms of the GNU Lesser *)
7 (* General Public License version 2.1, with the special exception *)
8 (* on linking described in file LICENSE. *)
10 (********************************************************************)
16 (* Todo use labeled graph *)
17 module G
= Graph.Imperative.Digraph.Concrete
(struct
20 let equal a b
= a
.id_str
= b
.id_str
21 let compare a b
= String.compare a
.id_str b
.id_str
22 let hash a
= Hashtbl.hash a
.id_str
25 module Dom
= Graph.Dominator.Make
(G
)
26 module Topo
= Graph.WeakTopological.Make
(G
)
28 let rec targets (t
: cfg_term
) : label list
=
29 match t
.cfg_term_desc
with
31 | CFGswitch
(_
, brs
) -> List.fold_left
(fun acc
(_
, a
) -> targets a
@ acc
) [] brs
35 type labeled_block
= label
* block
36 type usage
= Multi
| One
39 | Scope
of label
* usage
* exp_tree
* exp_tree
40 | Loop
of (loop_clause
* ident
option * Ptree.term
* int option ref) list
* exp_tree
41 | Block
of labeled_block
43 let rec _print_exp_structure' exp
=
45 | Scope
(lbl
, _
, tgt
, exp
) ->
46 Format.printf
"Scope( %s = " lbl
.id_str
;
47 _print_exp_structure' tgt
;
49 _print_exp_structure' exp
;
52 Format.printf
"Loop[ ";
53 _print_exp_structure' exp
;
55 | Block
(l
, _
) -> Format.printf
"Block(%s)" l
.id_str
57 let graph_from_blocks (bl
: (label
* block
) list
) : G.t
=
58 let g = G.create
() in
60 (fun (source
, (_
, t
)) ->
61 let target_label = targets t
in
62 G.add_vertex
g source
;
63 List.iter
(fun target
-> G.add_edge
g source target
) target_label)
67 exception NotReducible
of (string * string)
68 exception NotConnected
of G.V.t list
71 Exn_printer.register
(fun fmt exn
->
73 | NotReducible
(n1
, n2
) ->
74 Format.fprintf fmt
"CFG is not a reducible graph. The nodes %s %s belong to a cycle with multiple entries" n1
78 "CFG is not a connected graph. The following nodes are not reachable from the start block: ";
79 List.iter
(fun el
-> Format.printf
"%s" el
.id_str
) s
82 module Sint
= Extset.Make
(struct
85 let compare a b
= String.compare a
.id_str b
.id_str
88 let _graph_is_reducible (g : G.t
) (dom
: G.V.t
-> G.V.t
-> bool) (entry
: label
) =
89 let visited = ref Sint.empty
in
90 let to_visit = Stack.create
() in
91 Stack.push entry
to_visit;
93 while not
(Stack.is_empty
to_visit) do
94 let node = Stack.pop
to_visit in
95 visited := Sint.add
node !visited;
99 if not
(Sint.mem succ
!visited) then Stack.push succ
to_visit
100 else if (* back-edge *)
101 not
(dom succ
node) then raise
(NotReducible
(succ
.id_str
, node.id_str
)))
104 (* graph is connected *)
105 let unreached = G.fold_vertex
(fun v u
-> if not
(Sint.mem v
!visited) then Sint.add v u
else u
) g Sint.empty
in
106 if not
(Sint.is_empty
unreached) then raise
(NotConnected
(Sint.elements
unreached));
109 let rec entry e
= match e
with Block b
-> b
| Loop
(_
, h
) -> entry h
| Scope
(_
, _
, _
, h
) -> entry h
110 (* unused | _ -> assert false *)
112 let mk_scope label usage tgt body
= Scope
(label
, usage
, tgt
, body
)
114 let rec treeify_from_components pred dom
(prev
: exp_tree
option) blocks
(wto
: label
Graph.WeakTopological.t
) :
117 (Graph.WeakTopological.fold_left
119 let e = treeify_component pred dom blocks c
in
120 let lbl = fst
(entry e) in
121 let forward_preds = List.filter
(fun pred
-> not
(dom
lbl pred
)) (pred
lbl) in
122 let usage = if List.length
forward_preds > 1 then Multi
else One
in
123 match prev
with Some prev
-> Some
(mk_scope lbl usage e prev
) | None
-> Some
e)
126 and treeify_component pred dom blocks
(wto
: label
Graph.WeakTopological.element
) : exp_tree
=
127 let open Graph.WeakTopological
in
129 | Vertex b
-> Block
(List.find
(fun (l
, _
) -> l
.id_str
= b
.id_str
) blocks
)
130 | Component
(v
, b
) ->
131 let rec split_invariants = function
132 | { cfg_instr_desc
= CFGinvariant is
} :: xs
->
133 let invs, stmts
= split_invariants xs
in
138 let l, (s
, t
) = List.find
(fun (l, _
) -> l.id_str
= v
.id_str
) blocks
in
139 let invariants, stmts
= split_invariants s
in
141 Loop
(invariants, treeify_from_components pred dom
(Some
(Block
(l, (stmts
, t
)))) blocks b
)
143 and treeify pred dom cs
= treeify_from_components pred dom None cs
145 let stackify (bl
: labeled_block list
) (entry : label
) : exp_tree
=
146 let g = graph_from_blocks bl
in
147 let idom = Dom.compute_idom
g entry in
148 let dom = Dom.idom_to_dom
idom in
150 (* graph_is_reducible g dom entry; *)
151 let comps = Topo.recursive_scc
g entry in
152 let t = treeify
(G.pred
g) dom bl
comps in