Project

General

Profile

Download (32.3 KB) Statistics
| Branch: | Tag: | Revision:
1
(********************************************************************)
2
(*                                                                  *)
3
(*  The LustreC compiler toolset   /  The LustreC Development Team  *)
4
(*  Copyright 2012 -    --   ONERA - CNRS - INPT                    *)
5
(*                                                                  *)
6
(*  LustreC is free software, distributed WITHOUT ANY WARRANTY      *)
7
(*  under the terms of the GNU Lesser General Public License        *)
8
(*  version 2.1.                                                    *)
9
(*                                                                  *)
10
(********************************************************************)
11

    
12
open Utils
13
open Lustre_types
14
open Corelang
15
open Format
16

    
17
(* To update thank to some command line options *)
18
let debug = ref false
19
          
20
(** Normalisation iters through the AST of expressions and bind fresh definition
21
    when some criteria are met. This creation of fresh definition is performed by
22
    the function mk_expr_alias_opt when the alias argument is on.
23

    
24
    Initial expressions, ie expressions attached a variable in an equation
25
    definition are not aliased. This non-alias feature is propagated in the
26
    expression AST for array access and power construct, tuple, and some special
27
    cases of arrows.
28

    
29
    Two global variables may impact the normalization process:
30
    - unfold_arrow_active
31
    - force_alias_ite: when set, bind a fresh alias for then and else
32
      definitions.
33
*)
34

    
35
type param_t =
36
  {
37
    unfold_arrow_active: bool;
38
    force_alias_ite: bool;
39
    force_alias_internal_fun: bool;
40
  }
41

    
42
let params = ref
43
               {
44
                 unfold_arrow_active = false;
45
                 force_alias_ite = false;
46
                 force_alias_internal_fun =false;
47
               }
48

    
49
type norm_ctx_t =
50
  {
51
    parentid: ident;
52
    vars: var_decl list;
53
    is_output: ident -> bool; 
54
  }
55

    
56
           
57
let expr_true loc ck =
58
{ expr_tag = Utils.new_tag ();
59
  expr_desc = Expr_const (Const_tag tag_true);
60
  expr_type = Type_predef.type_bool;
61
  expr_clock = ck;
62
  expr_delay = Delay.new_var ();
63
  expr_annot = None;
64
  expr_loc = loc }
65

    
66
let expr_false loc ck =
67
{ expr_tag = Utils.new_tag ();
68
  expr_desc = Expr_const (Const_tag tag_false);
69
  expr_type = Type_predef.type_bool;
70
  expr_clock = ck;
71
  expr_delay = Delay.new_var ();
72
  expr_annot = None;
73
  expr_loc = loc }
74

    
75
let expr_once loc ck =
76
 { expr_tag = Utils.new_tag ();
77
  expr_desc = Expr_arrow (expr_true loc ck, expr_false loc ck);
78
  expr_type = Type_predef.type_bool;
79
  expr_clock = ck;
80
  expr_delay = Delay.new_var ();
81
  expr_annot = None;
82
  expr_loc = loc }
83

    
84
let is_expr_once =
85
  let dummy_expr_once = expr_once Location.dummy_loc (Clocks.new_var true) in
86
  fun expr -> Corelang.is_eq_expr expr dummy_expr_once
87

    
88
let unfold_arrow expr =
89
 match expr.expr_desc with
90
 | Expr_arrow (e1, e2) ->
91
    let loc = expr.expr_loc in
92
    let ck = List.hd (Clocks.clock_list_of_clock expr.expr_clock) in
93
    { expr with expr_desc = Expr_ite (expr_once loc ck, e1, e2) }
94
 | _                   -> assert false
95

    
96

    
97

    
98
(* Get the equation in [defs] with [expr] as rhs, if any *)
99
let get_expr_alias defs expr =
100
 try Some (List.find (fun eq -> Clocks.eq_clock expr.expr_clock eq.eq_rhs.expr_clock && is_eq_expr eq.eq_rhs expr) defs)
101
 with
102
 | Not_found -> None
103
  
104
(* Replace [expr] with (tuple of) [locals] *)
105
let replace_expr locals expr =
106
 match locals with
107
 | []  -> assert false
108
 | [v] -> { expr with
109
   expr_tag = Utils.new_tag ();
110
   expr_desc = Expr_ident v.var_id }
111
 | _   -> { expr with
112
   expr_tag = Utils.new_tag ();
113
   expr_desc = Expr_tuple (List.map expr_of_vdecl locals) }
114

    
115
let unfold_offsets e offsets =
116
  let add_offset e d =
117
(*Format.eprintf "add_offset %a(%a) %a @." Printers.pp_expr e Types.print_ty e.expr_type Dimension.pp_dimension d;
118
    let res = *)
119
    { e with
120
      expr_tag = Utils.new_tag ();
121
      expr_loc = d.Dimension.dim_loc;
122
      expr_type = Types.array_element_type e.expr_type;
123
      expr_desc = Expr_access (e, d) }
124
(*in (Format.eprintf "= %a @." Printers.pp_expr res; res) *)
125
  in
126
 List.fold_left add_offset e offsets
