aboutsummaryrefslogtreecommitdiffstats
path: root/caml/Linearizeaux.ml
blob: 8a4297f47abbc7e4343ccdb71470bce3d352d9a4 (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
open BinPos
open Coqlib
open Datatypes
open LTL
open Lattice
open CList
open Maps
open Camlcoq

(* Trivial enumeration, in decreasing order of PC *)

(***
let enumerate_aux f reach =
  positive_rec
    Coq_nil
    (fun pc nodes ->
      if PMap.get pc reach
      then Coq_cons (pc, nodes)
      else nodes) 
    f.fn_nextpc
***)

(* More clever enumeration that flattens basic blocks *)

let rec int_of_pos = function
  | Coq_xI p -> (int_of_pos p lsl 1) + 1
  | Coq_xO p -> int_of_pos p lsl 1
  | Coq_xH -> 1

(* Count the reachable predecessors for each node *)

let reachable_predecessors f reach =
  let count = Array.make (int_of_pos f.fn_nextpc) 0 in
  let increment pc =
    let i = int_of_pos pc in
    count.(i) <- count.(i) + 1 in
  positive_rec
    ()
    (fun pc _ ->
      if PMap.get pc reach then coqlist_iter increment (successors f pc))
    f.fn_nextpc;
  count

(* Recognize instructions with only one successor *)

let single_successor f pc =
  match PTree.get pc f.fn_code with
    | Some i ->
        (match i with
           | Lnop s -> Some s
           | Lop (op, args, res, s) -> Some s
           | Lload (chunk, addr, args, dst, s) -> Some s
           | Lstore (chunk, addr, args, src, s) -> Some s
           | Lcall (sig0, ros, args, res, s) -> Some s
           | Ltailcall (sig0, ros, args) -> None
           | Lalloc (arg, res, s) -> Some s
           | Lcond (cond, args, ifso, ifnot) -> None
           | Lreturn optarg -> None)
    | None -> None

(* Build the enumeration *)

let enumerate_aux f reach =
  let preds = reachable_predecessors f reach in
  let enum = ref Coq_nil in
  let emitted = Array.make (int_of_pos f.fn_nextpc) false in
  let rec emit_basic_block pc =
    enum := Coq_cons(pc, !enum);
    emitted.(int_of_pos pc) <- true;
    match single_successor f pc with
    | None -> ()
    | Some pc' ->
        let npc' = int_of_pos pc' in
        if preds.(npc') <= 1 && not emitted.(npc') then emit_basic_block pc' in
  let rec emit_all pc =
    if pc <> Coq_xH then begin
      let pc = coq_Ppred pc in
      if not emitted.(int_of_pos pc) && PMap.get pc reach
      then emit_basic_block pc;
      emit_all pc
    end in
  emit_all f.fn_nextpc;
  CList.rev !enum