Project

General

Profile

Download (32.6 KB) Statistics
| Branch: | Tag: | Revision:
1
open Format
2
open LustreSpec
3
open Machine_code
4
open C_backend_common
5
open Utils
6

    
7

    
8
module type SPECARG = 
9
sig
10
  val prog : program 
11
  val machines : machine_t list
12
end
13
  
14
  (**************************************************************************)
15
  (*                              SPEC DATATYPES                            *)
16
  (**************************************************************************)
17
    
18
    
19
  type eexpr_minimachine_t = {
20
  muid: tag;
21
  mquantifiers: (quantifier_type * var_decl list) list;
22
  mmmemory: var_decl list;
23
  mmcalls: (ident * static_call) list;     (* map from stateful/stateless instance to node, 
24
					      no internals *)
25
  mminstances: (ident * static_call) list; (* sub-map of mcalls, from stateful instance to node *)
26
  mminit: instr_t list;
27
  mmstep_logic: step_t;  
28
  mmstep_effects: step_t;  
29
  (* mmlogic: step_t;   *)
30
}
31

    
32
type spec_machine_t = {
33
  m_requires: eexpr_minimachine_t list;
34
  m_ensures: eexpr_minimachine_t list;
35
  m_behaviors: (string * eexpr_minimachine_t list * eexpr_minimachine_t list) list;
36
}
37

    
38

    
39
let machine_from_minimachine_effects m mm =
40
{
41
  mname = m.mname;
42
  mmemory = mm.mmmemory;
43
  mcalls = mm.mmcalls;
44
  minstances = mm.mminstances;
45
  minit = []; (* ??? *)
46
  mstatic = [] ; (* ??? *)
47
  mstep = mm.mmstep_effects;
48
  mspec = None;
49
  mannot = [];
50
}
51

    
52
let machine_from_minimachine_logics m mm =
53
{
54
  mname = m.mname;
55
  mmemory = mm.mmmemory;
56
  mcalls = mm.mmcalls;
57
  minstances = mm.mminstances;
58
  minit = []; (* ??? *)
59
  mstatic = [] ; (* ??? *)
60
  mstep = mm.mmstep_logic;
61
  mspec = None;
62
  mannot = [];
63
}
64

    
65
(**************************************************************************)
66
(*                       DATATYPES PRINTERS                               *)
67
(**************************************************************************)
68

    
69

    
70

    
71
let pp_acsl_type var fmt t =
72
  let rec aux t pp_suffix =
73
  match (Types.repr t).Types.tdesc with
74
  | Types.Tclock t'       -> aux t' pp_suffix
75
  | Types.Tbool           -> fprintf fmt "boolean %s%a" var pp_suffix ()
76
  | Types.Treal           -> fprintf fmt "real %s%a" var pp_suffix ()
77
  | Types.Tint            -> fprintf fmt "integer %s%a" var pp_suffix ()