127

    
128
(* IS IT USED ? TODO 
129
(* Create an alias for [expr], if none exists yet *)
130
let mk_expr_alias (parentid, vars) (defs, vars) expr =
131
(*Format.eprintf "mk_expr_alias %a %a %a@." Printers.pp_expr expr Types.print_ty expr.expr_type Clocks.print_ck expr.expr_clock;*)
132
  match get_expr_alias defs expr with
133
  | Some eq ->
134
    let aliases = List.map (fun id -> List.find (fun v -> v.var_id = id) vars) eq.eq_lhs in
135
    (defs, vars), replace_expr aliases expr
136
  | None    ->
137
    let new_aliases =
138
      List.map2
139
	(mk_fresh_var (parentid, vars) expr.expr_loc)
140
	(Types.type_list_of_type expr.expr_type)
141
	(Clocks.clock_list_of_clock expr.expr_clock) in
142
    let new_def =
143
      mkeq expr.expr_loc (List.map (fun v -> v.var_id) new_aliases, expr)
144
    in
145
    (* Format.eprintf "Checking def of alias: %a -> %a@." (fprintf_list ~sep:", " (fun fmt v -> Format.pp_print_string fmt v.var_id)) new_aliases Printers.pp_expr expr; *)
146
    (new_def::defs, new_aliases@vars), replace_expr new_aliases expr
147
 *)
148
  
149
(* Create an alias for [expr], if [expr] is not already an alias (i.e. an ident)
150
   and [opt] is true *)
151
let mk_expr_alias_opt opt norm_ctx (defs, vars) expr =
152
  if !debug then
153
    Log.report ~plugin:"normalization" ~level:2
154
      (fun fmt -> Format.fprintf  fmt "mk_expr_alias_opt %B %a %a %a@." opt Printers.pp_expr expr Types.print_ty expr.expr_type Clocks.print_ck expr.expr_clock);
155
  match expr.expr_desc with
156
  | Expr_ident alias ->
157
    (defs, vars), expr
158
  | _                ->
159
    match get_expr_alias defs expr with
160
    | Some eq ->
161
       (* Format.eprintf "Found a preexisting definition@."; *)
162
      let aliases = List.map (fun id -> List.find (fun v -> v.var_id = id) vars) eq.eq_lhs in
163
      (defs, vars), replace_expr aliases expr
164
    | None    ->
165
       (* Format.eprintf "Didnt found a preexisting definition (opt=%b)@." opt;
166
        * Format.eprintf "existing defs are: @[[%a@]]@."
167
        *   (fprintf_list ~sep:"@ "(fun fmt eq ->
168
        *        Format.fprintf fmt "ck:%a isckeq=%b, , iseq=%b, eq=%a"
169
        *          Clocks.print_ck eq.eq_rhs.expr_clock
170
        *          (Clocks.eq_clock expr.expr_clock eq.eq_rhs.expr_clock)
171
        *          (is_eq_expr eq.eq_rhs expr)
172
        *          Printers.pp_node_eq eq))
173
        *   defs; *)
174
      if opt
175
      then
176
	let new_aliases =
177
	  List.map2
178
	    (mk_fresh_var (norm_ctx.parentid, (norm_ctx.vars@vars)) expr.expr_loc)
179
	    (Types.type_list_of_type expr.expr_type)
180
	    (Clocks.clock_list_of_clock expr.expr_clock) in
181
	let new_def =
182
	  mkeq expr.expr_loc (List.map (fun v -> v.var_id) new_aliases, expr)
183
	in
184
	(* Typing and Registering machine type *) 
185
	let _ = if Machine_types.is_active then
186
                  Machine_types.type_def (norm_ctx.parentid, norm_ctx.vars) new_aliases expr
187
        in
188
	(new_def::defs, new_aliases@vars), replace_expr new_aliases expr
189
      else
190
	(defs, vars), expr
191

    
192
(* Create a (normalized) expression from [ref_e],
193
   replacing description with [norm_d],
194
   taking propagated [offsets] into account
195
   in order to change expression type *)
196
let mk_norm_expr offsets ref_e norm_d =
197
  (*Format.eprintf "mk_norm_expr %a %a @." Printers.pp_expr ref_e Printers.pp_expr { ref_e with expr_desc = norm_d};*)
198
  let drop_array_type ty =
199
    Types.map_tuple_type Types.array_element_type ty in
200
  { ref_e with
201
    expr_desc = norm_d;
202
    expr_type = Utils.repeat (List.length offsets) drop_array_type ref_e.expr_type }
203
														
204
(* normalize_<foo> : defs * used vars -> <foo> -> (updated defs * updated vars) * normalized <foo> *)
205
let rec normalize_list alias norm_ctx offsets norm_element defvars elist =
206
  List.fold_right
207
    (fun t (defvars, qlist) ->
208
      let defvars, norm_t = norm_element alias norm_ctx offsets defvars t in
209
      (defvars, norm_t :: qlist)
210
    ) elist (defvars, [])
211

    
212
let rec normalize_expr ?(alias=true) ?(alias_basic=false) norm_ctx offsets defvars expr =
213
  (*Format.eprintf "normalize %B %a:%a [%a]@." alias Printers.pp_expr expr Types.print_ty expr.expr_type (Utils.fprintf_list ~sep:"," Dimension.pp_dimension) offsets;*)
214
  match expr.expr_desc with
215
  | Expr_const _
216
  | Expr_ident _ -> defvars, unfold_offsets expr offsets
217
  | Expr_array elist ->
