Project

General

Profile

Download (29.6 KB) Statistics
| Branch: | Tag: | Revision:
1
open Lustre_types
2
open Machine_code_types
3
open Machine_code_common
4
open Format
5
(* open Horn_backend_common
6
 * open Horn_backend *)
7
open Zustre_data
8
  
9
let report = Log.report ~plugin:"z3 interface"
10
           
11
module HBC = Horn_backend_common
12
let node_name = HBC.node_name
13

    
14
let concat = HBC.concat
15

    
16
let rename_machine = HBC.rename_machine
17
let rename_machine_list = HBC.rename_machine_list
18

    
19
let rename_next = HBC.rename_next
20
let rename_mid = HBC.rename_mid
21
let rename_current = HBC.rename_current
22

    
23
let rename_current_list = HBC.rename_current_list
24
let rename_mid_list = HBC.rename_mid_list
25
let rename_next_list = HBC.rename_next_list
26

    
27
let full_memory_vars = HBC.full_memory_vars
28
let inout_vars = HBC.inout_vars
29
let reset_vars = HBC.reset_vars
30
let step_vars = HBC.step_vars
31
let local_memory_vars = HBC.local_memory_vars
32
let step_vars_m_x = HBC.step_vars_m_x
33
let step_vars_c_m_x = HBC.step_vars_c_m_x
34
  
35
let machine_reset_name = HBC.machine_reset_name 
36
let machine_step_name = HBC.machine_step_name 
37
let machine_stateless_name = HBC.machine_stateless_name 
38

    
39
let preprocess = Horn_backend.preprocess
40
  
41

    
42
exception UnknownFunction of (string * (Format.formatter -> unit))
43
(** Sorts
44

    
45
A sort is introduced for each basic type and each enumerated type.
46

    
47
A hashtbl records these and allow easy access to sort values, when
48
   provided with a enumerated type name. 
49

    
50
*)
51
        
52
let bool_sort = Z3.Boolean.mk_sort !ctx
53
let int_sort = Z3.Arithmetic.Integer.mk_sort !ctx
54
let real_sort = Z3.Arithmetic.Real.mk_sort !ctx
55

    
56

    
57
let get_const_sort = Hashtbl.find const_sorts  
58
let get_sort_elems = Hashtbl.find sort_elems
59
let get_tag_sort id = try Hashtbl.find const_tags id with _ -> Format.eprintf "Unable to find sort for tag=%s@." id; assert false
60
  
61

    
62
  
63
let decl_sorts () =
64
  Hashtbl.iter (fun typ decl ->
65
    match typ with
66
    | Tydec_const var ->
67
      (match decl.top_decl_desc with
68
      | TypeDef tdef -> (
69
	match tdef.tydef_desc with
70
	| Tydec_enum tl ->
71
	  let new_sort = Z3.Enumeration.mk_sort_s !ctx var tl in
72
          Hashtbl.add const_sorts var new_sort;
73
          Hashtbl.add sort_elems new_sort tl;
74
          List.iter (fun t -> Hashtbl.add const_tags t new_sort) tl
75
          
76
	| _ -> Format.eprintf "Unknown type : %a@.@?" Printers.pp_var_type_dec_desc typ; assert false
77
      )
78
      | _ -> assert false
79
      )
80
    | _        -> ()) Corelang.type_table
81

    
82
                 
83
let rec type_to_sort t =
84
  if Types.is_bool_type t  then bool_sort else
85
    if Types.is_int_type t then int_sort else 
86
  if Types.is_real_type t then real_sort else 
87
  match (Types.repr t).Types.tdesc with
88
  | Types.Tconst ty       -> get_const_sort ty
89
  | Types.Tclock t        -> type_to_sort t
90
  | Types.Tarray(dim,ty)   -> Z3.Z3Array.mk_sort !ctx int_sort (type_to_sort ty)
91
  | Types.Tstatic(d, ty)-> type_to_sort ty
92
  | Types.Tarrow _
93
  | _                     -> Format.eprintf "internal error: pp_type %a@."
94
                               Types.print_ty t; assert false
95

    
96

    
97
(* let idx_var = *)
98
(*   Z3.FuncDecl.mk_func_decl_s !ctx "__idx__" [] idx_sort  *)
99
    
100
(* let uid_var = *)
101
(*   Z3.FuncDecl.mk_func_decl_s !ctx "__uid__" [] uid_sort  *)
102

    
103
(** Func decls
104

    
105
    Similarly fun_decls are registerd, by their name, into a hashtbl. The
106
    proposed encoding introduces a 0-ary fun_decl to model variables and
107
    fun_decl with arguments to declare reset and step predicates.
108

    
109

    
110

    
111
*)
112
let register_fdecl id fd = Hashtbl.add decls id fd
113
let get_fdecl id =
114
  try
115
    Hashtbl.find decls id
116
  with Not_found -> (report ~level:3 (fun fmt -> Format.fprintf fmt  "Unable to find func_decl %s@.@?" id); raise Not_found)
117

    
118
let pp_fdecls fmt =
119
  Format.fprintf fmt "Registered fdecls: @[%a@]@ "
120
    (Utils.fprintf_list ~sep:"@ " Format.pp_print_string)  (Hashtbl.fold (fun id _ accu -> id::accu) decls [])