78
  | Types.Tarray (d, t')  ->
79
    let pp_suffix' fmt () = fprintf fmt "%a[%a]" pp_suffix () pp_c_dimension d in
80
    aux t' pp_suffix'
81
  (* | Types.Tstatic (_, t') -> fprintf fmt "const "; aux t' pp_suffix *)
82
  (* | Types.Tconst ty       -> fprintf fmt "%s %s" ty var *)
83
  (* | Types.Tarrow (_, _)   -> fprintf fmt "void (\*%s)()" var *)
84
  | _                     -> 
85
    (eprintf "internal error: pp_acsl_type %a@." Types.print_ty t; assert false)
86
  in aux t (fun fmt () -> ())
87

    
88
let pp_acsl_var_decl fmt id =
89
  pp_acsl_type id.var_id fmt id.var_type
90

    
91

    
92
let pp_quantifiers fmt (q, vars) =
93
  let pp_var fmt id = 
94
    fprintf fmt "%s: %a" id.var_id Types.print_ty id.var_type
95
  in
96
  match q with
97
    | Forall -> fprintf fmt "forall %a" (fprintf_list ~sep:"; " pp_var) vars 
98
    | Exists -> fprintf fmt "exists %a" (fprintf_list ~sep:"; " pp_var) vars 
99

    
100
(*
101
let pp_eexpr fmt ee =
102
  Format.fprintf fmt 
103
    "%a%t @[<v 2>mem      : %a@;instances: %a@;init     : %a@;logic step     :@;  @[<v 2>%a@]@;effects step     :@;  @[<v 2>%a@]@;@]@;"
104
    (Utils.fprintf_list ~sep:"; " pp_quantifiers) ee.mquantifiers
105
    (fun fmt -> match ee.mquantifiers with [] -> () | _ -> Format.fprintf fmt ";")
106
    (Utils.fprintf_list ~sep:", " Printers.pp_var) ee.mmmemory
107
    (Utils.fprintf_list ~sep:", " (fun fmt (o1, o2) -> Format.fprintf fmt "(%s, %a)" o1 pp_static_call o2)) ee.mminstances
108
    (Utils.fprintf_list ~sep:"@ " pp_instr) ee.mminit
109
    pp_step ee.mmstep_logic
110
    pp_step ee.mmstep_effects
111

    
112

    
113
let pp_spec fmt spec =
114
  Format.fprintf fmt "@[<hov 2>(*@@ ";
115
  Utils.fprintf_list ~sep:"@;@@ " (fun fmt r -> Format.fprintf fmt "requires %a;" pp_eexpr r) fmt spec.m_requires;
116
  Utils.fprintf_list ~sep:"@;@@ " (fun fmt r -> Format.fprintf fmt "ensures %a; " pp_eexpr r) fmt spec.m_ensures;
117
  Utils.fprintf_list ~sep:"@;" (fun fmt (name, assumes, ensures) -> 
118
    Format.fprintf fmt "behavior %s:@[@ %a@ %a@]" 
119
      name
120
      (Utils.fprintf_list ~sep:"@ " (fun fmt r -> Format.fprintf fmt "assumes %a;" pp_eexpr r)) assumes
121
      (Utils.fprintf_list ~sep:"@ " (fun fmt r -> Format.fprintf fmt "ensures %a;" pp_eexpr r)) ensures
122
  ) fmt spec.m_behaviors;
123
  Format.fprintf fmt "@]*)";
124
  ()
125
*)
126

    
127

    
128
(**************************************************************************)
129
(*                            CONVERTER                                   *)
130
(**************************************************************************)
131
(* The eexpr shoud have been normalized, ie. its eexpr_normalized field updated
132
   We add a new boolean output var and bound it to the main expression
133
   characterizing the eexpr.   
134
*)
135

    
136
let save_var v =
137
  { v with var_id = v.var_id^"_save" }
138

    
139
let rec postTransformLogicValue x = match x with
140
  | StateVar v -> StateVar (save_var v)
141
  | Fun (i, vl) -> Fun (i, List.map postTransformLogicValue vl)
142
  | Array vl -> Array (List.map postTransformLogicValue vl)
143
  | Access (x, y) -> Access (postTransformLogicValue x, postTransformLogicValue y)
144
  | Power (x, y) -> Power (postTransformLogicValue x, postTransformLogicValue y)
145
  | x -> x
146

    
147
let rec postTransformLogic x = List.map (function
148
    | MLocalAssign (x, y) -> MLocalAssign (x, postTransformLogicValue y)
149
    | MStateAssign (x, y) -> MStateAssign (x, postTransformLogicValue y)
150
    | MStep (x, y, z) -> MStep (x, y, List.map postTransformLogicValue z)
151
    | MBranch (x, y) -> MBranch (postTransformLogicValue x, List.map (function (x, y)-> (x, postTransformLogic y)) y)
152
    | MReset x -> MReset x
153
    ) x
154

    
155
let rec postTransformSide = function
156
    | MStateAssign (i, v)::q -> (MStateAssign (save_var i, StateVar i))::(MStateAssign (i, v))::(postTransformSide q)
157
    | t::q -> t::(postTransformSide q)
158
    | [] -> []
159

    
160
let rec postTranformMemory = function
161
    | t::q -> t::(save_var t)::(postTranformMemory q)
162
    | [] -> []
163

    
164
let translate_eexpr nd eexpr =
165
  (* Format.eprintf "Translating eexpr: %a" Printers.pp_eexpr eexpr; *)
166
  let output_var, eqs, locals = 
167
    match eexpr.eexpr_normalized with None -> assert false | Some x -> x 
168
  in 
169
  (* both inputs and outputs are considered here as inputs for the specification *) 
170
  let inputs = nd.node_inputs @ nd.node_outputs in
171
  let inputs_quantifiers = inputs @ (List.flatten (List.map snd eexpr.eexpr_quantifiers)) in 
172
  
173
  let eexpr_local_vars = output_var :: locals @ (List.flatten (List.map snd eexpr.eexpr_quantifiers)) in
174
  let visible_vars = eexpr_local_vars @ inputs in
175
  
176
  let sort_eqs inputs eqs = 
177
    let eqs_logic, new_locals_logic, sch_logic = Scheduling.schedule_eqs inputs visible_vars eqs in
178
    (* Format.eprintf "sch: [%a]@;new locals: [%a]@;locals:[%a]@.eexpr local vars: [%a]@.@?"  *)
179
    (*   (Utils.fprintf_list ~sep:", " Format.pp_print_string) sch_logic *)
180
    (*   (Utils.fprintf_list ~sep:", " Printers.pp_var) new_locals_logic *)
181
    (*   (Utils.fprintf_list ~sep:", " Printers.pp_var) locals *)
182
    (*   (Utils.fprintf_list ~sep:", " Printers.pp_var) eexpr_local_vars;  *)
183
    let locals = eexpr_local_vars @ new_locals_logic @ (List.flatten (List.map snd eexpr.eexpr_quantifiers)) in
184
    let sorted_eqs_rev_logic, remainder_logic = 
185
      List.fold_left 
186
	(fun (accu, eqs_remainder) v -> 
187
	  if List.exists (fun eq -> List.mem v eq.eq_lhs) accu
188
	  then (* The variable was already handled by a previous selected eq. 
189
		  Typically it is part of a tuple *)
190
	    ((* Format.eprintf "Case 1 for variable %s@." v; *)
191
	     (accu, eqs_remainder)
192
	    )
193
	  else if List.exists (fun vdecl -> vdecl.var_id = v) locals || output_var.var_id = v
194
	  then ((* Select the eq associated to v. *) 
195
	    (* Format.eprintf "Case 2 for variable %s@." v; *)
196
	    let eq_v, remainder = find_eq v eqs_remainder in
197
	    eq_v::accu, remainder
198
	  )
199
	  else ((* else it is a constant value, checked during typing phase *)
200
	    (* Format.eprintf "Case 3 for variable %s@." v; *)
201
	    accu, eqs_remainder
202
	  )
203
	) 
204
	([], eqs_logic) 
205
	sch_logic 
206
    in
207
    if List.length remainder_logic > 0 then (
208
      Format.eprintf "Spec equations not used are@.%a@.Full equation set is:@.%a@.@?"
209
	Printers.pp_node_eqs remainder_logic
210
	Printers.pp_node_eqs eqs_logic;
211
      assert false );
212
    List.rev sorted_eqs_rev_logic, locals  
213
  in
214

    
215
  
216
  (* Generating logic definition instructions *)
217
  let sorted_eqs, locals = sort_eqs inputs_quantifiers eqs in
218

    
219
  let init_args = 
220
    VDSet.empty, 
221
    [], 
222
    Utils.IMap.empty, 
223
    List.fold_right (fun l -> VDSet.add l) locals VDSet.empty,
224
    [] 
225
  in
226

    
227
  let m, init, j, locals, s_logic = 
228
    translate_eqs 
229
      nd
230
      true (* keep_ite *)  
231
      eexpr_local_vars
232
      init_args
233
      (sorted_eqs) 
234
  in
235

    
236
  (* We remove side effects *)
237
  let s_logic = List.filter (fun i -> match i with MStateAssign _ -> false | _ -> true) s_logic in 
238
  (* and put the output var as the last instr *)
239
  let s_logic =
240
    let output_assign, others = 
241
      List.partition 
242
	(fun i -> match i with | MStep([v], _, _) | MLocalAssign(v,_) -> v.var_id = output_var.var_id | _ -> false)
243
	s_logic 
244
    in
245
    (* Format.eprintf "output instr: @.%a@.others:@.%a@." *)
246
    (*   (Utils.fprintf_list ~sep:"@." pp_instr) output_assign *)
247
    (*   (Utils.fprintf_list ~sep:"@." pp_instr) others; *)
248
    others @ output_assign
249
  in
250
  let _,_,_,_, s_side_effects = 
251
    translate_eqs nd true (*TODO: explose ite *)  eexpr_local_vars init_args (sorted_eqs) 
252
  in
253
  let rec filter_side_effects instrs =
254
    List.fold_right (
255
      fun i accu ->
256
	match i with
257
      | MStep([v], _, _) 
258
      | MLocalAssign(v,_) -> 
259
	if v.var_id <> output_var.var_id then
260
	  i::accu
261
	else
262
	  accu
263
      | MBranch (g, cases) -> 
264
	let filtered_cases = 
265
	  List.map (fun (l, l_instrs) -> l, filter_side_effects l_instrs) cases in
266
	MBranch(g, filtered_cases) :: accu
267
      | _ -> i::accu
268
	  
269
    ) instrs []
270
  in
271

    
272
  let s_side_effects = filter_side_effects s_side_effects in 
273
  
274
  {
275
    muid = eexpr.eexpr_tag;
276
    mquantifiers = eexpr.eexpr_quantifiers;
277
    mmmemory = postTranformMemory (VDSet.elements m);
278
    mmcalls = []; (* no calls *)
279
    mminstances = []; (* no calls *)
280
    mminit = init;
281
    mmstep_logic = {
282
      step_inputs = inputs;
283
      step_outputs = [output_var];
284
      step_locals = VDSet.elements (VDSet.remove output_var (VDSet.diff locals m));
285
      step_checks = [] (* Not handled yet *);
286
      step_instrs = (
287
	(* special treatment depending on the active backend. For horn backend,
288
	   common branches are not merged while they are in C or Java
289
	   backends. *)
290
	match !Options.output with
291
	| "horn" -> s_logic
292
	| "C" | "java" | _ -> (*TODO: check that this is correct to remove : join_guards_list*) (postTransformLogic s_logic)
293
      );
294
      step_asserts = [];
295
    };
296
    mmstep_effects = {
297
      step_inputs = inputs; (* contains nd.node_inputs + nd.node_outputs *)
298
      step_outputs = nd.node_outputs; (* used by the printer to print correctly the names *)
299
      step_locals = VDSet.elements (VDSet.remove output_var (VDSet.diff locals m));
300
      step_checks = [] (* Not handled yet *);
301
      step_instrs = (
302
	(* special treatment depending on the active backend. For horn backend,
303
	   common branches are not merged while they are in C or Java
304
	   backends. *)
305
	match !Options.output with
306
	| "horn" -> s_side_effects
307
	| "C" | "java" | _ -> (*TODO: check that this is correct to remove : join_guards_list*) (postTransformSide s_side_effects)
308
      );
309
      step_asserts = [];
310
    }
311
  }    
312

    
313
let translate_spec nd spec = 
314
  (* Each eexpr of the spec is expressed as a minimachine: 
315
     instrs (to update memory and set local vars) 
316
     + expr (to compute the output
317
     + memory defs 
318
     + instances (for callee nodes)
319
  *)
320
  let transl = List.map (translate_eexpr nd) in
321
  {
322
    m_requires = transl spec.requires;
323
    m_ensures = transl spec.ensures;
324
    m_behaviors =
325
      List.map
326
	(fun (beh_id, req, ens, _) -> beh_id, transl req, transl ens) 
327
	spec.behaviors
328
  }
329
    
330

    
331
(*
332

    
333
mspec = Utils.option_map (translate_spec nd) nd.node_spec;
334
    mannot = List.flatten (
335
      List.map (fun ann -> List.map (fun (kwd, eexpr) -> kwd, (translate_eexpr nd eexpr)) ann.annots) nd.node_annot);
336
*)
337

    
338

    
339
(**************************************************************************)
340
(*                              HEADER                                    *)
341
(**************************************************************************)
342
    
343
  (* Print basic library function as ACSL functions *)
344
  let basic_lib_pp_acsl i get_val_type pp_val fmt vl =
345
    match i, vl with
346
    | "ite", [v1; v2; v3] -> Format.fprintf fmt "(%a?(%a):(%a))" pp_val v1 pp_val v2 pp_val v3 
347
    | "uminus", [v] -> Format.fprintf fmt "(- %a)" pp_val v
348
    | "not", [v] -> Format.fprintf fmt "(!%a)" pp_val v 
349
    | "impl", [v1; v2] -> Format.fprintf fmt "((!%a) ||  %a)" pp_val v1 pp_val v2 
350
    | "=", [v1; v2] -> Format.fprintf fmt "(%a == %a)" pp_val v1 pp_val v2
351
    | "mod", [v1; v2] -> Format.fprintf fmt "(%a %% %a)" pp_val v1 pp_val v2 
352
    | "equi", [v1; v2] -> Format.fprintf fmt "(!%a == !%a)" pp_val v1 pp_val v2
353
    | "xor", [v1; v2] -> Format.fprintf fmt "(%a ^ %a)" pp_val v1 pp_val v2
354
    | _, [v1; v2] -> Format.fprintf fmt "(%a %s %a)" pp_val v1 i pp_val v2 
355
    | _ -> raise (Failure ("No ACSL printer for function " ^ i))
356
      
357
let pp_acsl_tag fmt t =
358
 pp_print_string fmt (if t = Corelang.tag_true then "\\true" else if t = Corelang.tag_false then "\\false" else t)
359
let rec pp_acsl_const fmt c =
360
  match c with
361
    | Const_int i     -> pp_print_int fmt i
362
    | Const_real r    -> pp_print_string fmt r
363
    | Const_float r   -> pp_print_float fmt r
364
    | Const_tag t     -> pp_acsl_tag fmt t
365
    | Const_array ca  -> fprintf fmt "{%a }" (Utils.fprintf_list ~sep:", " pp_c_const) ca
366
    | Const_struct fl -> fprintf fmt "{%a }" (Utils.fprintf_list ~sep:", " (fun fmt (f, c) -> pp_c_const fmt c)) fl
367
    | Const_string _ -> assert false (* string occurs in annotations not in C *)
368

    
369
  let rec pp_acsl_val ?(is_lhs=false) self pp_var fmt v =
370
    match v with
371
    | Cst c         -> pp_acsl_const fmt c
372
    | Array _      
373
    | Access _       -> assert false (* no arrays *)
374
    | Power (v, n)  -> assert false
375
    | LocalVar v    -> pp_var fmt v
376
    | StateVar v    ->     
377
      (match (Types.repr v.var_type).Types.tdesc with
378
      | Types.Tbool           -> fprintf fmt "((%t)?\\true:\\false)"
379
      | _ -> fprintf fmt "%t")
380
      (if Types.is_array_type v.var_type
381
      then assert false
382
      else fun fmt -> fprintf fmt "%s%s_reg.%s" self 
383
     (if !Options.no_pointer then "." else "->") v.var_id)
384
    | Fun (n, vl)   -> Format.fprintf fmt "%a" (basic_lib_pp_acsl n Machine_code.get_val_type (pp_acsl_val self pp_var)) vl
385
      
386

    
387
  let rec pp_eexpr_logic_instr m eem fmt instr =
388
    let self = mk_self m in
389
    let conv_m =  machine_from_minimachine_logics m eem in
390
    match instr with 
391
    | MReset i -> assert false (* should not happen, calls were inlined *)
392
    | MLocalAssign (i,v) -> (
393
      match conv_m.mstep.step_outputs with 
394
      | [o] -> if i = o then
395
	  fprintf fmt "%a;" (pp_acsl_val self (pp_c_var_read conv_m)) v
396
	else
397
	  fprintf fmt "\\let %a = %a;" 
398
	    (pp_c_var_read conv_m (* TODO no variable shold be treated as output *)) i
399
	    (pp_acsl_val self (pp_c_var_read conv_m)) v
400

    
401
      | _ -> 
402
	assert false (* should not happen: only a single output *)
403
    )
404
    | MStateAssign (i,v) -> 
405
      assert false (* should not happen, no side effects in logical predicates *)
406
    | MStep ([i0], i, vl) when Basic_library.is_internal_fun i  ->
407
      pp_eexpr_logic_instr m eem fmt (MLocalAssign (i0, Fun (i, vl)))
408
  | MStep ([i0], "ite", vl) ->
409
    pp_eexpr_logic_instr m eem fmt (MLocalAssign (i0, Fun ("ite", vl)))
410
  | MStep (il, i, vl) ->
411
    Format.eprintf "Illegal function call %s@.%a@.@?" i pp_instr instr; 
412
    assert false (* should not happen, calls were inlined *)
413
  | MBranch (g,hl) -> assert false (* should not happen. Oder ??? TODO *)
414
    
415

    
416
let pp_logic_eexpr m fmt ee =
417
  fprintf fmt "%a%t%a"
418
    (Utils.fprintf_list ~sep:"@ " pp_quantifiers) ee.mquantifiers
419
    (Utils.pp_final_char_if_non_empty " " ee.mquantifiers) 
420
    (Utils.fprintf_list ~sep:"@;" 
421
       (pp_eexpr_logic_instr m ee)) ee.mmstep_logic.step_instrs
422
    
423

    
424
let pp_acsl_spec_logics stateless m fmt spec = 
425
  let self = mk_self m in
426
  let pp_expr_def fmt ee =
427
    match ee.mmstep_logic.step_instrs with
428
    | [MStep([o], i, vl)] -> () (* We do nothing, the expression is simple and 
429
				   was introduced directly in the contract *)
430
    | _ -> ((* We define a new ACSL predicate *)
431
      fprintf fmt "/*@@ @[<v 3>predicate spec_%i(%a%t) =@;%a@]@;*/@." 
432
	ee.muid   
433
	(Utils.fprintf_list ~sep:", " pp_acsl_var_decl) ee.mmstep_logic.step_inputs
434
  (fun fmt -> if stateless then fprintf fmt "" else fprintf fmt "%t%a %s%s"
435
  (Utils.pp_final_char_if_non_empty ", " ee.mmstep_logic.step_inputs)
436
	pp_machine_memtype_name m.mname.node_id
437
  (if !Options.no_pointer then "" else "*")
438
	self)
439
	(pp_logic_eexpr m) ee
440
    )
441

    
442
  in
443
  List.iter (pp_expr_def fmt) 
444
    (spec.m_requires@
445
       spec.m_ensures@
446
       (List.fold_left 
447
	  (fun accu (_,assumes, ensures) -> assumes@ensures@accu) 
448
	  [] spec.m_behaviors)
449
    )
450

    
451
(* Access to the value of a variable:
452
   - if it's not a scalar output, then its name is enough
453
   - otherwise, dereference it (it has been declared as a pointer,
454
     despite its scalar Lustre type)
455
   - moreover, cast arrays variables into their original array type.
456
*)
457
let pp_acsl_var_read suffix outputs fmt id =
458
  if Types.is_array_type id.var_type
459
  then
460
    assert false (* no array *)
461
  else (
462
    (if List.exists (fun o -> o.var_id = id.var_id) outputs (* id is output *)
463
    then fprintf fmt "((*%s)%s" id.var_id suffix
464
    else fprintf fmt "(%s%s" id.var_id suffix);
465
      match (Types.repr id.var_type).Types.tdesc with
466
      | Types.Tbool           -> fprintf fmt "?\\true:\\false)"
467
      | _ -> fprintf fmt ")"
468
  )
469

    
470
    
471
let pp_requires_mem stateless machines fmt m =
472
  let self = mk_self m in
473
  List.iter (fun v -> fprintf fmt "requires \\valid(%s);@;" v.var_id) m.mstep.step_outputs;
474
  let mems = Machine_code.get_mems m machines in
475
  (if not !Options.no_pointer then
476
    List.iter (fun prefix -> fprintf fmt "requires \\valid(%s%a);@;" self
477
      (Utils.fprintf_list ~sep:"" (fun fmt s -> fprintf fmt "->%s" s)) prefix
478
    )
479
      (Machine_code.get_instances m machines)
480
  );
481
  if not stateless then fprintf fmt "requires \\valid(%s);@;" self;
482
  if List.length mems + List.length m.mstep.step_outputs > 1 then
483
    fprintf fmt "requires \\separated(@[<hov>%a%t%a@]);@;" 
484
      (Utils.fprintf_list ~sep:",@ " 
485
	      (fun fmt v -> pp_print_string fmt v.var_id))
486
      m.mstep.step_outputs 
487
      (Utils.pp_final_char_if_non_empty ",@ " mems)
488
      (if !Options.no_pointer then
489
        fun fmt x -> fprintf fmt "%s" (if stateless then "" else self) (*maybe we want to add more pointers here like arrays *)
490
      else
491
        Utils.fprintf_list ~sep:",@ " (fun fmt (prefix, var) -> fprintf fmt "&%s%a->_reg.%s"
492
	        self 
493
	        (Utils.fprintf_list ~sep:"" (fun fmt s -> fprintf fmt "->%s" s)) prefix
494
	        var.var_id))
495
      mems
496

    
497
let pp_assigns more stateless machines fmt m =
498
  let self = mk_self m in
499
  let mems = Machine_code.get_mems m machines in
500
  fprintf fmt "assigns @[<hov>%a%a%t%a@];@;"
501
    (Utils.fprintf_list ~sep:",@ " (fun fmt v -> fprintf fmt "*%s" v.var_id))
502
    m.mstep.step_outputs
503
    (if !Options.no_pointer then
504
        fun fmt mems -> fprintf fmt "%s" (if stateless then "" else (", *"^self)) (*maybe we want to keep some memory like array *)
505
     else Utils.fprintf_list ~sep:",@ "
506
       (fun fmt (prefix, var) -> fprintf fmt "%t%s%a->_reg.%s"
507
         (Utils.pp_final_char_if_non_empty ",@ " mems)
508
         self
509
         (Utils.fprintf_list ~sep:"" (fun fmt s -> fprintf fmt "->%s" s)) prefix
510
         var.var_id)
511
    )
512
    mems
513
    (Utils.pp_final_char_if_non_empty ",@ " more)
514
    (Utils.fprintf_list ~sep:",@ " (fun fmt v -> v fmt))
515
    more
516

    
517

    
518
let pp_acsl_mem_valid stateless pre post machines fmt m =
519
  fprintf fmt "@[<v 2>/*@@ ";
520
  pp_requires_mem stateless machines fmt m;
521
  pre fmt;
522
  post fmt;
523
  pp_assigns [] stateless machines fmt m;
524
  fprintf fmt "@]*/@.";
525
  ()
526

    
527
(* Seems to be a simplification of pp_assign (in c_backend_src *)
528
let pp_expr_rhs m pp_var fmt var_type value =
529
  let self = mk_self m in
530
  let depth = C_backend_src.expansion_depth value in
531
(*eprintf "pp_assign %a %a %d@." Types.print_ty var_type pp_val value depth;*)
532
  let loop_vars = C_backend_src.mk_loop_variables m var_type depth in
533
  let reordered_loop_vars = C_backend_src.reorder_loop_variables loop_vars in
534
  let rec aux fmt vars =
535
    match vars with
536
    | [] ->
537
      fprintf fmt "%a;" 
538
	(C_backend_src.pp_value_suffix self loop_vars pp_var) value
539
    | _ -> assert false
540
  in
541
  begin
542
    reset_loop_counter ();
543
    (*reset_addr_counter ();*)
544
    aux fmt reordered_loop_vars
545
  end
546

    
547
let pp_acsl_spec_contracts stateless pre post machines m outputs fmt spec = 
548
  let self = mk_self m in
549
    (* let is_output = fun oid -> List.exists (fun v -> v.var_id = oid) outputs in *)
550
  let pp_eexpr_expr fmt ee = 
551
      (* If the eexpr contains a single definition we use it directly. Otherwise,
552
	 we rely on an external predicate *)
553
    let conv_m =  machine_from_minimachine_logics m ee in
554
    match ee.mmstep_logic.step_instrs with
555
    | [MStep([o], i, vl)] -> 
556
      fprintf fmt "%a %t"
557
	(Utils.fprintf_list ~sep:" " pp_quantifiers) ee.mquantifiers
558
	(fun fmt ->
559
	  let value = Fun (i, vl) in
560
       	  pp_expr_rhs
561
	    conv_m
562
	    (pp_c_var_read conv_m) 
563
	    fmt
564
	    o.var_type value 
565
	)
566
    | _ -> fprintf fmt "spec_%i(%a%t);" 
567
      ee.muid   
568
      (Utils.fprintf_list ~sep:", " (pp_acsl_var_read "" outputs)) ee.mmstep_logic.step_inputs
569
      (fun fmt -> if stateless then fprintf fmt "" else fprintf fmt ", %s%s" (if !Options.no_pointer then "*" else "") self)
570
  in
571
  fprintf fmt "@[<v 2>/*@@ ";
572
  (* Valid pointers *)
573
  pp_requires_mem stateless machines fmt m;
574
  
575
  (* Spec requires *)
576
  Utils.fprintf_list ~sep:"" 
577
    (fun fmt r -> fprintf fmt "requires %a@ " pp_eexpr_expr r) 
578
    fmt 
579
    spec.m_requires;
580
  pre fmt;
581
  Utils.fprintf_list ~sep:"" 
582
    (fun fmt r -> fprintf fmt "ensures %a@ " pp_eexpr_expr r) 
583
    fmt 
584
    spec.m_ensures;
585
  post fmt;
586
  fprintf fmt "@ ";
587
    (* TODO assigns + separated *)
588
    (* fprintf fmt "assigns *self%t%a;@ "  *)
589
    (*   (fun fmt -> if List.length outputs > 0 then fprintf fmt ", ") *)
590
    (*   (fprintf_list ~sep:"," (fun fmt v -> fprintf fmt "*%s" v.var_id)) outputs; *)
591
    Utils.fprintf_list ~sep:"@ " (fun fmt (name, assumes, ensures) -> 
592
      fprintf fmt "behavior %s:@[@ %a@ %a@]" 
593
	name
594
	(Utils.fprintf_list ~sep:"@ " (fun fmt r -> fprintf fmt "assumes %a" pp_eexpr_expr r)) assumes
595
	(Utils.fprintf_list ~sep:"@ " (fun fmt r -> fprintf fmt "ensures %a" pp_eexpr_expr r)) ensures
596
    ) fmt spec.m_behaviors;
597
    (* Assings *)
598
    pp_assigns [] stateless machines fmt m;
599
    fprintf fmt "@]@ */@.";
600
    ()
601

    
602

    
603
let pp_c_decl_struct_spec_var fmt id =
604
  if !Options.ghost_mode then
605
    fprintf fmt "/*@@ ghost %a */" pp_c_decl_struct_var id
606
 else 
607
    fprintf fmt "%a" pp_c_decl_struct_var id
608
  
609
module Make = 
610
  functor (SpecArg: SPECARG) -> 
611
struct
612
  
613
  open SpecArg
614

    
615
(**************************************************************************)
616
(*                              INITIALIZE DATA                           *)
617
(**************************************************************************)
618
(* Map each machine uid to its compiled spec (and TODO later annot) *)
619
let compiled_contracts : (node_desc * spec_machine_t) list ref = ref []
620
let compiled_ee : eexpr_minimachine_t list ref = ref []
621

    
622
let init machines =
623
  
624
  List.iter (
625
    fun m -> (* iterate through spec eexpr and register them *)
626
      let nd = m.mname in
627
      let translate_eexpr ee = 
628
	        let eem = translate_eexpr nd ee in
629
	        compiled_ee := eem::!compiled_ee;
630
	        eem
631
      in
632
      let tl = List.map translate_eexpr in
633
      match m.mspec with
634
      | None -> ()
635
      | Some spec ->
636
	let compiled_spec =
637
	  { m_requires = tl spec.requires;
638
	    m_ensures =  tl spec.ensures;
639
	    m_behaviors = List.map 
640
	      (fun (s, eel1, eel2, _) -> (s, tl eel1, tl eel2))
641
	      spec.behaviors
642
	  }
643
	in
644
	compiled_contracts := (nd, compiled_spec)::!compiled_contracts
645
  ) machines
646

    
647
let get_ee_minimachine ee = 
648
  List.find (fun eem -> eem.muid = ee.eexpr_tag) !compiled_ee 
649

    
650
let get_spec nd = List.assoc nd !compiled_contracts
651

    
652
(**************************************************************************)
653
(*                              HEADER                                    *)
654
(**************************************************************************)
655

    
656
module HdrMod = struct
657

    
658
let get_spec_memories m =
659
  match m.mspec with
660
    None -> []
661
  | Some _ -> 
662
    let spec = get_spec m.mname in
663
    List.flatten (
664
    List.map (fun ee -> ee.mmmemory) 
665
      (spec.m_requires@
666
	 spec.m_ensures@
667
	 (List.fold_left 
668
	    (fun accu (_,assumes, ensures) -> assumes@ensures@accu) 
669
	    [] spec.m_behaviors)
670
      ))
671

    
672
let _print_machine_decl_init_fun_prefix pre post fmt m =
673
      let self = mk_self m in
674
	    fprintf fmt "/*@@requires \\valid(%s);@." self;
675
      pre fmt;
676
      post fmt;
677
	    fprintf fmt "assigns *%s;*/@." self
678

    
679

    
680
let _print_machine_decl_step_fun_prefix stateless pre post fmt m =
681
(* Print specification contracts if any *)
682
      (match m.mspec with
683
      | None -> pp_acsl_mem_valid stateless pre post machines fmt m
684
      | Some _ -> 
685
	let spec = get_spec m.mname in
686
    	pp_acsl_spec_contracts stateless pre post machines m m.mstep.step_outputs fmt spec
687
      )
688

    
689
let has_spec_mem m = (get_spec_memories m) <> []
690

    
691
let pp_registers_struct fmt m = 
692
  let spec_memories = get_spec_memories m in
693
  (Utils.fprintf_list ~sep:"@;" pp_c_decl_struct_spec_var) fmt spec_memories
694

    
695
let print_machine_decl_prefix fmt m =
696
  (* Print specification if any *)
697
  let mems = Machine_code.get_mems m machines in  
698
  (match m.mspec with
699
  | None -> ()
700
  | Some _ ->
701
    let spec = get_spec m.mname in
702
    pp_acsl_spec_logics (List.length mems == 0) m fmt spec
703
  )
704

    
705
let print_machine_decl_step_fun_prefix fmt m = _print_machine_decl_step_fun_prefix false (fun fmt -> ()) (fun fmt -> ()) fmt m
706

    
707
let print_machine_decl_init_fun_prefix fmt m = _print_machine_decl_init_fun_prefix (fun fmt -> ()) (fun fmt -> ()) fmt m
708
	
709
let print_machine_decl_stateless_fun_prefix fmt m = _print_machine_decl_step_fun_prefix true (fun fmt -> ()) (fun fmt -> ()) fmt m
710

    
711
let print_global_decl = fun fmt -> ()
712

    
713
end
714

    
715
(**************************************************************************)
716
(*                              CODE                                      *)
717
(**************************************************************************)
718

    
719
module SrcMod =
720
struct
721

    
722

    
723
(**************************************************************************)
724
(*                              CODE                                      *)
725
(**************************************************************************)
726

    
727
  let pp_instr_debug m (eem: eexpr_minimachine_t) fmt instrs =
728
    let self = mk_self m in
729
    let conv_m = machine_from_minimachine_effects m eem in
730
    Utils.fprintf_list ~sep:"@;" 
731
      (C_backend_src.pp_machine_instr_internal 
732
	 [] (* no dependencies considered *)
733
	 conv_m
734
	 (* (m.mname.node_id,  *)
735
	 (*  ee.mmstep_effects.step_inputs,  *)
736
	 (*  ee.mmstep_effects.step_outputs,  *)
737
	 (*  ee.mmstep_effects.step_locals,  *)
738
	 (*  ee.mmmemory,  *)
739
	 (*  ee.mminstances,  *)
740
	 (*  ee.mmcalls) *)
741
	 self)
742
      fmt 
743
      instrs
744

    
745
  (* Print instructions *)
746
  let pp_instr pp_machine_instr m (eem: eexpr_minimachine_t) fmt instrs =
747
    let self = mk_self m in
748
    let conv_m = machine_from_minimachine_effects m eem in
749
    Utils.fprintf_list ~sep:"@;" 
750
      (pp_machine_instr 
751
	 [] (* no dependencies considered *)
752
	 conv_m
753
	 (* (m.mname.node_id,  *)
754
	 (*  ee.mmstep_effects.step_inputs,  *)
755
	 (*  ee.mmstep_effects.step_outputs,  *)
756
	 (*  ee.mmstep_effects.step_locals,  *)
757
	 (*  ee.mmmemory,  *)
758
	 (*  ee.mminstances,  *)
759
	 (*  ee.mmcalls) *)
760
	 self)
761
      fmt 
762
      instrs
763

    
764
  let pp_acsl_spec_side_effects pp_machine_instr m fmt spec = 
765
    let pp_side_effects fmt ee =  
766
      (* Declare local vars *)
767
      let locals = 
768
	List.filter 
769
	  (fun l -> not (List.mem l m.mstep.step_locals)) 
770
	  ee.mmstep_effects.step_locals 
771
      in
772
      (Utils.fprintf_list ~sep:";@," pp_c_decl_local_var) fmt locals;
773
      Utils.pp_final_char_if_non_empty ";@," locals fmt ;
774
      pp_instr pp_machine_instr m ee fmt ee.mmstep_effects.step_instrs
775
    in
776
    let effects = spec.m_requires@spec.m_ensures@
777
      (List.fold_left 
778
	 (fun accu (_,assumes, ensures) -> assumes@ensures@accu) 
779
	 [] spec.m_behaviors)
780
    in
781
    let effects = List.filter (fun ee -> ee.mmstep_effects.step_instrs <> []) effects in
782
    let all_instrs = List.flatten (List.map (fun e -> e.mmstep_effects.step_instrs) effects) in
783
    if all_instrs <> [] then (
784
      fprintf fmt "// Begin of specification memory update block@;";
785
      if !Options.ghost_mode then
786
	fprintf fmt "@[<v 3>/*@@ ghost %a@]@;*/@;" 
787
	  (Utils.fprintf_list ~sep:"@;" pp_side_effects)
788
	  effects
789
      else (
790
	Utils.fprintf_list ~sep:"@;" pp_side_effects fmt effects;
791
	fprintf fmt "@;"
792
      )
793
      ;
794
      fprintf fmt "// End of specification memory update block@."
795
    )
796

    
797
let pp_acsl_spec_init_side_effects pp_machine_instr m fmt spec = 
798
   let pp_side_effects fmt ee =  
799
    (* Print instructions *)
800
    pp_instr pp_machine_instr m ee fmt ee.mminit
801
  in
802
  
803
  let effects = spec.m_requires@spec.m_ensures@
804
    (List.fold_left 
805
       (fun accu (_,assumes, ensures) -> assumes@ensures@accu) 
806
       [] spec.m_behaviors)
807
  in
808
  
809
  let effects = List.filter (fun ee -> ee.mminit <> []) effects in
810
  let all_instrs = List.flatten (List.map (fun e -> e.mminit) effects) in
811
  if all_instrs <> [] then (
812
    fprintf fmt "// Begin of specification memory init block@;";
813
    if !Options.ghost_mode then
814
      fprintf fmt "@[<v 3>/*@@ ghost %a@]@;*/@;" 
815
	(Utils.fprintf_list ~sep:"@;" pp_side_effects)
816
	effects
817
    else (
818
      Utils.fprintf_list ~sep:"@;" pp_side_effects fmt effects;
819
      fprintf fmt "@;"
820
    )
821
    ;
822
    fprintf fmt "// End of specification memory init block@."
823
  )
824

    
825
let print_step_code_postfix pp_machine_instr stateless fmt m =
826
  (* Print specification if any: insert side effect at the end of the function body  *)
827
  match m.mspec with
828
  | None -> ()
829
  | Some _ -> (* the node contain a spec. It has been compiled in the init phase *)
830
    let spec = get_spec m.mname in
831
    pp_acsl_spec_side_effects pp_machine_instr m fmt spec
832

    
833
let print_step_code_prefix pp_machine_instr x fmt m = ()
834
let print_step_code_midfix pp_machine_instr x fmt m = ()
835

    
836
  let print_instr_prefix m fmt x = ()
837
  let print_instr_postfix m fmt x = ()
838
    
839
let print_init_code_postfix pp_machine_instr fmt m =
840
  (* Print specification if any: insert side effect at the end of the function body  *)
841
  match m.mspec with
842
  | None -> ()
843
  | Some _ -> (* the node contain a spec. It has been compiled in the init phase *)
844
    let spec = get_spec m.mname in
845
    pp_acsl_spec_init_side_effects pp_machine_instr m fmt spec
846
    
847
end
848

    
849
(**************************************************************************)
850
(*                              MAKEFILE                                  *)
851
(**************************************************************************)
852

    
853
let makefile_targets fmt basename nodename dependencies =
854
  fprintf fmt "FRAMACEACSL=`frama-c -print-share-path`/e-acsl@.";
855
  (* EACSL version of library file . c *)
856
  fprintf fmt "%s_eacsl.c: %s.c %s.h@." basename basename basename;
857
  fprintf fmt 
858
    "\tframa-c -e-acsl-full-mmodel -machdep x86_64 -e-acsl %s.c -then-on e-acsl -print -ocode %s_eacsl.c@." 
859
    basename basename; 
860
  fprintf fmt "@.";
861
  fprintf fmt "@.";
862

    
863
  (* EACSL version of library file . c + main .c  *)
864
  fprintf fmt "%s_main_eacsl.c: %s.c %s.h %s_main.c@." basename basename basename basename;
865
  fprintf fmt "\tframa-c -e-acsl-full-mmodel -machdep x86_64 -e-acsl %s.c %s_main.c -then-on e-acsl -print -ocode %s_main_eacsl.i@." 
866
    basename basename basename; 
867
  (* Ugly hack to deal with eacsl bugs *)
868
  fprintf fmt "\tgrep -v _fc_stdout %s_main_eacsl.i > %s_main_eacsl.c" basename basename;
869
  fprintf fmt "@.";
870
  fprintf fmt "@.";
871

    
872
  (* EACSL version of binary *)
873
  fprintf fmt "%s_main_eacsl: %s_main_eacsl.c@." basename basename;
874
  fprintf fmt "\t${GCC} -Wno-attributes -I${INC} -I. -c %s_main_eacsl.c@." basename; (* compiling instrumented lib + main *)
875
  C_backend_makefile.fprintf_dependencies fmt dependencies; 
876
  fprintf fmt "\t${GCC} -Wno-attributes -o %s_main_eacsl io_frontend.o %a %s %s_main_eacsl.o %a@." 
877
    basename 
878
    (Utils.fprintf_list ~sep:" " (fun fmt (s, _, _) -> Format.fprintf fmt "%s.o" s)) 
879
    (C_backend_makefile.compiled_dependencies dependencies)
880
    ("${FRAMACEACSL}/e_acsl.c " 
881
     ^ "${FRAMACEACSL}/memory_model/e_acsl_bittree.c " 
882
     ^ "${FRAMACEACSL}/memory_model/e_acsl_mmodel.c")
883
    basename 
884
    (Utils.fprintf_list ~sep:" " (fun fmt lib -> fprintf fmt "-l%s" lib)) 
885
    (C_backend_makefile.lib_dependencies dependencies)
886
  ;
887
  fprintf fmt "@.";
888

    
889
module MakefileMod =
890
struct
891
  let other_targets = makefile_targets
892
    
893
end
894

    
895
module MainMod = C_backend_main.EmptyMod
896

    
897
module CoqMod = C_backend_coq.EmptyMod
898

    
899
end
900
(* Local Variables: *)
901
(* compile-command:"make -C ../../.." *)
902
(* End: *)
(8-8/9)