218
     let defvars, norm_elist = normalize_list alias norm_ctx offsets (fun _ -> normalize_array_expr ~alias:true) defvars elist in
219
     let norm_expr = mk_norm_expr offsets expr (Expr_array norm_elist) in
220
     mk_expr_alias_opt alias norm_ctx defvars norm_expr
221
  | Expr_power (e1, d) when offsets = [] ->
222
     let defvars, norm_e1 = normalize_expr norm_ctx offsets defvars e1 in
223
     let norm_expr = mk_norm_expr offsets expr (Expr_power (norm_e1, d)) in
224
     mk_expr_alias_opt alias norm_ctx defvars norm_expr
225
  | Expr_power (e1, d) ->
226
     normalize_expr ~alias:alias norm_ctx (List.tl offsets) defvars e1
227
  | Expr_access (e1, d) ->
228
     normalize_expr ~alias:alias norm_ctx (d::offsets) defvars e1
229
  | Expr_tuple elist ->
230
     let defvars, norm_elist =
231
       normalize_list alias norm_ctx offsets (fun alias -> normalize_expr ~alias:alias ~alias_basic:false) defvars elist in
232
     defvars, mk_norm_expr offsets expr (Expr_tuple norm_elist)
233
  | Expr_appl (id, args, None)
234
      when Basic_library.is_homomorphic_fun id 
235
	&& Types.is_array_type expr.expr_type ->
236
     let defvars, norm_args =
237
       normalize_list
238
	 alias
239
	 norm_ctx
240
	 offsets
241
	 (fun _ -> normalize_array_expr ~alias:true)
242
	 defvars
243
	 (expr_list_of_expr args)
244
     in
245
     defvars, mk_norm_expr offsets expr (Expr_appl (id, expr_of_expr_list args.expr_loc norm_args, None))
246
  | Expr_appl (id, args, None) when Basic_library.is_expr_internal_fun expr
247
      && not (!params.force_alias_internal_fun || alias_basic) ->
248
     let defvars, norm_args = normalize_expr ~alias:true norm_ctx offsets defvars args in
249
     defvars, mk_norm_expr offsets expr (Expr_appl (id, norm_args, None))
250
  | Expr_appl (id, args, r) ->
251
     let defvars, r =
252
       match r with
253
       | None -> defvars, None
254
       | Some r ->
255
	  let defvars, norm_r = normalize_expr ~alias_basic:true norm_ctx [] defvars r in
256
	  defvars, Some norm_r
257
     in
258
     let defvars, norm_args = normalize_expr norm_ctx [] defvars args in
259
     let norm_expr = mk_norm_expr [] expr (Expr_appl (id, norm_args, r)) in
260
     if offsets <> []
261
     then
262
       let defvars, norm_expr = normalize_expr norm_ctx [] defvars norm_expr in
263
       normalize_expr ~alias:alias norm_ctx offsets defvars norm_expr
264
     else
265
       mk_expr_alias_opt (alias && (!params.force_alias_internal_fun || alias_basic
266
				    || not (Basic_library.is_expr_internal_fun expr)))
267
	 norm_ctx defvars norm_expr
268
  | Expr_arrow (e1,e2) when !params.unfold_arrow_active && not (is_expr_once expr) ->
269
     (* Here we differ from Colaco paper: arrows are pushed to the top *)
270
     normalize_expr ~alias:alias norm_ctx offsets defvars (unfold_arrow expr)
271
  | Expr_arrow (e1,e2) ->
272
     let defvars, norm_e1 = normalize_expr norm_ctx offsets defvars e1 in
273
     let defvars, norm_e2 = normalize_expr norm_ctx offsets defvars e2 in
274
     let norm_expr = mk_norm_expr offsets expr (Expr_arrow (norm_e1, norm_e2)) in
275
     mk_expr_alias_opt alias norm_ctx defvars norm_expr
276
  | Expr_pre e ->
277
     let defvars, norm_e = normalize_expr norm_ctx offsets defvars e in
278
     let norm_expr = mk_norm_expr offsets expr (Expr_pre norm_e) in
279
     mk_expr_alias_opt alias norm_ctx defvars norm_expr
280
  | Expr_fby (e1, e2) ->
281
     let defvars, norm_e1 = normalize_expr norm_ctx offsets defvars e1 in
282
     let defvars, norm_e2 = normalize_expr norm_ctx offsets defvars e2 in
283
     let norm_expr = mk_norm_expr offsets expr (Expr_fby (norm_e1, norm_e2)) in
284
     mk_expr_alias_opt alias norm_ctx defvars norm_expr
285
  | Expr_when (e, c, l) ->
286
     let defvars, norm_e = normalize_expr norm_ctx offsets defvars e in
287
     defvars, mk_norm_expr offsets expr (Expr_when (norm_e, c, l))
288
  | Expr_ite (c, t, e) ->
289
     let defvars, norm_c = normalize_guard norm_ctx defvars c in
290
     let defvars, norm_t = normalize_cond_expr  norm_ctx offsets defvars t in
291
     let defvars, norm_e = normalize_cond_expr  norm_ctx offsets defvars e in
292
     let norm_expr = mk_norm_expr offsets expr (Expr_ite (norm_c, norm_t, norm_e)) in
293
     mk_expr_alias_opt alias norm_ctx defvars norm_expr
294
  | Expr_merge (c, hl) ->
