aboutsummaryrefslogtreecommitdiffstats
path: root/backend/RTLTunnelingaux.ml
blob: 5fe327d4499eca60278393c6152ddb028b469ad8 (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
(* *************************************************************)
(*                                                             *)
(*             The Compcert verified compiler                  *)
(*                                                             *)
(*           Sylvain Boulmé  Grenoble-INP, VERIMAG             *)
(*           TODO: Proper author information                   *)
(*                                                             *)
(*  Copyright VERIMAG. All rights reserved.                    *)
(*  This file is distributed under the terms of the INRIA      *)
(*  Non-Commercial License Agreement.                          *)
(*                                                             *)
(* *************************************************************)

(*

This file implements the [branch_target] oracle that identifies "nop" branches in a RTL function,
and computes their target node with the distance (ie the number of cummulated nops) toward this target.

See [RTLTunneling.v]

*)

open Coqlib
open RTL
open Maps
open Camlcoq
open Tunnelinglibs

let nopcounter = ref 0

module LANG = struct
  type code_unit = RTL.instruction
  type funct = RTL.coq_function
end

module OPT = struct
  let langname = "RTL"
  let limit_tunneling = None
  let debug_flag = ref false
  let final_dump = false
end

module rec T: sig
  val get_node: cfg -> positive -> node
  val set_branch: cfg -> positive -> node -> unit
  val debug: ('a, out_channel, unit) format -> 'a
  val string_of_labeli: ('a, node) Hashtbl.t -> 'a -> string
  exception BugOnPC of int
  val branch_target: RTL.coq_function -> (positive * Z.t) PTree.t

end = Tunnelinglibs.Tunneling(LANG)(OPT)(FUNS)

and FUNS: sig
  val build_simplified_cfg: cfg -> node list -> positive -> LANG.code_unit -> node list

  val print_code_unit: cfg -> bool -> int * LANG.code_unit -> bool

  val fn_code: LANG.funct -> LANG.code_unit PTree.t
  val fn_entrypoint: LANG.funct -> positive

  val check_code_unit: (positive * integer) PTree.t -> positive -> LANG.code_unit -> unit
end = struct
  let build_simplified_cfg c acc pc i =
    match i with
    | Inop s ->
       let ns = T.get_node c s in
       T.set_branch c pc ns;
       incr nopcounter;
       acc
    | Icond (_, _, s1, s2, _) ->
       c.num_rems <- c.num_rems + 1;
       let ns1 = T.get_node c s1 in
       let ns2 = T.get_node c s2 in
       let npc = T.get_node c pc in
       npc.inst <- COND(ns1, ns2);
       npc::acc
    | _ -> acc

  let print_code_unit c println (pc, i) =
    match i with
    | Inop s -> (if println then T.debug "\n"); T.debug "%d:Inop %d %s\n" pc (P.to_int s) (T.string_of_labeli c.nodes pc); false
    | Icond (_, _, s1, s2, _) -> (if println then T.debug "\n"); T.debug "%d:Icond (%d,%d) %s\n" pc (P.to_int s1) (P.to_int s2) (T.string_of_labeli c.nodes pc); false
    | _ -> T.debug "%d " pc; true

  let fn_code f = f.fn_code
  let fn_entrypoint f = f.fn_entrypoint

  (*************************************************************)
  (* Copy-paste of the extracted code of the verifier          *)
  (* with [raise (BugOnPC (P.to_int pc))] instead of [Error.*] *)

  let get td pc =
    match PTree.get pc td with
    | Some p -> let (t0, d) = p in (t0, d)
    | None -> (pc, Z.of_uint 0)

  let check_code_unit td pc i =
    match PTree.get pc td with
    | Some p ->
        let (tpc, dpc) = p in
        let dpc0 = dpc in begin
          match i with
          | Inop s ->
            let (ts, ds) = get td s in
            if peq tpc ts
            then if zlt ds dpc0
                 then ()
                 else raise (T.BugOnPC (P.to_int pc))
            else raise (T.BugOnPC (P.to_int pc))
          | Icond (_, _, s1, s2, _) ->
            let (ts1, ds1) = get td s1 in
            let (ts2, ds2) = get td s2 in
            if peq tpc ts1
            then if peq tpc ts2
                 then if zlt ds1 dpc0
                      then if zlt ds2 dpc0
                           then ()
                           else raise (T.BugOnPC (P.to_int pc))
                      else raise (T.BugOnPC (P.to_int pc))
                 else raise (T.BugOnPC (P.to_int pc))
            else raise (T.BugOnPC (P.to_int pc))
          | _ ->
            raise (T.BugOnPC (P.to_int pc)) end
    | None -> ()

end

let branch_target = T.branch_target