source: Deliverables/D2.2/8051-indexed-labels-branch/src/clight/clightAnnotator.ml @ 1291

Last change on this file since 1291 was 1291, checked in by tranquil, 9 years ago

Started branch of untrusted compiler with indexed labels

  • added indexing structure to CostLabel?
  • propagated changes to other modules
  • added indexing as parameter to labelling
  • loop indexes not implemented yet, so behaviour is still the same
File size: 13.2 KB
Line 
1(* This module provides an annotation function for Clight programs
2   when given the cost associated to each cost labels of the
3   program. *)
4
5
6let error_prefix = "Clight Annotator"
7let error = Error.global_error error_prefix
8
9
10let cost_id_prefix = "_cost"
11let cost_incr_prefix = "_cost_incr"
12
13
14(* Program var and fun names, cost labels and labels *)
15
16let string_set_of_list l =
17  List.fold_left (fun res s -> StringTools.Set.add s res)
18    StringTools.Set.empty l
19
20let triple_union
21    (names1, cost_labels1, user_labels1)
22    (names2, cost_labels2, user_labels2) =
23  (StringTools.Set.union names1 names2,
24   CostLabel.Set.union cost_labels1 cost_labels2,
25   Label.Set.union user_labels1 user_labels2)
26
27let empty_triple =
28        (StringTools.Set.empty, CostLabel.Set.empty, Label.Set.empty)
29
30let name_singleton id =
31  (StringTools.Set.singleton id, CostLabel.Set.empty, Label.Set.empty)
32
33let cost_label_singleton lbl =
34  (StringTools.Set.empty, CostLabel.Set.singleton lbl, Label.Set.empty)
35
36let label_singleton lbl =
37  (StringTools.Set.empty, CostLabel.Set.empty, Label.Set.singleton lbl)
38
39let list_union l = List.fold_left triple_union empty_triple l
40
41let f_ctype ctype sub_ctypes_res =
42  let res = match ctype with
43    | Clight.Tstruct (id, fields) | Clight.Tunion (id, fields) ->
44      (string_set_of_list (id :: (List.map fst fields)),
45       CostLabel.Set.empty, Label.Set.empty)
46    | Clight.Tcomp_ptr id -> name_singleton id
47    | _ -> empty_triple in
48  list_union (res :: sub_ctypes_res)
49
50let f_expr _ sub_ctypes_res sub_expr_descrs_res =
51  list_union (sub_ctypes_res @ sub_expr_descrs_res)
52
53let f_expr_descr ed sub_ctypes_res sub_exprs_res =
54  let res = match ed with
55    | Clight.Evar id | Clight.Efield (_, id) | Clight.Ecall (id, _, _) ->
56      name_singleton id
57    | Clight.Ecost (cost_lbl, _) -> cost_label_singleton cost_lbl
58    | _ -> empty_triple in
59  list_union (res :: (sub_ctypes_res @ sub_exprs_res))
60
61let f_stmt stmt sub_exprs_res sub_stmts_res =
62  let stmt_res = match stmt with
63    | Clight.Slabel (lbl, _) | Clight.Sgoto lbl -> label_singleton lbl
64    | Clight.Scost (cost_lbl, _) -> cost_label_singleton cost_lbl
65    | _ -> empty_triple in
66  list_union (stmt_res :: (sub_exprs_res @ sub_stmts_res))
67
68let body_idents = ClightFold.statement f_ctype f_expr f_expr_descr f_stmt
69
70let prog_idents p =
71  let def_idents = function
72    | Clight.Internal def ->
73        let vars =
74          string_set_of_list
75            (List.map fst (def.Clight.fn_params @ def.Clight.fn_vars)) in
76        let (names, cost_labels, user_labels) =
77          body_idents def.Clight.fn_body in
78        (StringTools.Set.union vars names, cost_labels, user_labels)
79    | Clight.External (id, _, _) ->
80        (StringTools.Set.singleton id, CostLabel.Set.empty, 
81         Label.Set.empty) in
82  let fun_idents (id, f_def) =
83    let (names, cost_labels, user_labels) = def_idents f_def in
84    (StringTools.Set.add id names, cost_labels, user_labels) in
85  let f idents def = triple_union idents (fun_idents def) in
86  List.fold_left f empty_triple p.Clight.prog_funct
87
88let names p =
89  let (names, _, _) = prog_idents p in names
90let cost_labels p =
91  let (_, cost_labels, _) = prog_idents p in cost_labels
92let user_labels p =
93  let (_, _, user_labels) = prog_idents p in user_labels
94
95let all_labels p =
96  let (_, cost_labels, user_labels) = prog_idents p in
97        let f lbl = StringTools.Set.add (CostLabel.string_of_cost_label lbl) in 
98  let all = CostLabel.Set.fold f cost_labels StringTools.Set.empty in
99  Label.Set.fold StringTools.Set.add user_labels all
100
101let all_idents p =
102  let (names, cost_labels, user_labels) = prog_idents p in
103        let f lbl = StringTools.Set.add (CostLabel.string_of_cost_label lbl) in
104  let cost_labels = CostLabel.Set.fold f cost_labels StringTools.Set.empty in
105  let to_string_set fold set =
106    fold (fun lbl idents -> StringTools.Set.add lbl idents) set
107      StringTools.Set.empty in
108  let user_labels = to_string_set Label.Set.fold user_labels in
109  StringTools.Set.union names (StringTools.Set.union cost_labels user_labels)
110
111let fresh_ident base p =
112  StringTools.Gen.fresh_prefix (all_idents p) base
113
114let fresh_universe base p =
115  let universe = fresh_ident base p in
116  StringTools.Gen.new_universe universe
117
118let make_fresh base p =
119  let universe = fresh_universe base p in
120  (fun () -> StringTools.Gen.fresh universe)
121
122
123(* Instrumentation *)
124
125let int_typ = Clight.Tint (Clight.I32, AST.Signed)
126
127let const_int i = Clight.Expr (Clight.Econst_int i, int_typ)
128
129(* Instrument an expression. *)
130
131let rec instrument_expr cost_mapping cost_incr e =
132  let Clight.Expr (e, t) = e in
133  match e with
134    | Clight.Ecost (lbl, e) when CostLabel.Map.find lbl cost_mapping = 0 ->
135        e
136    | _ ->
137        let e' = instrument_expr_descr cost_mapping cost_incr e in
138        Clight.Expr (e', t)
139and instrument_expr_descr cost_mapping cost_incr e = match e with
140  | Clight.Econst_int _ | Clight.Econst_float _ | Clight.Evar _
141  | Clight.Esizeof _ -> e
142  | Clight.Ederef e ->
143      let e' = instrument_expr cost_mapping cost_incr e in
144      Clight.Ederef e'
145  | Clight.Eaddrof e ->
146      let e' = instrument_expr cost_mapping cost_incr e in
147      Clight.Eaddrof e'
148  | Clight.Eunop (op, e) ->
149      let e' = instrument_expr cost_mapping cost_incr e in
150      Clight.Eunop (op, e')
151  | Clight.Ebinop (op, e1, e2) ->
152      let e1' = instrument_expr cost_mapping cost_incr e1 in
153      let e2' = instrument_expr cost_mapping cost_incr e2 in
154      Clight.Ebinop (op, e1', e2')
155  | Clight.Ecast (t, e) ->
156      let e' = instrument_expr cost_mapping cost_incr e in
157      Clight.Ecast (t, e')
158  | Clight.Econdition (e1, e2, e3) ->
159      let e1' = instrument_expr cost_mapping cost_incr e1 in
160      let e2' = instrument_expr cost_mapping cost_incr e2 in
161      let e3' = instrument_expr cost_mapping cost_incr e3 in
162      Clight.Econdition (e1', e2', e3')
163  | Clight.Eandbool (e1, e2) ->
164      let e1' = instrument_expr cost_mapping cost_incr e1 in
165      let e2' = instrument_expr cost_mapping cost_incr e2 in
166      Clight.Eandbool (e1', e2')
167  | Clight.Eorbool (e1, e2) ->
168      let e1' = instrument_expr cost_mapping cost_incr e1 in
169      let e2' = instrument_expr cost_mapping cost_incr e2 in
170      Clight.Eorbool (e1', e2')
171  | Clight.Efield (e, x) ->
172      let e' = instrument_expr cost_mapping cost_incr e in
173      Clight.Efield (e', x)
174  | Clight.Ecost (lbl, e) when CostLabel.Map.mem lbl cost_mapping ->
175      let e' = instrument_expr cost_mapping cost_incr e in
176      let incr = CostLabel.Map.find lbl cost_mapping in
177      if incr = 0 then let Clight.Expr (e'', _) = e' in e''
178      else Clight.Ecall (cost_incr, const_int incr, e')
179  | Clight.Ecost (_, e) ->
180    let Clight.Expr (e', _) = instrument_expr cost_mapping cost_incr e in
181    e'
182  | Clight.Ecall (x, e1, e2) -> assert false (* Should not happen. *)
183
184(* Instrument a statement. *)
185
186let rec instrument_body cost_mapping cost_incr stmt = match stmt with
187  | Clight.Sskip | Clight.Sbreak | Clight.Scontinue | Clight.Sreturn None
188  | Clight.Sgoto _ ->
189    stmt
190  | Clight.Sassign (e1, e2) ->
191    let e1' = instrument_expr cost_mapping cost_incr e1 in
192    let e2' = instrument_expr cost_mapping cost_incr e2 in
193    Clight.Sassign (e1', e2')
194  | Clight.Scall (eopt, f, args) ->
195    let eopt' = match eopt with
196      | None -> None
197      | Some e -> Some (instrument_expr cost_mapping cost_incr e) in
198    let f' = instrument_expr cost_mapping cost_incr f in
199    let args' = List.map (instrument_expr cost_mapping cost_incr) args in
200    Clight.Scall (eopt', f', args')
201  | Clight.Ssequence (s1, s2) ->
202    Clight.Ssequence (instrument_body cost_mapping cost_incr s1,
203                      instrument_body cost_mapping cost_incr s2)
204  | Clight.Sifthenelse (e, s1, s2) ->
205    let e' = instrument_expr cost_mapping cost_incr e in
206    let s1' = instrument_body cost_mapping cost_incr s1 in
207    let s2' = instrument_body cost_mapping cost_incr s2 in
208    Clight.Sifthenelse (e', s1', s2')
209  | Clight.Swhile (e, s) ->
210    let e' = instrument_expr cost_mapping cost_incr e in
211    let s' = instrument_body cost_mapping cost_incr s in
212    Clight.Swhile (e', s')
213  | Clight.Sdowhile (e, s) ->
214    let e' = instrument_expr cost_mapping cost_incr e in
215    let s' = instrument_body cost_mapping cost_incr s in
216    Clight.Sdowhile (e', s')
217  | Clight.Sfor (s1, e, s2, s3) ->
218    let s1' = instrument_body cost_mapping cost_incr s1 in
219    let e' = instrument_expr cost_mapping cost_incr e in
220    let s2' = instrument_body cost_mapping cost_incr s2 in
221    let s3' = instrument_body cost_mapping cost_incr s3 in
222    Clight.Sfor (s1', e', s2', s3')
223  | Clight.Sreturn (Some e) ->
224    let e' = instrument_expr cost_mapping cost_incr e in
225    Clight.Sreturn (Some e')
226  | Clight.Sswitch (e, ls) ->
227    let e' = instrument_expr cost_mapping cost_incr e in
228    let ls' = instrument_ls cost_mapping cost_incr ls in
229    Clight.Sswitch (e', ls')
230  | Clight.Slabel (lbl, s) ->
231    let s' = instrument_body cost_mapping cost_incr s in
232    Clight.Slabel (lbl, s')
233  | Clight.Scost (lbl, s) when CostLabel.Map.mem lbl cost_mapping ->
234    (* Keep the cost label in the code. *)
235    let s' = instrument_body cost_mapping cost_incr s in
236    let incr = CostLabel.Map.find lbl cost_mapping in
237    let fun_typ = Clight.Tfunction ([int_typ], Clight.Tvoid) in
238    let f = Clight.Expr (Clight.Evar cost_incr, fun_typ) in
239    let args = [Clight.Expr (Clight.Econst_int incr, int_typ)] in
240    Clight.Scost (lbl, Clight.Ssequence (Clight.Scall (None, f, args), s'))
241  (*
242    let s' = instrument_body cost_mapping cost_incr s in
243    let incr = CostLabel.Map.find lbl cost_mapping in
244    if incr = 0 then s'
245    else
246    let fun_typ = Clight.Tfunction ([int_typ], Clight.Tvoid) in
247    let f = Clight.Expr (Clight.Evar cost_incr, fun_typ) in
248    let args = [Clight.Expr (Clight.Econst_int incr, int_typ)] in
249    Clight.Ssequence (Clight.Scall (None, f, args), s')
250  *)
251  | Clight.Scost (lbl, s) ->
252    (* Keep the cost label in the code and show the increment of 0. *)
253    let s' = instrument_body cost_mapping cost_incr s in
254    let fun_typ = Clight.Tfunction ([int_typ], Clight.Tvoid) in
255    let f = Clight.Expr (Clight.Evar cost_incr, fun_typ) in
256    let args = [Clight.Expr (Clight.Econst_int 0, int_typ)] in
257    Clight.Scost (lbl, Clight.Ssequence (Clight.Scall (None, f, args), s'))
258  (*
259    instrument_body cost_mapping cost_incr s
260  *)
261and instrument_ls cost_mapping cost_incr = function
262  | Clight.LSdefault s ->
263    let s' = instrument_body cost_mapping cost_incr s in
264    Clight.LSdefault s'
265  | Clight.LScase (i, s, ls) ->
266    let s' = instrument_body cost_mapping cost_incr s in
267    let ls' = instrument_ls cost_mapping cost_incr ls in
268    Clight.LScase (i, s', ls')
269
270(* Instrument a function. *)
271
272let instrument_funct cost_mapping cost_incr (id, def) =
273  let def = match def with
274    | Clight.Internal def ->
275        let body = instrument_body cost_mapping cost_incr def.Clight.fn_body in
276        Clight.Internal { def with Clight.fn_body = body }
277    | Clight.External _ -> def
278  in
279  (id, def)
280
281(* This is the declaration of the cost variable. *)
282
283let cost_decl cost_id =
284  let init = [Clight.Init_int32 0] in
285  ((cost_id, init), int_typ)
286
287(* This is the definition of the increment cost function. *)
288
289let cost_incr_def cost_id cost_incr =
290  let int_var x = Clight.Expr (Clight.Evar x, int_typ) in
291  let param = "incr" in
292  let cost = int_var cost_id in
293  let increment = int_var param in
294  let cost_increment =
295    Clight.Expr (Clight.Ebinop (Clight.Oadd, cost, increment), int_typ) in
296  let stmt = Clight.Sassign (cost, cost_increment) in
297  let cfun =
298    { Clight.fn_return = Clight.Tvoid ;
299      Clight.fn_params = [(param, int_typ)] ;
300      Clight.fn_vars   = [] ;
301      Clight.fn_body =   stmt } in
302  (cost_incr, Clight.Internal cfun)
303
304let save_tmp tmp_file s =
305  let cout = open_out tmp_file in
306  output_string cout s ;
307  flush cout ;
308  close_out cout
309
310(** [instrument prog cost_map] instruments the program [prog]. First a fresh
311    global variable --- the so-called cost variable --- is added to the program.
312    Then, each cost label in the program is replaced by an increment of the cost
313    variable, following the mapping [cost_map]. The function also returns the
314    name of the cost variable and the name of the cost increment function. *)
315
316let instrument p cost_mapping =
317
318  (* Create a fresh 'cost' variable. *)
319  let names = names p in
320  let cost_id = StringTools.Gen.fresh_prefix names cost_id_prefix in
321  let cost_decl = cost_decl cost_id in
322
323  (* Define an increment function for the cost variable. *)
324  let cost_incr =
325    StringTools.Gen.fresh_prefix (StringTools.Set.add cost_id names)
326      cost_incr_prefix in
327  let cost_incr_def = cost_incr_def cost_id cost_incr in
328
329  (* Instrument each function *)
330  let prog_funct =
331    List.map (instrument_funct cost_mapping cost_incr) p.Clight.prog_funct in
332
333  (* Glue all this together. *)
334  let prog_vars = cost_decl :: p.Clight.prog_vars in
335  let prog_funct = cost_incr_def :: prog_funct in
336  let p' =
337    { p with Clight.prog_vars = prog_vars ; Clight.prog_funct = prog_funct } in
338
339  (* Save the resulted program. Then re-parse it.
340     Indeed, the instrumentation may add side-effects in expressions, which is
341     not Clight compliant. Re-parsing the result with CIL will remove these
342     side-effects in expressions to obtain a Clight program. *)
343  let tmp_file = Filename.temp_file "clight_instrument" ".c" in
344  save_tmp tmp_file (ClightPrinter.print_program p') ;
345  let res = ClightParser.process tmp_file in
346  Misc.SysExt.safe_remove tmp_file ;
347  (res, cost_id, cost_incr)
Note: See TracBrowser for help on using the repository browser.