295
     let defvars, norm_hl = normalize_branches norm_ctx offsets defvars hl in
296
     let norm_expr = mk_norm_expr offsets expr (Expr_merge (c, norm_hl)) in
297
     mk_expr_alias_opt alias norm_ctx defvars norm_expr
298

    
299
(* Creates a conditional with a merge construct, which is more lazy *)
300
(*
301
  let norm_conditional_as_merge alias node norm_expr offsets defvars expr =
302
  match expr.expr_desc with
303
  | Expr_ite (c, t, e) ->
304
  let defvars, norm_t = norm_expr (alias node offsets defvars t in
305
  | _ -> assert false
306
*)
307
and normalize_branches norm_ctx offsets defvars hl =
308
  List.fold_right
309
    (fun (t, h) (defvars, norm_q) ->
310
      let (defvars, norm_h) = normalize_cond_expr norm_ctx offsets defvars h in
311
      defvars, (t, norm_h) :: norm_q
312
    )
313
    hl (defvars, [])
314

    
315
and normalize_array_expr ?(alias=true) norm_ctx offsets defvars expr =
316
  (*Format.eprintf "normalize_array %B %a [%a]@." alias Printers.pp_expr expr (Utils.fprintf_list ~sep:"," Dimension.pp_dimension) offsets;*)
317
  match expr.expr_desc with
318
  | Expr_power (e1, d) when offsets = [] ->
319
     let defvars, norm_e1 = normalize_expr norm_ctx offsets defvars e1 in
320
     defvars, mk_norm_expr offsets expr (Expr_power (norm_e1, d))
321
  | Expr_power (e1, d) ->
322
     normalize_array_expr ~alias:alias norm_ctx (List.tl offsets) defvars e1
323
  | Expr_access (e1, d) -> normalize_array_expr ~alias:alias norm_ctx (d::offsets) defvars e1
324
  | Expr_array elist when offsets = [] ->
325
     let defvars, norm_elist = normalize_list alias norm_ctx offsets (fun _ -> normalize_array_expr ~alias:true) defvars elist in
326
     defvars, mk_norm_expr offsets expr (Expr_array norm_elist)
327
  | Expr_appl (id, args, None) when Basic_library.is_expr_internal_fun expr ->
328
     let defvars, norm_args = normalize_list alias norm_ctx offsets (fun _ -> normalize_array_expr ~alias:true) defvars (expr_list_of_expr args) in
329
     defvars, mk_norm_expr offsets expr (Expr_appl (id, expr_of_expr_list args.expr_loc norm_args, None))
330
  |  _ -> normalize_expr ~alias:alias norm_ctx offsets defvars expr
331

    
332
and normalize_cond_expr ?(alias=true) norm_ctx offsets defvars expr =
333
  (*Format.eprintf "normalize_cond %B %a [%a]@." alias Printers.pp_expr expr (Utils.fprintf_list ~sep:"," Dimension.pp_dimension) offsets;*)
334
  match expr.expr_desc with
335
  | Expr_access (e1, d) ->
336
     normalize_cond_expr ~alias:alias norm_ctx (d::offsets) defvars e1
337
  | Expr_ite (c, t, e) ->
338
     let defvars, norm_c = normalize_guard norm_ctx defvars c in
339
     let defvars, norm_t = normalize_cond_expr norm_ctx offsets defvars t in
340
     let defvars, norm_e = normalize_cond_expr norm_ctx offsets defvars e in
341
     defvars, mk_norm_expr offsets expr (Expr_ite (norm_c, norm_t, norm_e))
342
  | Expr_merge (c, hl) ->
343
     let defvars, norm_hl = normalize_branches norm_ctx offsets defvars hl in
344
     defvars, mk_norm_expr offsets expr (Expr_merge (c, norm_hl))
345
  | _ when !params.force_alias_ite ->
346
     (* Forcing alias creation for then/else expressions *)
347
     let defvars, norm_expr =
348
       normalize_expr ~alias:alias norm_ctx offsets defvars expr
349
     in
350
     mk_expr_alias_opt true norm_ctx defvars norm_expr
351
  | _ -> (* default case without the force_alias_ite option *)
352
     normalize_expr ~alias:alias norm_ctx offsets defvars expr
353
       
354
and normalize_guard norm_ctx defvars expr =
355
  let defvars, norm_expr = normalize_expr ~alias_basic:true norm_ctx [] defvars expr in
356
  mk_expr_alias_opt true norm_ctx defvars norm_expr
357

    
358
(* outputs cannot be memories as well. If so, introduce new local variable.
359
*)
360
let decouple_outputs norm_ctx defvars eq =
361
  let rec fold_lhs defvars lhs tys cks =
362
    match lhs, tys, cks with
363
    | [], [], []          -> defvars, []
364
    | v::qv, t::qt, c::qc -> let (defs_q, vars_q), lhs_q = fold_lhs defvars qv qt qc in
365
			     if norm_ctx.is_output v
366
			     then
367
			       let newvar = mk_fresh_var (norm_ctx.parentid, norm_ctx.vars) eq.eq_loc t c in
368
			       let neweq  = mkeq eq.eq_loc ([v], expr_of_vdecl newvar) in
369
			       (neweq :: defs_q, newvar :: vars_q), newvar.var_id :: lhs_q
370
			     else
371
			       (defs_q, vars_q), v::lhs_q
372
    | _                   -> assert false in
373
  let defvars', lhs' =
374
    fold_lhs
375
      defvars
376
      eq.eq_lhs
377
      (Types.type_list_of_type eq.eq_rhs.expr_type)
378
      (Clocks.clock_list_of_clock eq.eq_rhs.expr_clock) in
379
  defvars', {eq with eq_lhs = lhs' }