121

    
122
    
123
let decl_var id =
124
  (* Format.eprintf "Declaring var %s@." id.var_id; *)
125
  let fdecl = Z3.FuncDecl.mk_func_decl_s !ctx id.var_id [] (type_to_sort id.var_type) in
126
  register_fdecl id.var_id fdecl;
127
  fdecl
128

    
129
(* Declaring the function used in expr *) 
130
let decl_fun op args typ =
131
  let args = List.map type_to_sort args in
132
  let fdecl = Z3.FuncDecl.mk_func_decl_s !ctx op args (type_to_sort typ) in
133
  register_fdecl op fdecl;
134
  fdecl
135

    
136
let idx_sort = int_sort
137
let uid_sort = Z3.Z3List.mk_sort !ctx (Z3.Symbol.mk_string !ctx "uid_list") int_sort
138
let uid_conc = 
139
  let fd = Z3.Z3List.get_cons_decl uid_sort in
140
  fun head tail -> Z3.FuncDecl.apply fd [head;tail]
141

    
142
let get_instance_uid =
143
  let hash : (string, int) Hashtbl.t = Hashtbl.create 13 in
144
  let cpt = ref 0 in
145
  fun i ->
146
    let id =
147
      if Hashtbl.mem hash i then
148
	Hashtbl.find hash i
149
      else (
150
	incr cpt;
151
	Hashtbl.add hash i !cpt;
152
	!cpt
153
      )
154
    in
155
    Z3.Arithmetic.Integer.mk_numeral_i !ctx id
156
  
157

    
158
  
159
let decl_rel ?(no_additional_vars=false) name args_sorts =
160
  (* Enriching arg_sorts with two new variables: a counting index and an
161
     uid *)
162
  let args_sorts =
163
    if no_additional_vars then args_sorts else idx_sort::uid_sort::args_sorts in
164
  
165
  (* let args_sorts = List.map (fun v -> type_to_sort v.var_type) args in *)
166
  if !debug then
167
    Format.eprintf "Registering fdecl %s (%a)@."
168
      name
169
      (Utils.fprintf_list ~sep:"@ "
170
	 (fun fmt sort -> Format.fprintf fmt "%s" (Z3.Sort.to_string sort)))
171
      args_sorts
172
  ;
173
  let fdecl = Z3.FuncDecl.mk_func_decl_s !ctx name args_sorts bool_sort in
174
  Z3.Fixedpoint.register_relation !fp fdecl;
175
  register_fdecl name fdecl;
176
  fdecl
177
  
178

    
179

    
180
(* Shared variables to describe counter and uid *)
181

    
182
let idx = Corelang.dummy_var_decl "__idx__" Type_predef.type_int
183
let idx_var = Z3.Expr.mk_const_f !ctx (decl_var idx) 
184
let uid = Corelang.dummy_var_decl "__uid__" Type_predef.type_int
185
let uid_fd = Z3.FuncDecl.mk_func_decl_s !ctx "__uid__" [] uid_sort 
186
let _ = register_fdecl "__uid__"  uid_fd  
187
let uid_var = Z3.Expr.mk_const_f !ctx uid_fd 
188

    
189
(** Conversion functions
190

    
191
    The following is similar to the Horn backend. Each printing function is
192
    rephrased from pp_xx to xx_to_expr and produces a Z3 value.
193

    
194
*)
195

    
196

    
197
(* Returns the f_decl associated to the variable v *)
198
let horn_var_to_expr v =
199
  Z3.Expr.mk_const_f !ctx (get_fdecl v.var_id)
200

    
201

    
202

    
203

    
204
  (* Used to print boolean constants *)
205
let horn_tag_to_expr t =
206
  if t = tag_true then
207
    Z3.Boolean.mk_true !ctx
208
  else if t = tag_false then
209
    Z3.Boolean.mk_false !ctx
210
  else
211
    (* Finding the associated sort *)
212
    let sort = get_tag_sort t in
213
    let elems = get_sort_elems sort in 
214
    let res : Z3.Expr.expr option =
215
      List.fold_left2 (fun res cst expr ->
216
          match res with
217
          | Some _ -> res
218
          | None -> if t = cst then Some (expr:Z3.Expr.expr) else None
219
        ) None elems (Z3.Enumeration.get_consts sort)
220
    in
221
    match res with None -> assert false | Some s -> s
222
    
223
(* Prints a constant value *)
224
let rec horn_const_to_expr c =
225
  match c with
226
    | Const_int i    -> Z3.Arithmetic.Integer.mk_numeral_i !ctx i
227
    | Const_real r  -> Z3.Arithmetic.Real.mk_numeral_s !ctx (Real.to_string r)
228
    | Const_tag t    -> horn_tag_to_expr t
229
    | _              -> assert false
230

    
231

    
232

    
233
(* Default value for each type, used when building arrays. Eg integer array
234
   [2;7] is defined as (store (store (0) 1 7) 0 2) where 0 is this default value
235
   for the type integer (arrays).
236
*)
237
let rec horn_default_val t =
238
  let t = Types.dynamic_type t in
239
  if Types.is_bool_type t  then Z3.Boolean.mk_true !ctx else
240
  if Types.is_int_type t then Z3.Arithmetic.Integer.mk_numeral_i !ctx 0 else 
