aboutsummaryrefslogtreecommitdiffstats
path: root/src/bourdoncle/bourdoncleIterator.ml
blob: 3cf0c784350254d1de7f11c3d74ce1beeb353dba (plain)
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
type ('ab, 'instr) adom = {
  order: 'ab -> 'ab -> bool;
  join: 'ab -> 'ab -> 'ab;
  widen: 'ab -> 'ab -> 'ab;
  top: unit -> 'ab;
  bot: unit -> 'ab;
  transfer: 'instr -> 'ab -> 'ab;
  to_string: 'ab -> string
}

type 'instr cfg = {
  entry: int;
  succ: (int * 'instr) list array;
}

(* Utilities *)
let rec print_list_sep_rec sep pp = function
  | [] -> ""
  | x::q -> sep^(pp x)^(print_list_sep_rec sep pp q)

let rec print_list_sep_list_rec sep pp = function
  | [] -> []
  | x::q -> (sep^(pp x))::(print_list_sep_list_rec sep pp q)

let print_list_sep sep pp = function
  | [] -> ""
  | x::q -> (pp x)^(print_list_sep_rec sep pp q)

let dot_cfg cfg filename =
  let f = open_out filename in
    Printf.fprintf f "digraph {\n";
    Array.iteri
      (fun i l ->
	 List.iter (fun (j,_) -> Printf.fprintf f "  n%d -> n%d\n" i j) l)
      cfg.succ;
    Printf.fprintf f "}\n";
    close_out f


(* Bourdoncle *)
type bourdoncle = L of (bourdoncle list) * Ptset.t | I of int

let rec string_of_bourdoncle_list l =
    print_list_sep  " " string_of_bourdoncle l
and string_of_bourdoncle = function
  | L (l,_) -> "("^(string_of_bourdoncle_list l)^")"
  | I i -> string_of_int i

(* For efficiency we pre-compute the set of nodes in a cfc *)
let add_component =
  List.fold_left
    (fun s b ->
       match b with
	 | I i -> Ptset.add i s
	 | L (_,s') -> Ptset.union s s')
    Ptset.empty

(* Bourdoncle strategy computation  *)
let get_bourdoncle cfg =
  let date = ref 0 in
  let debut = Array.map (fun _ -> 0) cfg.succ in
  let stack = Stack.create () in
  let rec component i =
    let partition = ref [] in
      List.iter
	(fun (j,_) ->
	   if debut.(j)=0 then ignore (visite j partition))
	cfg.succ.(i);
      (I i) :: !partition
  and visite i partition =
    incr date;
    debut.(i) <- !date;
    let min = ref !date in
    let loop = ref false in
      Stack.push i stack;
      List.iter
	(fun (j,_) ->
	   let m = if debut.(j)=0 then visite j partition else debut.(j) in
	     if m <= !min then
	       begin
		 min := m;
		 loop := true
	       end)
	cfg.succ.(i);
      if !min=debut.(i) then
	begin
	  debut.(i) <- max_int;
	  let k = ref (Stack.pop stack) in
	    if !loop then begin
	      while (!k<>i) do
		debut.(!k) <- 0;
		k := Stack.pop stack;
	      done;
	      let c = component i in
		partition := (L (c,add_component c)) :: !partition
	    end
	    else partition := (I i) :: !partition
	end;
      !min
  in
  let partition = ref [] in
    (* only one entry in the cfg *)
    ignore (visite cfg.entry partition);
    Array.iteri (fun i d -> if d=0 then cfg.succ.(i) <- []) debut;
    !partition

(* predecessors *)
let get_pred cfg =
  let pred = Array.make (Array.length cfg.succ) [] in
    Array.iteri
      (fun i succs ->
	 List.iter
	   (fun (j,ins) ->
	      pred.(j) <- (i,ins) :: pred.(j))
	   succs
      )
      cfg.succ;
    pred

let check_fixpoint adom cfg res =
  if not (adom.order (adom.top ()) res.(cfg.entry)) then
    failwith "res.(ENTRY) should be top !\n";
  Array.iteri
      (fun i succs ->
	 List.iter
	 (fun (j,op) ->
	    if not (adom.order (adom.transfer op res.(i)) res.(j)) then
	      begin
		dot_cfg cfg "debug_bourdoncle.dot";
		failwith (Printf.sprintf "res.(%d) should be lower than res.(%d) !\n" i j)
	      end)
	   succs)
    cfg.succ

let option_down_iterations = ref 1

let rec f_list f acc = function
    [] -> acc
  | x::q -> f_list f (f acc x) q

let run_with_bourdoncle adom b cfg =
  let preds = get_pred cfg in
  let res = Array.init (Array.length preds) (fun _ -> adom.bot ()) in
  let join_list = f_list adom.join in
  let _ = res.(cfg.entry) <- adom.top () in
    let upd j =
      if j <> cfg.entry then
	res.(j) <-
	  join_list (adom.bot ())
	  (List.map (fun (i,op) -> adom.transfer op res.(i)) preds.(j)) in
    let upd_except_cfc j cfc =
      if j <> cfg.entry then
	res.(j) <- join_list res.(j)
	  (List.map (fun (i,op) -> adom.transfer op res.(i))
	     (List.filter (fun (i,op) -> not (Ptset.mem i cfc)) preds.(j)))
    in
    let nb_down = !option_down_iterations in
    let rec iter_component down = function
      | L (I head::rest,cfc) ->
	  let rec aux down = function
	      [] ->
		let old_ab = res.(head) in
		let _ = upd head in
		let new_ab = res.(head) in
		  if down >= nb_down || (new_ab = old_ab) then ()
		  else if not (adom.order new_ab old_ab) then
		    begin
		      res.(head) <- adom.widen old_ab new_ab;
		      aux (-1) rest
		    end
		  else (upd head; aux (down+1) rest)
	    | b::q -> iter_component down b; aux down q in
	    upd_except_cfc head cfc;
	    aux down rest
      | I i -> upd i
      | _ -> assert false in
      List.iter (iter_component (-1)) b;
      check_fixpoint adom cfg res;
      res

let run adom cfg =
  let b = get_bourdoncle cfg in
    run_with_bourdoncle adom b cfg