380

    
381
let rec normalize_eq norm_ctx defvars eq =
382
(*Format.eprintf "normalize_eq %a@." Types.print_ty eq.eq_rhs.expr_type;*)
383
  match eq.eq_rhs.expr_desc with
384
  | Expr_pre _
385
  | Expr_fby _  ->
386
    let (defvars', eq') = decouple_outputs norm_ctx defvars eq in
387
    let (defs', vars'), norm_rhs = normalize_expr ~alias:false norm_ctx [] defvars' eq'.eq_rhs in
388
    let norm_eq = { eq' with eq_rhs = norm_rhs } in
389
    (norm_eq::defs', vars')
390
  | Expr_array _ ->
391
    let (defs', vars'), norm_rhs = normalize_array_expr ~alias:false norm_ctx [] defvars eq.eq_rhs in
392
    let norm_eq = { eq with eq_rhs = norm_rhs } in
393
    (norm_eq::defs', vars')
394
  | Expr_appl (id, _, None) when Basic_library.is_homomorphic_fun id && Types.is_array_type eq.eq_rhs.expr_type ->
395
    let (defs', vars'), norm_rhs = normalize_array_expr ~alias:false norm_ctx [] defvars eq.eq_rhs in
396
    let norm_eq = { eq with eq_rhs = norm_rhs } in
397
    (norm_eq::defs', vars')
398
  | Expr_appl _ ->
399
    let (defs', vars'), norm_rhs = normalize_expr ~alias:false norm_ctx [] defvars eq.eq_rhs in
400
    let norm_eq = { eq with eq_rhs = norm_rhs } in
401
    (norm_eq::defs', vars')
402
  | _ ->
403
    let (defs', vars'), norm_rhs = normalize_cond_expr ~alias:false norm_ctx [] defvars eq.eq_rhs in
404
    let norm_eq = { eq with eq_rhs = norm_rhs } in
405
    norm_eq::defs', vars'
406

    
407
let normalize_eq_split norm_ctx defvars eq =
408
  try
409
    let defs, vars = normalize_eq norm_ctx defvars eq in
410
    List.fold_right (fun eq (def, vars) -> 
411
        let eq_defs = Splitting.tuple_split_eq eq in
412
        if eq_defs = [eq] then
413
          eq::def, vars 
414
        else
415
          List.fold_left (normalize_eq norm_ctx) (def, vars) eq_defs
416
      ) defs ([], vars)  
417
    
418
  with ex -> (
419
    Format.eprintf "Issue normalizing eq split: %a@." Printers.pp_node_eq eq;
420
    raise ex
421
  )
422

    
423
(* Projecting an eexpr to an eexpr associated to a single
424
   variable. Returns the updated ee, the bounded variable and the
425
   associated statement *)
426
let normalize_pred_eexpr decls norm_ctx (def,vars) ee =
427
  assert (ee.eexpr_quantifiers = []); (* We do not normalize quantifiers yet. This is for very far future. *)
428
  (* don't do anything is eexpr is just a variable *)
429
  let skip =
430
    match ee.eexpr_qfexpr.expr_desc with
431
    | Expr_ident _ | Expr_const _ -> true
432
    | _ -> false
433
  in
434
  if skip then
435
    ee, (def, vars)
436
  else (
437
    (* New output variable *)
438
    let output_id = "spec" ^ string_of_int ee.eexpr_tag in
439
    let output_var = 
440
      mkvar_decl 
441
        ee.eexpr_loc 
442
        (output_id, 
443
         mktyp ee.eexpr_loc Tydec_bool, (* It is a predicate, hence a bool *)
444
         mkclock ee.eexpr_loc Ckdec_any, 
445
         false (* not a constant *),
446
         None,
447
         None
448
        ) 
449
    in
450
    let output_expr = expr_of_vdecl output_var in
451
    (* Rebuilding an eexpr with a silly expression, just a variable *)
452
    let ee' = { ee with eexpr_qfexpr = output_expr } in
453

    
454
    (* Now processing a fresh equation output_id = eexpr_qfexpr. We
455
       inline possible calls within, normalize it and type/clock the
456
       result.  *)
457
    let eq = mkeq ee.eexpr_loc ([output_id], ee.eexpr_qfexpr) in
458

    
459

    
460
    (* (\* Inlining any calls *\)
461
     * let nodes = get_nodes decls in
462
     * let calls = ISet.elements (get_expr_calls nodes ee.eexpr_qfexpr) in
463
     * let vars, eqs =
464
     *   if calls = [] && not (eq_has_arrows eq) then
465
     *     vars, [eq]    
466
     *   else
467
     *     assert false (\* TODO *\)
468
     * in *)
469
    
470
    (* Normalizing expr and eqs *)
471
    let defs, vars = List.fold_left (normalize_eq_split norm_ctx) (def, vars) [eq] in
472
    let vars = output_var :: vars in 
473
(*    let todefine =
474
      List.fold_left
475
        (fun m x-> if List.exists (fun y-> x.var_id = y.var_id) (locals) then m else ISet.add x.var_id m)
476
        (ISet.add output_id ISet.empty) vars in
477
 *)      
478

    
479
    (* Typing / Clocking *)
480
    try
481
      ignore (Typing.type_var_decl_list vars !Global.type_env vars);
482
        (*
483
    let env = Typing.type_var_decl [] !Global.type_env xxxx output_var in (* typing the variable *)
484
    (* Format.eprintf "typing var %s: %a@." output_id Types.print_ty output_var.var_type; *)
485
    let env = Typing.type_var_decl_list (vars@node.node_outputs@node.node_inputs) env (vars@node.node_outputs@node.node_inputs) in
486
    (*Format.eprintf "Env: %a@.@?" (Env.pp_env Types.print_ty) env;*)
487
    let undefined_vars = List.fold_left (Typing.type_eq (env, quant_vars@vars) false) todefine defs in
488
  (* check that table is empty *)
489
    if (not (ISet.is_empty undefined_vars)) then
490
      raise (Types.Error (ee.eexpr_loc, Types.Undefined_var undefined_vars));
491
    
492
    (*Format.eprintf "normalized eqs %a@.@?" 
493
      (Utils.fprintf_list ~sep:", " Printers.pp_node_eq) defs;  *)
494
         *)
495

    
496
    ee', (defs, vars)
497
    
498
  with (Types.Error (loc,err)) as exc ->
499
    eprintf "Typing error for eexpr %a: %a%a%a@."
500
      Printers.pp_eexpr ee
501
      Types.pp_error err
502
      (Utils.fprintf_list ~sep:", " Printers.pp_node_eq) defs
503
      Location.pp_loc loc
504
  
505
      
506
    ;
507
    raise exc
508
                                     
509
  )
510
    
511
   (*
512
  
513
  let quant_vars = List.flatten (List.map snd ee.eexpr_quantifiers) in
514
  (* Calls are first inlined *)
515
  
516
  (*Format.eprintf "eexpr %a@.calls: %a@.@?" Printers.pp_eexpr ee (Utils.fprintf_list ~sep:", " (fun fmt nd -> pp_print_string fmt nd.node_id)) calls;  *)
517
  let (new_locals, eqs) =
518
    if calls = [] && not (eq_has_arrows eq) then
519
      (locals, [eq])     
520
    else ( (* TODO remettre le code. Je l'ai enleve pour des dependances cycliques *)
521
(*      let new_locals, eqs, asserts = Inliner.inline_eq ~arrows:true eq locals calls in
522
      (*Format.eprintf "eqs %a@.@?" 
523
	(Utils.fprintf_list ~sep:", " Printers.pp_node_eq) eqs;  *)
524
      (new_locals, eqs)
525
*)
526
           (locals, [eq])     
527
 
528
    ) in
529
  (* Normalizing expr and eqs *)
530
    let defs, vars = List.fold_left (normalize_eq_split node) ([], new_locals) eqs in
531
    let todefine = List.fold_left
532
    (fun m x-> if List.exists (fun y-> x.var_id = y.var_id) (locals) then m else ISet.add x.var_id m)
533
    (ISet.add output_id ISet.empty) vars in
534
  
535
  try
536
    let env = Typing.type_var_decl_list quant_vars !Global.type_env quant_vars in
537
    let env = Typing.type_var_decl [] env output_var in (* typing the variable *)
538
    (* Format.eprintf "typing var %s: %a@." output_id Types.print_ty output_var.var_type; *)
539
    let env = Typing.type_var_decl_list (vars@node.node_outputs@node.node_inputs) env (vars@node.node_outputs@node.node_inputs) in
540
    (*Format.eprintf "Env: %a@.@?" (Env.pp_env Types.print_ty) env;*)
541
    let undefined_vars = List.fold_left (Typing.type_eq (env, quant_vars@vars) false) todefine defs in
542
  (* check that table is empty *)
543
    if (not (ISet.is_empty undefined_vars)) then
544
      raise (Types.Error (ee.eexpr_loc, Types.Undefined_var undefined_vars));
545
    
546
    (*Format.eprintf "normalized eqs %a@.@?" 
547
      (Utils.fprintf_list ~sep:", " Printers.pp_node_eq) defs;  *)
548
    ee.eexpr_normalized <- Some (output_var, defs, vars)
549
    
550
  with (Types.Error (loc,err)) as exc ->
551
    eprintf "Typing error for eexpr %a: %a%a%a@."
552
      Printers.pp_eexpr ee
553
      Types.pp_error err
554
      (Utils.fprintf_list ~sep:", " Printers.pp_node_eq) defs
555
      Location.pp_loc loc
556
  
557
      
558
    ;
559
    raise exc
560
                                                 *)    
561
 
562

    
563
(* We use node local vars to make sure we are creating fresh variables *) 
564
let normalize_spec decls parentid (in_vars, out_vars, l_vars) s =  
565
  (* Original set of variables actually visible from here: in/out and
566
     spec locals (no node locals) *)
567
  let orig_vars = in_vars @ out_vars @ s.locals in
568
  (* Format.eprintf "NormSpec: init locals: %a@." Printers.pp_vars s.locals; *)
569
  let not_is_orig_var v =
570
    List.for_all ((!=) v) orig_vars in
571
  let norm_ctx = {
572
      parentid = parentid;
573
      vars = in_vars @ out_vars @ l_vars;
574
      is_output = (fun _ -> false) (* no need to introduce fresh variables for outputs *);
575
    }
576
  in
577
  (* Normalizing existing stmts *)
578
  let eqs, auts = List.fold_right (fun s (el,al)  -> match s with Eq e -> e::el, al | Aut a -> el, a::al) s.stmts ([], []) in
579
  if auts != [] then assert false; (* Automata should be expanded by now. *)
580
  let defsvars = 
581
    List.fold_left (normalize_eq norm_ctx) ([], orig_vars) eqs
582
  in
583
  (* Iterate through predicates and normalize them on the go, creating
584
     fresh variables for any guarantees/assumes/require/ensure *)
585
  let process_predicates l defvars =
586
    (* Format.eprintf "ProcPred: vars: %a@." Printers.pp_vars (snd defvars); *)
587
    let res = List.fold_right (fun ee (accu, defvars) ->
588
        let ee', defvars = normalize_pred_eexpr decls norm_ctx defvars ee in
589
        ee'::accu, defvars
590
      ) l ([], defvars)
591
    in
592
    (* Format.eprintf "ProcStmt: %a@." Printers.pp_node_eqs (fst (snd res));
593
     * Format.eprintf "ProcPred: vars: %a@." Printers.pp_vars (snd (snd res)); *)
594
    res
595
  in
596

    
597
  
598
  let assume', defsvars = process_predicates s.assume defsvars in
599
  let guarantees', defsvars = process_predicates s.guarantees defsvars in
600
  let modes', (defs, vars) =
601
    List.fold_right (
602
        fun m (accu_m, defsvars) ->
603
        let require', defsvars = process_predicates m.require defsvars in
604
        let ensure', defsvars = process_predicates m.ensure defsvars in
605
        { m with require = require'; ensure = ensure' }:: accu_m, defsvars
606
      ) s.modes ([], defsvars)
607
  in
608
  
609
  let new_locals = List.filter not_is_orig_var vars in (* removing inouts and initial locals ones *)
610
  new_locals, defs,      
611
  {s with
612
    (* locals = s.locals @ new_locals; *)
613
    stmts = [];
614
    assume = assume';
615
    guarantees = guarantees';
616
    modes = modes'
617
  }
618
(* let nee _ = () in
619
 *   (\*normalize_eexpr decls iovars in *\)
620
 *   List.iter nee s.assume;
621
 *   List.iter nee s.guarantees;
622
 *   List.iter (fun m -> 
623
 *       List.iter nee m.require;
624
 *     List.iter nee m.ensure
625
 *     ) s.modes; *)
626
   
627

    
628
                                                                     
629
  
630
  
631
    
632
(* The normalization phase introduces new local variables
633
   - output cannot be memories. If this happen, new local variables acting as
634
   memories are introduced. 
635
   - array constants, pre, arrow, fby, ite, merge, calls to node with index
636
   access
637
   Thoses values are shared, ie. no duplicate expressions are introduced.
638

    
639
   Concerning specification, a similar process is applied, replacing an
640
   expression by a list of local variables and definitions
641
*)
642

    
643
(** normalize_node node returns a normalized node, 
644
    ie. 
645
    - updated locals
646
    - new equations
647
    -
648
*)
649
let normalize_node decls node =
650
  reset_cpt_fresh ();
651
  let orig_vars = node.node_inputs@node.node_outputs@node.node_locals in
652
  let not_is_orig_var v =
653
    List.for_all ((!=) v) orig_vars in
654
  let norm_ctx = {
655
      parentid = node.node_id;
656
      vars = get_node_vars node;
657
      is_output = (fun vid -> List.exists (fun v -> v.var_id = vid) node.node_outputs);
658
    }
659
  in
660

    
661
  let eqs, auts = get_node_eqs node in
662
  if auts != [] then assert false; (* Automata should be expanded by now. *)
663
  let spec, new_vars, eqs =
664
    begin
665
      (* Update mutable fields of eexpr to perform normalization of
666
	 specification.
667

    
668
	 Careful: we do not normalize annotations, since they can have the form
669
	 x = (a, b, c) *)
670
      match node.node_spec with
671
      | None 
672
        | Some (NodeSpec _) -> node.node_spec, [], eqs
673
      | Some (Contract s) ->
674
         let new_locals, new_stmts, s' = normalize_spec
675
                    decls
676
                    node.node_id
677
                    (node.node_inputs, node.node_outputs, node.node_locals)
678
                    s
679
         in
680
         (* Format.eprintf "Normalization bounded new locals: %a@." Printers.pp_vars new_locals;
681
          * Format.eprintf "Normalization bounded stmts: %a@." Printers.pp_node_eqs new_stmts; *)
682
         Some (Contract s'), new_locals, new_stmts@eqs
683
    end
684
  in
685
  let defs, vars =
686
    List.fold_left (normalize_eq norm_ctx) ([], new_vars@orig_vars) eqs in
687
  (* Normalize the asserts *)
688
  let vars, assert_defs, asserts =
689
    List.fold_left (
690
        fun (vars, def_accu, assert_accu) assert_ ->
691
	let assert_expr = assert_.assert_expr in
692
	let (defs, vars'), expr = 
693
	  normalize_expr 
694
	    ~alias:true (* forcing introduction of new equations for fcn calls *) 
695
	    norm_ctx 
696
	    [] (* empty offset for arrays *)
697
	    ([], vars) (* defvar only contains vars *)
698
	    assert_expr
699
	in
700
        (*Format.eprintf "New assert vars: %a@.@?" (fprintf_list ~sep:", " Printers.pp_var) vars';*)
701
	vars', defs@def_accu, {assert_ with assert_expr = expr}::assert_accu
702
      ) (vars, [], []) node.node_asserts in
703
  let new_locals = List.filter not_is_orig_var vars in (* we filter out inout
704
							  vars and initial locals ones *)
705
  
706
  let all_locals = node.node_locals @ new_locals in (* we add again, at the
707
						       beginning of the list the
708
						       local declared ones *)
709
  (*Format.eprintf "New locals: %a@.@?" (fprintf_list ~sep:", " Printers.pp_var) new_locals;*)
710

    
711

    
712
  (* Updating annotations: traceability and machine types for fresh variables *)
713
  
714
  (* Compute traceability info:
715
     - gather newly bound variables
716
     - compute the associated expression without aliases
717
   *)
718
  let new_annots =
719
    if !Options.traces then
720
      begin
721
	let diff_vars = List.filter (fun v -> not (List.mem v node.node_locals) ) all_locals in
722
	let norm_traceability = {
723
	    annots = List.map (fun v ->
724
	                 let eq =
725
	                   try
726
		             List.find (fun eq -> List.exists (fun v' -> v' = v.var_id ) eq.eq_lhs) (defs@assert_defs) 
727
	                   with Not_found -> 
728
		             (
729
		               Format.eprintf "Traceability annotation generation: var %s not found@." v.var_id; 
730
		               assert false
731
		             ) 
732
	                 in
733
	                 let expr = substitute_expr diff_vars (defs@assert_defs) eq.eq_rhs in
734
	                 let pair = mkeexpr expr.expr_loc (mkexpr expr.expr_loc (Expr_tuple [expr_of_ident v.var_id expr.expr_loc; expr])) in
735
	                 Annotations.add_expr_ann node.node_id pair.eexpr_tag ["traceability"];
736
	                 (["traceability"], pair)
737
	               ) diff_vars;
738
	    annot_loc = Location.dummy_loc
739
	  }
740
	in
741
	norm_traceability::node.node_annot
742
      end
743
    else
744
      node.node_annot
745
  in
746

    
747
  let new_annots =
748
    List.fold_left (fun annots v ->
749
        if Machine_types.is_active && Machine_types.is_exportable v then
750
	  let typ = Machine_types.get_specified_type v in
751
  	  let typ_name = Machine_types.type_name typ in
752

    
753
	  let loc = v.var_loc in
754
	  let typ_as_string =
755
	    mkexpr
756
	      loc
757
	      (Expr_const
758
	         (Const_string typ_name))
759
	  in
760
	  let pair = expr_to_eexpr (expr_of_expr_list loc [expr_of_vdecl v; typ_as_string]) in
761
	  Annotations.add_expr_ann node.node_id pair.eexpr_tag Machine_types.keyword;
762
	  {annots = [Machine_types.keyword, pair]; annot_loc = loc}::annots
763
        else
764
	  annots
765
      ) new_annots new_locals
766
  in
767
  
768
  
769
  let node =
770
    { node with
771
      node_locals = all_locals;
772
      node_stmts = List.map (fun eq -> Eq eq) (defs @ assert_defs);
773
      node_asserts = asserts;
774
      node_annot = new_annots;
775
      node_spec = spec;
776
    }
777
  in ((*Printers.pp_node Format.err_formatter node;*)
778
      node
779
    )
780

    
781
let normalize_inode decls nd =
782
  reset_cpt_fresh ();
783
  match nd.nodei_spec with
784
    None | Some (NodeSpec _) -> nd
785
    | Some (Contract _) -> assert false
786
                         
787
let normalize_decl (decls: program_t) (decl: top_decl) : top_decl =
788
  match decl.top_decl_desc with
789
  | Node nd ->
790
     let decl' = {decl with top_decl_desc = Node (normalize_node decls nd)} in
791
     update_node nd.node_id decl';
792
     decl'
793
  | ImportedNode nd ->
794
     let decl' = {decl with top_decl_desc = ImportedNode (normalize_inode decls nd)} in
795
     update_node nd.nodei_id decl';
796
     decl'
797
     
798
    | Include _| Open _ | Const _ | TypeDef _ -> decl
799

    
800
let normalize_prog p decls =
801
  (* Backend specific configurations for normalization *)
802
  params := p;
803

    
804
  (* Main algorithm: iterates over nodes *)
805
  List.map (normalize_decl decls) decls
806

    
807

    
808
(* Fake interface for outside uses *)
809
let mk_expr_alias_opt opt (parentid, ctx_vars) (defs, vars) expr =
810
  mk_expr_alias_opt
811
    opt
812
    {parentid = parentid; vars = ctx_vars; is_output = (fun _ -> false) }
813
    (defs, vars)
814
    expr
815

    
816
    
817
           (* Local Variables: *)
818
           (* compile-command:"make -C .." *)
819
           (* End: *)
820
    
(44-44/67)