241
  if Types.is_real_type t then Z3.Arithmetic.Real.mk_numeral_i !ctx 0 else 
242
  (* match (Types.dynamic_type t).Types.tdesc with
243
   * | Types.Tarray(dim, l) -> (\* TODO PL: this strange code has to be (heavily) checked *\)
244
   *    let valt = Types.array_element_type t in
245
   *    fprintf fmt "((as const (Array Int %a)) %a)"
246
   *      pp_type valt 
247
   *      pp_default_val valt
248
   * | Types.Tstruct(l) -> assert false
249
   * | Types.Ttuple(l) -> assert false
250
   * |_ -> *) assert false
251

    
252
(* Conversion of basic library functions *)
253
    
254
let horn_basic_app i vl (vltyp, typ) =
255
  match i, vl with
256
  | "ite", [v1; v2; v3] ->  Z3.Boolean.mk_ite !ctx v1 v2 v3
257
  | "uminus", [v] ->    Z3.Arithmetic.mk_unary_minus
258
       !ctx v
259
  | "not", [v] ->
260
     Z3.Boolean.mk_not
261
       !ctx v
262
  | "=", [v1; v2] ->
263
     Z3.Boolean.mk_eq
264
       !ctx v1 v2
265
  | "&&", [v1; v2] ->
266
     Z3.Boolean.mk_and
267
       !ctx
268
       [v1; v2]
269
  | "||", [v1; v2] ->
270
          Z3.Boolean.mk_or
271
       !ctx
272
       [v1;
273
         v2]
274

    
275
  | "impl", [v1; v2] ->
276
     Z3.Boolean.mk_implies
277
       !ctx v1 v2
278
 | "mod", [v1; v2] ->
279
          Z3.Arithmetic.Integer.mk_mod
280
       !ctx v1 v2
281
  | "equi", [v1; v2] ->
282
          Z3.Boolean.mk_eq
283
       !ctx
284
       v1 v2
285
  | "xor", [v1; v2] ->
286
          Z3.Boolean.mk_xor
287
       !ctx v1 v2
288
  | "!=", [v1; v2] ->
289
     Z3.Boolean.mk_not
290
       !ctx
291
       (
292
         Z3.Boolean.mk_eq
293
           !ctx v1 v2
294
       )
295
  | "/", [v1; v2] ->
296
     Z3.Arithmetic.mk_div
297
       !ctx v1 v2
298

    
299
  | "+", [v1; v2] ->
300
     Z3.Arithmetic.mk_add
301
       !ctx
302
       [v1; v2]
303
  | "-", [v1; v2] ->
304
     Z3.Arithmetic.mk_sub
305
       !ctx
306
       [v1 ;  v2]
307
       
308
  | "*", [v1; v2] ->
309
     Z3.Arithmetic.mk_mul
310
       !ctx
311
       [ v1;  v2]
312

    
313

    
314
  | "<", [v1; v2] ->
315
     Z3.Arithmetic.mk_lt
316
       !ctx v1 v2
317
  | "<=", [v1; v2] ->
318
     Z3.Arithmetic.mk_le
319
       !ctx v1 v2
320
  | ">", [v1; v2] ->
321
     Z3.Arithmetic.mk_gt
322
       !ctx v1 v2
323
  | ">=", [v1; v2] ->
324
     Z3.Arithmetic.mk_ge
325
       !ctx v1 v2
326
  | "int_to_real", [v1] ->
327
     Z3.Arithmetic.Integer.mk_int2real
328
       !ctx v1
329
  | _ ->
330
     let fd =
331
       try
332
         get_fdecl i
333
       with Not_found -> begin
334
           report ~level:3 (fun fmt -> Format.fprintf fmt "Registering function %s as uninterpreted function in Z3@.%s: (%a) -> %a" i i (Utils.fprintf_list ~sep:"," Types.print_ty) vltyp Types.print_ty typ); 
335
           decl_fun i vltyp typ
336
         end
337
     in
338
     Z3.FuncDecl.apply fd vl
339
    
340
     
341
  (* | _, [v1; v2] ->      Z3.Boolean.mk_and
342
   *      !ctx
343
   *      (val_to_expr v1)
344
   *      (val_to_expr v2)
345
   * 
346
   *      Format.fprintf fmt "(%s %a %a)" i val_to_exprr v1 val_to_expr v2 *)
347

    
348
(* | _ -> (
349
 *     let msg fmt = Format.fprintf fmt
350
 *                     "internal error: zustre unkown function %s (nb args = %i)@."
351
 *                     i (List.length vl)
352
 *     in
353
 *     raise (UnknownFunction(i, msg))
354
 *   ) *)
355

    
356
           
357
(* Convert a value expression [v], with internal function calls only.  [pp_var]
358
   is a printer for variables (typically [pp_c_var_read]), but an offset suffix
359
   may be added for array variables
360
*)
361
let rec horn_val_to_expr ?(is_lhs=false) m self v =
362
  (* Format.eprintf "h_v2e %a@." (Machine_code_common.pp_val m) v ; *)
363
  match v.value_desc with
364
  | Cst c       -> horn_const_to_expr c
365

    
366
  (* Code specific for arrays *)
367
  | Array il    ->
368
     (* An array definition: 
369
	(store (
370
	  ...
371
 	    (store (
372
	       store (
373
	          default_val
374
	       ) 
375
	       idx_n val_n
376
	    ) 
377
	    idx_n-1 val_n-1)
378
	  ... 
379
	  idx_1 val_1
380
	) *)
381
     let rec build_array (tab, x) =
382
       match tab with
383
       | [] -> horn_default_val v.value_type(* (get_type v) *)
384
       | h::t ->
385
	  Z3.Z3Array.mk_store
386
            !ctx
387
	    (build_array (t, (x+1)))
388
	    (Z3.Arithmetic.Integer.mk_numeral_i !ctx x)
389
	    (horn_val_to_expr ~is_lhs:is_lhs m self h)
390
     in
391
     build_array (il, 0)
392
     
393
  | Access(tab,index) ->
394
     Z3.Z3Array.mk_select !ctx 
395
       (horn_val_to_expr ~is_lhs:is_lhs m self tab)
396
       (horn_val_to_expr ~is_lhs:is_lhs m self index)
397

    
398
  (* Code specific for arrays *)
399
    
400
  | Power (v, n)  -> assert false
401
  | Var v    ->
402
     if is_memory m v then
403
       if Types.is_array_type v.var_type
404
       then assert false
405
       else horn_var_to_expr (rename_machine self ((if is_lhs then rename_next else rename_current) (* self *) v))
406
     
407
     else 
408
       horn_var_to_expr
409
         (rename_machine
410
            self
411
            v)
412
  | Fun (n, vl)   -> horn_basic_app n (List.map (horn_val_to_expr m self) vl) (List.map (fun v -> v.value_type) vl, v.value_type)
413

    
414
let no_reset_to_exprs machines m i =
415
  let (n,_) = List.assoc i m.minstances in
416
  let target_machine = List.find (fun m  -> m.mname.node_id = (Corelang.node_name n)) machines in
417

    
418
  let m_list = 
419
    rename_machine_list
420
      (concat m.mname.node_id i)
421
      (rename_mid_list (full_memory_vars machines target_machine))
422
  in
423
  let c_list =
424
    rename_machine_list
425
      (concat m.mname.node_id i)
426
      (rename_current_list (full_memory_vars machines target_machine))
427
  in
428
  match c_list, m_list with
429
  | [chd], [mhd] ->
430
     let expr =
431
       Z3.Boolean.mk_eq !ctx 
432
         (horn_var_to_expr mhd)
433
         (horn_var_to_expr chd)
434
     in
435
     [expr]
436
  | _ -> (
437
    let exprs =
438
      List.map2 (fun mhd chd -> 
439
          Z3.Boolean.mk_eq !ctx 
440
            (horn_var_to_expr mhd)
441
            (horn_var_to_expr chd)
442
        )
443
        m_list
444
        c_list
445
    in
446
    exprs
447
  )
448

    
449
let instance_reset_to_exprs machines m i =
450
  let (n,_) = List.assoc i m.minstances in
451
  let target_machine = List.find (fun m  -> m.mname.node_id = (Corelang.node_name n)) machines in
452
  let vars =
453
    (rename_machine_list
454
       (concat m.mname.node_id i)
455
       (rename_current_list (full_memory_vars machines target_machine))@  (rename_mid_list (full_memory_vars machines target_machine))
456
    )
457
    
458
  in
459
  let expr =
460
    Z3.Expr.mk_app
461
      !ctx
462
      (get_fdecl (machine_reset_name (Corelang.node_name n)))
463
      (List.map (horn_var_to_expr) (idx::uid::vars))
464
  in
465
  [expr]
466

    
467
let instance_call_to_exprs machines reset_instances m i inputs outputs =
468
  let self = m.mname.node_id in
469

    
470
  (* Building call args *)
471
  let idx_uid_inout =
472
    (* Additional input to register step counters, and uid *)
473
    let idx = horn_var_to_expr idx in
474
    let uid = uid_conc (get_instance_uid i) (horn_var_to_expr uid) in
475
    let inout = 
476
      List.map (horn_val_to_expr m self)
477
	(inputs @ (List.map (fun v -> mk_val (Var v) v.var_type) outputs))
478
    in
479
    idx::uid::inout
480
  in
481
    
482
  try (* stateful node instance *)
483
    begin
484
      let (n,_) = List.assoc i m.minstances in
485
      let target_machine = List.find (fun m  -> m.mname.node_id = Corelang.node_name n) machines in
486

    
487
      (* Checking whether this specific instances has been reset yet *)
488
      let reset_exprs = 
489
        if not (List.mem i reset_instances) then
490
	  (* If not, declare mem_m = mem_c *)
491
	  no_reset_to_exprs machines m i
492
        else
493
          [] (* Nothing to add yet *)
494
      in
495
      
496
      let mems = full_memory_vars machines target_machine in
497
      let rename_mems f = rename_machine_list (concat m.mname.node_id i) (f mems) in
498
      let mid_mems = rename_mems rename_mid_list in
499
      let next_mems = rename_mems rename_next_list in
500

    
501
      let call_expr = 
502
	match Corelang.node_name n, inputs, outputs, mid_mems, next_mems with
503
	| "_arrow", [i1; i2], [o], [mem_m], [mem_x] -> begin
504
          let stmt1 = (* out = ite mem_m then i1 else i2 *)
505
            Z3.Boolean.mk_eq !ctx
506
              ( (* output var *)
507
                horn_val_to_expr 
508
                  ~is_lhs:true
509
                  m self
510
                  (mk_val (Var o) o.var_type)
511
              )
512
              (
513
                Z3.Boolean.mk_ite !ctx 
514
	          (horn_var_to_expr mem_m) 
515
	          (horn_val_to_expr m self i1)
516
	          (horn_val_to_expr m self i2)
517
              )
518
          in
519
          let stmt2 = (* mem_X = false *)
520
            Z3.Boolean.mk_eq !ctx
521
	      (horn_var_to_expr mem_x)
522
              (Z3.Boolean.mk_false !ctx)
523
          in
524
          [stmt1; stmt2]
525
	end
526

    
527
	| node_name_n ->
528
           let expr = 
529
             Z3.Expr.mk_app
530
               !ctx
531
               (get_fdecl (machine_step_name (node_name n)))
532
               ( (* Arguments are input, output, mid_mems, next_mems *)
533
		 idx_uid_inout @ List.map (horn_var_to_expr) (mid_mems@next_mems)
534
		    
535
               )
536
           in
537
           [expr]
538
      in
539

    
540
      reset_exprs@call_expr
541
    end
542
  with Not_found -> ( (* stateless node instance *)
543
    let (n,_) = List.assoc i m.mcalls in
544
    let expr = 
545
      Z3.Expr.mk_app
546
        !ctx
547
        (get_fdecl (machine_stateless_name (node_name n)))
548
        idx_uid_inout 	  (* Arguments are inputs, outputs *)
549
    in
550
    [expr]
551
  )
552

    
553

    
554
    
555
(* (\* Prints a [value] indexed by the suffix list [loop_vars] *\) *)
556
(* let rec value_suffix_to_expr self value = *)
557
(*  match value.value_desc with *)
558
(*  | Fun (n, vl)  ->  *)
559
(*     horn_basic_app n (horn_val_to_expr self) (value_suffix_to_expr self vl) *)
560
    
561
(*  |  _            -> *)
562
(*    horn_val_to_expr self value *)
563

    
564

    
565
(* type_directed assignment: array vs. statically sized type
566
   - [var_type]: type of variable to be assigned
567
   - [var_name]: name of variable to be assigned
568
   - [value]: assigned value
569
   - [pp_var]: printer for variables
570
*)
571
let assign_to_exprs m var_name value =
572
  let self = m.mname.node_id in
573
  let e =
574
    Z3.Boolean.mk_eq
575
      !ctx
576
      (horn_val_to_expr ~is_lhs:true m self var_name)
577
      (horn_val_to_expr m self value)
578
  (* was: TODO deal with array accesses       (value_suffix_to_expr self value) *)
579
  in
580
  [e]
581

    
582
    
583
(* Convert instruction to Z3.Expr and update the set of reset instances *)
584
let rec instr_to_exprs machines reset_instances (m: machine_t) instr : Z3.Expr.expr list * ident list =
585
  match Corelang.get_instr_desc instr with
586
  | MComment _ -> [], reset_instances
587
  | MNoReset i -> (* we assign middle_mem with mem_m. And declare i as reset *)
588
    no_reset_to_exprs machines m i,
589
    i::reset_instances
590
  | MReset i -> (* we assign middle_mem with reset: reset(mem_m) *)
591
    instance_reset_to_exprs machines m i,
592
    i::reset_instances
593
  | MLocalAssign (i,v) ->
594
    assign_to_exprs
595
      m  
596
      (mk_val (Var i) i.var_type) v,
597
    reset_instances
598
  | MStateAssign (i,v) ->
599
    assign_to_exprs
600
      m 
601
      (mk_val (Var i) i.var_type) v,
602
    reset_instances
603
  | MStep ([i0], i, vl) when Basic_library.is_internal_fun i (List.map (fun v -> v.value_type) vl) ->
604
    assert false (* This should not happen anymore *)
605
  | MStep (il, i, vl) ->
606
    (* if reset instance, just print the call over mem_m , otherwise declare mem_m =
607
       mem_c and print the call to mem_m *)
608
    instance_call_to_exprs machines reset_instances m i vl il,
609
    reset_instances (* Since this instance call will only happen once, we
610
		       don't have to update reset_instances *)
611

    
612
  | MBranch (g,hl) -> (* (g = tag1 => expr1) and (g = tag2 => expr2) ...
613
			 should not be produced yet. Later, we will have to
614
			 compare the reset_instances of each branch and
615
			 introduced the mem_m = mem_c for branches to do not
616
			 address it while other did. Am I clear ? *)
617
    (* For each branch we obtain the logical encoding, and the information
618
       whether a sub node has been reset or not. If a node has been reset in one
619
       of the branch, then all others have to have the mem_m = mem_c
620
       statement. *)
621
    let self = m.mname.node_id in
622
    let branch_to_expr (tag, instrs) =
623
      let branch_def, branch_resets = instrs_to_expr machines reset_instances m instrs in
624
      let e =
625
	Z3.Boolean.mk_implies !ctx
626
          (Z3.Boolean.mk_eq !ctx 
627
             (horn_val_to_expr m self g)
628
	     (horn_tag_to_expr tag))
629
          branch_def in
630

    
631
      [e], branch_resets
632
	  
633
    in
634
    List.fold_left (fun (instrs, resets) b ->
635
      let b_instrs, b_resets = branch_to_expr b in
636
      instrs@b_instrs, resets@b_resets 
637
      ) ([], reset_instances) hl
638
  | MSpec _ -> assert false
639

    
640
and instrs_to_expr machines reset_instances m instrs = 
641
  let instr_to_exprs rs i = instr_to_exprs machines rs m i in
642
  let e_list, rs = 
643
    match instrs with
644
    | [x] -> instr_to_exprs reset_instances x 
645
    | _::_ -> (* TODO: check whether we should compuyte a AND on the exprs (expr list) built here. It was performed in the printer setting but seems to be useless here since the output is a list of exprs *)
646
       
647
       List.fold_left (fun (exprs, rs) i -> 
648
         let exprs_i, rs_i = instr_to_exprs rs i in
649
         exprs@exprs_i, rs@rs_i
650
       )
651
         ([], reset_instances) instrs 
652
	 
653
	 
654
    | [] -> [], reset_instances
655
  in
656
  let e = 
657
    match e_list with
658
    | [e] -> e
659
    | [] -> Z3.Boolean.mk_true !ctx
660
    | _ -> Z3.Boolean.mk_and !ctx e_list
661
  in
662
  e, rs
663

    
664

    
665
(*********************************************************)
666

    
667
(* Quantifiying universally all occuring variables *)
668
let add_rule ?(dont_touch=[]) vars  expr =
669
  (* let fds = Z3.Expr.get_args expr in *)
670
  (* Format.eprintf "Expr %s: args: [%a]@." *)
671
  (*   (Z3.Expr.to_string expr) *)
672
  (*   (Utils.fprintf_list ~sep:", " (fun fmt e -> Format.pp_print_string fmt (Z3.Expr.to_string e))) fds; *)
673

    
674
  (* (\* Old code relying on provided vars *\) *)
675
  (* let sorts = (List.map (fun id -> type_to_sort id.var_type) vars) in *)
676
  (* let symbols = (List.map (fun id -> Z3.FuncDecl.get_name (get_fdecl id.var_id)) vars) in *)
677
  
678
  (* New code: we extract vars from expr *)
679
  let module FDSet = Set.Make (struct type t = Z3.FuncDecl.func_decl
680
				      let compare = compare
681
				      let hash = Hashtbl.hash
682
  end)
683
  in
684
(* Fonction seems unused 
685

    
686
  let rec get_expr_vars e =
687
    let open Utils in
688
    let nb_args = Z3.Expr.get_num_args e in
689
    if nb_args <= 0 then (
690
      let fdecl = Z3.Expr.get_func_decl e in
691
      (* let params = Z3.FuncDecl.get_parameters fdecl in *)
692
      (* Format.eprintf "Extracting info about %s: @." (Z3.Expr.to_string e); *)
693
      let dkind = Z3.FuncDecl.get_decl_kind fdecl in
694
      match dkind with Z3enums.OP_UNINTERPRETED -> (
695
	(* Format.eprintf "kind = %s, " (match dkind with Z3enums.OP_TRUE -> "true" | Z3enums.OP_UNINTERPRETED -> "uninter"); *)
696
	(* let open Z3.FuncDecl.Parameter in *)
697
	(* List.iter (fun p -> *)
698
	(*   match p with *)
699
        (*     P_Int i -> Format.eprintf "int %i" i *)
700
	(*   | P_Dbl f -> Format.eprintf "dbl %f" f *)
701
	(*   | P_Sym s -> Format.eprintf "symb"  *)
702
	(*   | P_Srt s -> Format.eprintf "sort"  *)
703
	(*   | P_Ast _ ->Format.eprintf "ast"  *)
704
	(*   | P_Fdl f -> Format.eprintf "fundecl"  *)
705
	(*   | P_Rat s -> Format.eprintf "rat %s" s  *)
706
	     
707
	(* ) params; *)
708
	(* Format.eprintf "]@."; *)
709
	FDSet.singleton fdecl
710
      )
711
      | _ -> FDSet.empty
712
    )
713
    else (*if nb_args > 0 then*)
714
      List.fold_left
715
	(fun accu e ->  FDSet.union accu (get_expr_vars e))
716
	FDSet.empty (Z3.Expr.get_args e)
717
  in
718
 *)
719
  (* Unsed variable. Coul;d be reintroduced 
720
  let extracted_vars = FDSet.elements (FDSet.diff (get_expr_vars expr) (FDSet.of_list dont_touch)) in
721
  let extracted_sorts = List.map Z3.FuncDecl.get_range extracted_vars in
722
  let extracted_symbols = List.map Z3.FuncDecl.get_name extracted_vars in
723
   *)
724
  if !debug then (
725
    Format.eprintf "Declaring rule: %s with variables @[<v 0>@ [%a@ ]@]@ @."
726
      (Z3.Expr.to_string expr)
727
      (Utils.fprintf_list ~sep:",@ " (fun fmt e -> Format.fprintf fmt "%s" (Z3.Expr.to_string e))) (List.map horn_var_to_expr vars)
728
  )
729
    ;
730
  let expr = Z3.Quantifier.mk_forall_const
731
    !ctx  (* context *)
732
    (List.map horn_var_to_expr vars) (* TODO provide bounded variables as expr *)
733
    (* sorts           (\* sort list*\) *)
734
    (* symbols (\* symbol list *\) *)
735
    expr (* expression *)
736
    None (* quantifier weight, None means 1 *)
737
    [] (* pattern list ? *)
738
    [] (* ? *)
739
    None (* ? *)
740
    None (* ? *)
741
  in
742
  (* Format.eprintf "OK@.@?"; *)
743

    
744
  (*
745
    TODO: bizarre la declaration de INIT tout seul semble poser pb.
746
  *) 
747
  Z3.Fixedpoint.add_rule !fp
748
    (Z3.Quantifier.expr_of_quantifier expr)
749
    None
750

    
751
 
752
(********************************************************)
753
    
754
let machine_reset machines m =
755
  let locals = local_memory_vars machines m in
756
  
757
  (* print "x_m = x_c" for each local memory *)
758
  let mid_mem_def =
759
    List.map (fun v ->
760
      Z3.Boolean.mk_eq !ctx
761
	(horn_var_to_expr (rename_mid v))
762
	(horn_var_to_expr (rename_current v))
763
    ) locals
764
  in
765

    
766
  (* print "child_reset ( associated vars _ {c,m} )" for each subnode.
767
     Special treatment for _arrow: _first = true
768
  *)
769

    
770
  let reset_instances =
771
    
772
    List.map (fun (id, (n, _)) ->
773
      let name = node_name n in
774
      if name = "_arrow" then (
775
	Z3.Boolean.mk_eq !ctx
776
	  (
777
	    let vdecl = get_fdecl ((concat m.mname.node_id id) ^ "._arrow._first_m") in
778
	    Z3.Expr.mk_const_f !ctx vdecl
779
	  )
780
	  (Z3.Boolean.mk_true !ctx)
781
	  
782
      ) else (
783
	let machine_n = get_machine machines name in 
784
	
785
	Z3.Expr.mk_app
786
	  !ctx
787
	  (get_fdecl (name ^ "_reset"))
788
	  (List.map (horn_var_to_expr)
789
	     (idx::uid:: (* Additional vars: counters, uid *)
790
	      	(rename_machine_list (concat m.mname.node_id id) (reset_vars machines machine_n))
791
	  ))
792
	  
793
      )
794
    ) m.minstances
795
      
796
      
797
  in
798
  
799
  Z3.Boolean.mk_and !ctx (mid_mem_def @ reset_instances)
800
    
801
        
802

    
803
(*  TODO: empty list means true statement *)
804
let decl_machine machines m =
805
  if m.mname.node_id = Arrow.arrow_id then
806
    (* We don't do arrow function *)
807
    ()
808
  else
809
    begin
810
      let _ =
811
        List.map decl_var
812
      	  (
813
      	    (inout_vars machines m)@
814
      	      (rename_current_list (full_memory_vars machines m)) @
815
      	      (rename_mid_list (full_memory_vars machines m)) @
816
      	      (rename_next_list (full_memory_vars machines m)) @
817
      	      (rename_machine_list m.mname.node_id m.mstep.step_locals)
818
      	  )
819
      in
820
      if is_stateless m then
821
	begin
822
	  if !debug then 
823
	    Format.eprintf "Declaring a stateless machine: %s@." m.mname.node_id;
824

    
825
	  (* Declaring single predicate *)
826
	  let vars = inout_vars machines m in
827
	  let vars_types = List.map (fun v -> type_to_sort v.var_type) vars in
828
	  let _ = decl_rel (machine_stateless_name m.mname.node_id) vars_types in
829
	  
830
	  let horn_body, _ (* don't care for reset here *) =
831
	    instrs_to_expr
832
	      machines
833
	      ([] (* No reset info for stateless nodes *) )
834
	      m
835
	      m.mstep.step_instrs
836
	  in
837
	  let horn_head = 
838
	    Z3.Expr.mk_app
839
	      !ctx
840
	      (get_fdecl (machine_stateless_name m.mname.node_id))
841
	      (	List.map (horn_var_to_expr) (idx::uid:: (* Additional vars: counters, uid *) vars))
842
	  in
843
	  (* this line seems useless *)
844
	  let vars = idx::uid::vars@(rename_machine_list m.mname.node_id m.mstep.step_locals) in
845
	  (* Format.eprintf "useless Vars: %a@." (Utils.fprintf_list ~sep:"@ " Printers.pp_var) vars; *)
846
	  match m.mstep.step_asserts with
847
	  | [] ->
848
	     begin
849
	       (* Rule for single predicate : "; Stateless step rule @." *)
850
	       (*let vars = rename_machine_list m.mname.node_id m.mstep.step_locals in*)
851
	       (* TODO clean code *)
852
	       (* Format.eprintf "used Vars: %a@." (Utils.fprintf_list ~sep:"@ " Printers.pp_var) vars; *)
853
	       add_rule vars (Z3.Boolean.mk_implies !ctx horn_body horn_head)
854
		 
855
	     end
856
	  | assertsl ->
857
	     begin
858
	       (*Rule for step "; Stateless step rule with Assertions @.";*)
859
	       let body_with_asserts =
860
		 Z3.Boolean.mk_and !ctx (horn_body :: List.map (horn_val_to_expr m m.mname.node_id) assertsl)
861
	       in
862
	       let vars = rename_machine_list m.mname.node_id m.mstep.step_locals in
863
	       add_rule vars (Z3.Boolean.mk_implies !ctx body_with_asserts horn_head)
864
	     end
865
	end
866
      else
867
	begin
868

    
869
	  (* Rule for reset *)
870

    
871
	  let vars = reset_vars machines m in
872
	  let vars_types = List.map (fun v -> type_to_sort v.var_type) vars in
873
	  let _ = decl_rel (machine_reset_name m.mname.node_id) vars_types in
874
	  let horn_reset_body = machine_reset machines m in	    
875
	  let horn_reset_head = 
876
	    Z3.Expr.mk_app
877
	      !ctx
878
	      (get_fdecl (machine_reset_name m.mname.node_id))
879
	      (	List.map (horn_var_to_expr) (idx::uid:: (* Additional vars: counters, uid *) vars))
880
	  in
881

    
882
	  
883
	  let _ =
884
	    add_rule (idx::uid::vars) (Z3.Boolean.mk_implies !ctx horn_reset_body horn_reset_head)
885
	      
886
	  in
887

    
888
	  (* Rule for step*)
889
	  let vars = step_vars machines m in
890
  	  let vars_types = List.map (fun v -> type_to_sort v.var_type) vars in
891
          let _ = decl_rel (machine_step_name m.mname.node_id) vars_types in
892
	  let horn_step_body, _ (* don't care for reset here *) =
893
	    instrs_to_expr
894
	      machines
895
	      []
896
	      m
897
	      m.mstep.step_instrs
898
	  in
899
	  let horn_step_head = 
900
	    Z3.Expr.mk_app
901
	      !ctx
902
	      (get_fdecl (machine_step_name m.mname.node_id))
903
	      (	List.map (horn_var_to_expr) (idx::uid:: (* Additional vars: counters, uid *) vars))
904
	  in
905
	  match m.mstep.step_asserts with
906
	  | [] ->
907
	     begin
908
	       (* Rule for single predicate *) 
909
	       let vars = (step_vars_c_m_x machines m) @(rename_machine_list m.mname.node_id m.mstep.step_locals) in
910
	       add_rule (idx::uid::vars) (Z3.Boolean.mk_implies !ctx horn_step_body horn_step_head)
911
		 
912
	     end
913
	  | assertsl ->
914
	     begin
915
	       (* Rule for step Assertions @.; *)
916
	       let body_with_asserts =
917
		 Z3.Boolean.mk_and !ctx
918
		   (horn_step_body :: List.map (horn_val_to_expr m m.mname.node_id) assertsl)
919
	       in
920
	       let vars = (step_vars_c_m_x machines m) @(rename_machine_list m.mname.node_id m.mstep.step_locals) in
921
	       add_rule (idx::uid::vars) (Z3.Boolean.mk_implies !ctx body_with_asserts horn_step_head)
922
		 
923
	     end
924
     	       
925
	end
926
    end
927

    
928

    
929

    
930
(* Debug functions *)
931
(*
932
let rec extract_expr_fds e =
933
  (* Format.eprintf "@[<v 2>Extracting fundecls from expr %s@ " *)
934
  (*   (Z3.Expr.to_string e); *)
935
  
936
  (* Removing quantifier is there are some *)
937
  let e = (* I didn't found a nicer way to do it than with an exception.  My
938
	     bad *)
939
    try
940
      let eq = Z3.Quantifier.quantifier_of_expr e in
941
      let e2 = Z3.Quantifier.get_body eq in
942
      (* Format.eprintf "Extracted quantifier body@ "; *)
943
      e2
944
	
945
    with _ -> Format.eprintf "No quantifier info@ "; e
946
  in
947
  let _ =
948
    try 
949
    (
950
      let fd = Z3.Expr.get_func_decl e in
951
      let fd_symbol = Z3.FuncDecl.get_name fd in
952
      let fd_name = Z3.Symbol.to_string fd_symbol in
953
      if not (Hashtbl.mem decls fd_name) then
954
	register_fdecl fd_name fd;
955
      (* Format.eprintf "fdecls (%s): %s@ " *)
956
      (* 	fd_name *)
957
      (* 	(Z3.FuncDecl.to_string fd); *)
958
      try
959
	(
960
	  let args = Z3.Expr.get_args e in
961
	  (* Format.eprintf "@[<v>@ "; *)
962
	  (* List.iter extract_expr_fds args; *)
963
	  (* Format.eprintf "@]@ "; *)
964
	  ()
965
	)
966
      with _ ->
967
	Format.eprintf "Impossible to extract fundecl args for expression %s@ "
968
	  (Z3.Expr.to_string e)
969
    )
970
  with _ ->
971
    Format.eprintf "Impossible to extract anything from expression %s@ "
972
      (Z3.Expr.to_string e)
973
  in
974
  (* Format.eprintf "@]@ " *)
975
  ()      
976
 *)
977
(* Local Variables: *)
978
(* compile-command:"make -C ../.." *)
979
(* End: *)
(3-3/6)