Project

General

Profile

Download (31.6 KB) Statistics
| Branch: | Tag: | Revision:
1
(* We try to avoid opening modules here *)
2
module ST = Salsa.Types
3
module SDT = SalsaDatatypes
4
module LT = Lustre_types
5
module MC = Machine_code
6

    
7
(* Datatype for Salsa: FormalEnv, Ranges, Var set ... *)
8
open SalsaDatatypes
9
(******************************************************************)
10
(* TODO Xavier: should those functions be declared more globally? *)
11

    
12
let fun_types node = 
13
  try
14
    match node.LT.top_decl_desc with 
15
    | LT.Node nd -> 
16
      let tin, tout = Types.split_arrow nd.LT.node_type in
17
      Types.type_list_of_type tin, Types.type_list_of_type tout
18
    | _ -> Format.eprintf "%a is not a node@.@?" Printers.pp_decl node; assert false
19
  with Not_found -> Format.eprintf "Unable to find type def for function %s@.@?" (Corelang.node_name node); assert false
20

    
21
let called_node_id m id = 
22
  let td, _ =
23
    try
24
      List.assoc id m.MT.mcalls (* TODO Xavier: mcalls or minstances ? *)
25
    with Not_found -> assert false
26
  in
27
  td
28
(******************************************************************)    
29

    
30
(* Returns the set of vars that appear in the expression *)
31
let rec get_expr_real_vars e =
32
  let open MT in 
33
  match e.value_desc with
34
  | LocalVar v | StateVar v when Types.is_real_type v.LT.var_type -> Vars.singleton v
35
  | LocalVar _| StateVar _
36
  | Cst _ -> Vars.empty 
37
  | Fun (_, args) -> 
38
    List.fold_left 
39
      (fun acc e -> Vars.union acc (get_expr_real_vars e)) 
40
      Vars.empty args
41
  | Array _
42
  | Access _
43
  | Power _ -> assert false 
44

    
45
(* Extract the variables to appear as free variables in expressions (lhs) *)
46
let rec get_read_vars instrs =
47
  let open MT in
48
  match instrs with
49
    [] -> Vars.empty
50
  | i::tl -> (
51
    let vars_tl = get_read_vars tl in 
52
    match Corelang.get_instr_desc i with
53
    | MLocalAssign(_,e) 
54
    | MStateAssign(_,e) -> Vars.union (get_expr_real_vars e) vars_tl
55
    | MStep(_, _, el) -> List.fold_left (fun accu e -> Vars.union (get_expr_real_vars e) accu) vars_tl el
56
    | MBranch(e, branches) -> (
57
      let vars = Vars.union (get_expr_real_vars e) vars_tl in
58
      List.fold_left (fun vars (_, b) -> Vars.union vars (get_read_vars b) ) vars branches
59
    )
60
    | MReset _ 
61
    | MNoReset _ 
62
    | MComment _ -> Vars.empty  
63
  )
64

    
65
let rec get_written_vars instrs =
66
  let open MT in
67
  match instrs with
68
    [] -> Vars.empty
69
  | i::tl -> (
70
    let vars_tl = get_written_vars tl in 
71
    match Corelang.get_instr_desc i with
72
    | MLocalAssign(v,_) 
73
    | MStateAssign(v,_) -> Vars.add v vars_tl 
74
    | MStep(vdl, _, _) -> List.fold_left (fun accu v -> Vars.add v accu) vars_tl vdl
75
    | MBranch(_, branches) -> (
76
      List.fold_left (fun vars (_, b) -> Vars.union vars (get_written_vars b) ) vars_tl branches
77
    )
78
    | MReset _ 
79
    | MNoReset _ 
80
    | MComment _ -> Vars.empty    
81
  )
82

    
83
(* let rec iterTransformExpr fresh_id e_salsa abstractEnv old_range = *)
84
(*   let new_expr, new_range =  *)
85
(*     Salsa.MainEPEG.transformExpression fresh_id e_salsa abstractEnv  *)
86
(*   in *)
87
(*   Format.eprintf "New range: %a@." 	  RangesInt.pp_val new_range; *)
88
(*   if Salsa.Float.errLt new_range old_range < 0 then  *)
89
    
90
(*     iterTransformExpr fresh_id new_expr abstractEnv new_range *)
91
(*   else *)
92
(*     new_expr, new_range *)
93

    
94

    
95
(* Takes as input a salsa expression and return an optimized one *)
96
let opt_num_expr_sliced ranges e_salsa =
97
  try 
98
    let fresh_id = "toto"  in (* TODO more meaningful name *)
99

    
100
    let abstractEnv = RangesInt.to_abstract_env ranges in
101
    let new_e_salsa, e_val = 
102
      Salsa.MainEPEG.transformExpression fresh_id e_salsa abstractEnv
103
    in
104

    
105

    
106
    (* (\* Debug *\) *)
107
    (* Format.eprintf "Salsa:@.input expr: %s@.outputexpr: %s@." *)
108
    (*   (Salsa.Print.printExpression e_salsa) *)
109
    (*   (Salsa.Print.printExpression new_e_salsa); *)
110
    (* (\* Debug *\) *)
111
    
112

    
113
    let old_val = Salsa.Analyzer.evalExpr e_salsa abstractEnv [] in
114
    let expr, expr_range  =
115
      match RangesInt.Value.leq old_val e_val, RangesInt.Value.leq e_val old_val with
116
      | true, true -> (
117
	if !debug then Log.report ~level:2 (fun fmt ->
118
	  Format.fprintf fmt "No improvement on abstract value %a@ " RangesInt.pp_val e_val;
119
	);
120
	e_salsa, Some old_val
121
      )
122
      | true, false -> (
123
	if !debug then Log.report ~level:2 (fun fmt ->
124
	  Format.fprintf fmt "Improved!@ ";
125
	);
126
	new_e_salsa, Some e_val
127
      )
128
      | false, true -> Format.eprintf "CAREFUL --- new range is worse!. Restoring provided expression@ "; 	e_salsa, Some old_val
129

    
130
      | false, false ->
131
	 Format.eprintf
132
	   "Error; new range is not comparabe with old end. This should not happen!@.@?";
133
	assert false
134
    in
135
    if !debug then Log.report ~level:2 (fun fmt ->
136
      Format.fprintf fmt
137
	"  @[<v>old_expr: @[<v 0>%s@ range: %a@]@ new_expr: @[<v 0>%s@ range: %a@]@ @]@ "
138
	(Salsa.Print.printExpression e_salsa)
139
	(* MC.pp_val e *)
140
	RangesInt.pp_val old_val
141
	(Salsa.Print.printExpression new_e_salsa)
142
	(* MC.pp_val new_e *)
143
	RangesInt.pp_val e_val;
144
    );
145
    expr, expr_range
146
  with (* Not_found ->  *)
147
  | Salsa.Epeg_types.EPEGError _ -> (
148
    Log.report ~level:2 (fun fmt ->
149
      Format.fprintf fmt
150
	"BECAUSE OF AN ERROR, Expression %s was not optimized@ " 	(Salsa.Print.printExpression e_salsa)
151
(* MC.pp_val e *));
152
    e_salsa, None
153
  )
154

    
155

    
156
     
157
(* Optimize a given expression. It returns the modified expression, a computed range and freshly defined variables. *)
158
let optimize_expr nodename m constEnv printed_vars vars_env ranges formalEnv e : MT.value_t * RangesInt.t option * MT.instr_t list * Vars.VarSet.t = 
159
  let rec opt_expr vars_env ranges formalEnv e =
160
    let open MT in
161
    match e.value_desc with
162
    | Cst cst ->
163
       (* Format.eprintf "optmizing constant expr @ "; *)
164
       (* the expression is a constant, we optimize it directly if it is a real
165
  	  constant *)
166
       let typ = Typing.type_const Location.dummy_loc cst in
167
       if Types.is_real_type typ then 
168
	 opt_num_expr vars_env ranges formalEnv e 
169
       else e, None, [], Vars.empty
170
    | LocalVar v
171
    | StateVar v -> 
172
       if not (Vars.mem v printed_vars) && 
173
	 (* TODO xavier: comment recuperer le type de l'expression? Parfois e.value_type vaut 'd *)
174
	 (Types.is_real_type e.value_type ||  Types.is_real_type v.LT.var_type) 
175
       then
176
	 opt_num_expr vars_env ranges formalEnv e 
177
       else 
178
	 e, None, [],  Vars.empty  (* Nothing to optimize for expressions containing a single non real variable *)
179
    (* (\* optimize only numerical vars *\) *)
180
    (* if Type_predef.is_real_type v.LT.var_type then opt_num_expr ranges formalEnv e *)
181
    (* else e, None *)
182
    | Fun (fun_id, args) -> (
183
      (* necessarily, this is a basic function (ie. + - * / && || mod ... ) *)
184
      (* if the return type is real then optimize it, otherwise call recusrsively on arguments *)
185
      if Types.is_real_type e.value_type then
186
	opt_num_expr vars_env ranges formalEnv e 
187
      else (
188
	(* We do not care for computed local ranges. *)
189
  	let args', il, new_locals =
190
	  List.fold_right (
191
	    fun arg (al, il, nl) ->
192
	      let arg', _, arg_il, arg_nl =
193
		opt_expr vars_env ranges formalEnv arg in
194
	      arg'::al, arg_il@il, Vars.union arg_nl nl)
195
	    args
196
	    ([], [], Vars.empty)
197
	in
198
  	{ e with value_desc = Fun(fun_id, args')}, None, il, new_locals	  
199
      )
200
    )
201
    | Array _
202
    | Access _
203
    | Power _ -> assert false  
204
  and opt_num_expr vars_env ranges formalEnv e = 
205
    if !debug then (
206
      Log.report ~level:2 (fun fmt -> Format.fprintf fmt "Optimizing expression @[<hov>%a@]@ "
207
	MC.pp_val e);
208
    );
209
    (* if !debug then Format.eprintf "Optimizing expression %a with Salsa@ " MC.pp_val e;  *)
210
    (* Convert expression *)
211
    (* List.iter (fun (l,c) -> Format.eprintf "%s -> %a@ " l Printers.pp_const c) constEnv; *)
212
    let e_salsa : Salsa.Types.expression = value_t2salsa_expr constEnv e in
213
    (* Format.eprintf "apres deplaige constantes ok%a @." MC.pp_val (salsa_expr2value_t vars_env [](\* constEnv *\) e_salsa) ;  *)
214

    
215
    (* Convert formalEnv *)
216
    (* if !debug then Format.eprintf "Formal env is [%a]@ " FormalEnv.pp formalEnv; *)
217
    (* if !debug then Format.eprintf "Formal env converted to salsa@ "; *)
218

    
219
    (* Format.eprintf "Expression avant et apres substVars.@.Avant %a@." MC.pp_val (salsa_expr2value_t vars_env [] e_salsa) ;   *)
220

    
221
    (* Substitute all occurences of variables by their definition in env *)
222
    let (e_salsa: Salsa.Types.expression), _ = 
223
      Salsa.Rewrite.substVars 
224
	e_salsa
225
	(FormalEnv.to_salsa constEnv formalEnv)
226
	0 (* TODO: Nasrine, what is this integer value for ? *)
227
    in
228

    
229
    (* Format.eprintf "Apres %a@." MC.pp_val (salsa_expr2value_t vars_env [] e_salsa) ;   *)
230

    
231
    (* if !debug then Format.eprintf "Substituted def in expr@ "; *)
232
    let abstractEnv = RangesInt.to_abstract_env ranges in
233
    (* List.iter (fun (id, _) -> Format.eprintf "absenv: %s@." id) abstractEnv; *)
234
    (* The expression is partially evaluated by the available ranges
235
       valEnv2ExprEnv remplce les paires id, abstractVal par id, Cst itv - on
236
       garde evalPartExpr remplace les variables e qui sont dans env par la cst
237
       - on garde *)
238
    (* if !debug then Format.eprintf "avant avant eval part@ "; *)
239
    (* Format.eprintf "avant evalpart: %a@." MC.pp_val (salsa_expr2value_t vars_env constEnv e_salsa); *)
240
    let e_salsa =  
241
      Salsa.Analyzer.evalPartExpr 
242
	e_salsa
243
	(Salsa.Analyzer.valEnv2ExprEnv abstractEnv) 
244
	([] (* no blacklisted variables *))
245
	([] (* no arrays *))
246
    in
247
    (* Format.eprintf "apres evalpart: %a@." MC.pp_val (salsa_expr2value_t vars_env constEnv e_salsa); *)
248
    (* Checking if we have all necessary information *)
249

    
250
    let free_vars = get_salsa_free_vars vars_env constEnv abstractEnv e_salsa in
251
    if Vars.cardinal free_vars > 0 then (
252
      Log.report ~level:2 (fun fmt -> Format.fprintf fmt
253
	"Warning: unbounded free vars (%a) in expression %a. We do not optimize it.@ " 
254
	Vars.pp (Vars.fold (fun v accu ->
255
	  let v' = {v with LT.var_id = nodename.LT.node_id ^ "." ^ v.LT.var_id } in
256
	  Vars.add v' accu)
257
		   free_vars Vars.empty)
258
	MC.pp_val (salsa_expr2value_t vars_env constEnv e_salsa));
259
      if !debug then Log.report ~level:2 (fun fmt -> Format.fprintf fmt  "Some free vars, not optimizing@ ");
260
      if !debug then Log.report ~level:3 (fun fmt -> Format.fprintf fmt "  ranges: %a@ "
261
	RangesInt.pp ranges);
262

    
263
      (* if !debug then Log.report ~level:2 (fun fmt -> Format.fprintf fmt "Formal env was @[<v 0>%a@]@ " FormalEnv.pp formalEnv); *)
264
      
265
      
266
      let new_e = try salsa_expr2value_t vars_env constEnv e_salsa   with Not_found -> assert false in
267
      new_e, None, [] , Vars.empty
268
    )
269
    else (
270
      
271
      if !debug then
272
	Log.report ~level:3 (fun fmt -> Format.fprintf fmt "@[<v 2>Analyzing expression %a@  with ranges: @[<v>%a@ @]@ @]@ "
273
	  (C_backend_common.pp_c_val "" (C_backend_common.pp_c_var_read m)) (salsa_expr2value_t vars_env constEnv e_salsa)
274
	  (Utils.fprintf_list ~sep:",@ "(fun fmt (l,r) -> Format.fprintf fmt "%s -> %a" l FloatIntSalsa.pp r)) abstractEnv)
275
      ;
276

    
277
      (* Slicing expression *)
278
      let e_salsa, seq =
279
	Salsa.Rewrite.sliceExpr e_salsa 0 (Salsa.Types.Nop(Salsa.Types.Lab 0))
280
      in
281
      let def_tmps = Salsa.Utils.flatten_seq seq [] in
282
      (* Registering tmp ids in vars_env *)
283
      let vars_env', new_local_vars = List.fold_left
284
	(fun (vs,vars) (id, _) ->
285
	  let vdecl = Corelang.mk_fresh_var
286
	    nodename
287
	    Location.dummy_loc
288
	    e.MT.value_type
289
	    (Clocks.new_var true)
290
	    
291
	  in
292
	  let vs' =
293
	    VarEnv.add
294
	      id
295
	      {
296
		vdecl = vdecl ;
297
		is_local = true;
298
	      }
299
	      vs
300
	  in
301
	  let vars' = Vars.add vdecl vars in
302
	  vs', vars'
303
	)
304
	(vars_env,Vars.empty)
305
	def_tmps
306
      in 
307
      (* Debug *)
308
      if !debug then (
309
	Log.report ~level:3 (fun fmt ->
310
	  Format.fprintf  fmt "List of slices: @[<v 0>%a@]@ "
311
	    (Utils.fprintf_list
312
	       ~sep:"@ "
313
	       (fun fmt (id, e_id) ->
314
		 Format.fprintf fmt "(%s,%a) -> %a"
315
		   id
316
		   Printers.pp_var (get_var vars_env' id).vdecl
317
		   (C_backend_common.pp_c_val "" (C_backend_common.pp_c_var_read m)) (salsa_expr2value_t vars_env' constEnv e_id)
318
	       )
319
	    )
320
	    def_tmps;
321
	  Format.eprintf "Sliced expression: %a@ "
322
	    (C_backend_common.pp_c_val "" (C_backend_common.pp_c_var_read m)) (salsa_expr2value_t vars_env' constEnv e_salsa)
323
	  ;
324
	));
325
      (* Debug *)
326
      
327
      (* Optimize def tmp, and build the associated instructions.  Update the
328
	 abstract Env with computed ranges *)
329
      if !debug && List.length def_tmps >= 1 then (
330
	Log.report ~level:3 (fun fmt -> Format.fprintf fmt "@[<v 3>Optimizing sliced sub-expressions@ ")
331
      );
332
      let rev_def_tmp_instrs, ranges =
333
	List.fold_left (fun (accu_instrs, ranges) (id, e_id) ->
334
	  (* Format.eprintf "Cleaning/Optimizing %s@." id; *)
335
	  let e_id', e_range = (*Salsa.MainEPEG.transformExpression id e_id abstractEnv*)
336
	    opt_num_expr_sliced ranges e_id
337
	  in
338
	  let new_e_id' = try salsa_expr2value_t vars_env' constEnv e_id'  with Not_found -> assert false in
339

    
340
	  let vdecl = (get_var vars_env' id).vdecl in
341
	  
342
	  let new_local_assign =
343
	    (* let expr = salsa_expr2value_t vars_env' constEnv e_id' in *)
344
	    MT.MLocalAssign(vdecl, new_e_id')
345
	  in
346
	  let new_local_assign = {
347
	    MT.instr_desc = new_local_assign;
348
	    MT.lustre_eq = None (* could be Corelang.mkeq Location.dummy_loc
349
				   ([vdecl.LT.var_id], e_id) provided it is
350
				   converted as Lustre expression rather than
351
				   a Machine code value *);
352
	  }
353
	  in
354
	  let new_ranges =
355
	    match e_range with
356
	      None -> ranges
357
	    | Some e_range -> RangesInt.add_def ranges id e_range in
358
	  new_local_assign::accu_instrs, new_ranges
359
	) ([], ranges) def_tmps
360
      in
361
      if !debug && List.length def_tmps >= 1 then (
362
	Log.report ~level:3 (fun fmt -> Format.fprintf fmt "@]@ ")
363
      );
364

    
365
      (* Format.eprintf "Optimizing main expression %s@.AbstractEnv is %a" (Salsa.Print.printExpression e_salsa) RangesInt.pp ranges; *)
366
      
367

    
368
      let expr_salsa, expr_range = opt_num_expr_sliced ranges e_salsa in
369
      let expr = try salsa_expr2value_t vars_env' constEnv expr_salsa   with Not_found -> assert false in
370

    
371
      expr, expr_range, List.rev rev_def_tmp_instrs, new_local_vars
372

    
373

    
374

    
375
    )
376

    
377

    
378
      
379
  in
380
  opt_expr vars_env ranges formalEnv e  
381
    
382
    
383
(* Returns a list of assign, for each var in vars_to_print, that produce the
384
   definition of it according to formalEnv, and driven by the ranges. *)
385
let assign_vars nodename m constEnv vars_env printed_vars ranges formalEnv vars_to_print =
386
  (* We print thhe expression in the order of definition *)
387

    
388
  let ordered_vars = 
389
    List.stable_sort
390
      (FormalEnv.get_sort_fun formalEnv) 
391
      (Vars.elements vars_to_print) 
392
  in
393
  if !debug then Log.report ~level:4 (fun fmt -> Format.fprintf fmt
394
    "Printing vars in the following order: [%a]@ "
395
    (Utils.fprintf_list ~sep:", " Printers.pp_var) ordered_vars);
396
  
397
  List.fold_right (
398
    fun v (accu_instr, accu_ranges, accu_new_locals) -> 
399
      if !debug then  Log.report ~level:4 (fun fmt -> Format.fprintf fmt "Printing assign for variable %s@ " v.LT.var_id);
400
      try
401
	(* Obtaining unfold expression of v in formalEnv *)
402
	let v_def = FormalEnv.get_def formalEnv v  in
403
	let e, r, il, new_v_locals =
404
	  optimize_expr nodename m constEnv printed_vars vars_env ranges formalEnv v_def
405
	in
406
	let instr_desc = 
407
	  if try (get_var vars_env v.LT.var_id).is_local with Not_found -> assert false then
408
	    MT.MLocalAssign(v, e)
409
	  else
410
	    MT.MStateAssign(v, e)
411
	in
412
	  (il@((Corelang.mkinstr instr_desc)::accu_instr)), 
413
	    (
414
	      match r with 
415
	      | None -> ranges 
416
	      | Some v_r -> RangesInt.add_def ranges v.LT.var_id v_r),
417
	    (Vars.union accu_new_locals new_v_locals)
418
      with FormalEnv.NoDefinition _ -> (
419
	(* It should not happen with C backend, but may happen with Lustre backend *)
420
	if !Options.output = "lustre" then accu_instr, ranges, Vars.empty else (Format.eprintf "@?"; assert false)
421
      )
422
  ) ordered_vars ([], ranges, Vars.empty)
423

    
424
(* Main recursive function: modify the instructions list while preserving the
425
   order of assigns for state variables. Returns a quintuple: (new_instrs,
426
   ranges, formalEnv, printed_vars, and remaining vars to be printed) *)
427
let rec rewrite_instrs nodename m constEnv  vars_env m instrs ranges formalEnv printed_vars vars_to_print =
428
  let formal_env_def = FormalEnv.def constEnv vars_env in
429
  (* Format.eprintf "Rewrite intrs : [%a]@." MC.pp_instrs instrs; *)
430
  let assign_vars = assign_vars nodename m constEnv vars_env in
431
  (* if !debug then ( *)
432
  (*   Log.report ~level:3 (fun fmt -> Format.fprintf fmt    *)
433
  (*     "Current printed_vars: [%a]@ Vars to print: [%a]@ Formal env is [%a]@ " *)
434
  (*     Vars.pp printed_vars *)
435
  (*     Vars.pp vars_to_print *)
436
  (*     FormalEnv.pp formalEnv) *)
437
  (* ); *)
438
  match instrs with
439
  | [] -> 
440
     (* End of instruction list: we produce the definition of each variable that
441
	appears in vars_to_print. Each of them should be defined in formalEnv *)
442
     (* if !debug then Format.eprintf "Producing definitions %a@ " Vars.pp vars_to_print; *)
443
    let instrs, ranges', new_expr_locals = assign_vars printed_vars ranges formalEnv vars_to_print in
444
    instrs,
445
    ranges',     
446
    formalEnv,
447
    Vars.union printed_vars vars_to_print, (* We should have printed all required vars *)
448
    [], (* No more vars to be printed *)
449
    Vars.empty
450
      
451
  | hd_instr::tl_instrs -> 
452
     (* We reformulate hd_instr, producing or not a fresh instruction, updating
453
	formalEnv, possibly ranges and vars_to_print *)
454
     begin
455
       let hd_instrs, ranges, formalEnv, printed_vars, vars_to_print, hd_new_locals =
456
	 match Corelang.get_instr_desc hd_instr with 
457
	 | MT.MLocalAssign(vd,vt) when Types.is_real_type vd.LT.var_type  && not (Vars.mem vd vars_to_print) -> 
458
	   (* LocalAssign are injected into formalEnv *)
459
	   (* if !debug then Format.eprintf "Registering local assign %a@ " MC.pp_instr hd_instr; *)
460
	   (* if !debug then Format.eprintf "%a@ " MC.pp_instr hd_instr; *)
461
	   let formalEnv' = formal_env_def formalEnv vd vt in (* formelEnv updated with vd = vt *)
462
	   [],                        (* no instr generated *)
463
	   ranges,                    (* no new range computed *)
464
	   formalEnv',
465
	   printed_vars,              (* no new printed vars *)
466
	   vars_to_print,              (* no more or less variables to print *)
467
	   Vars.empty              (* no new locals *)
468
	   
469
	 | MT.MLocalAssign(vd,vt) when Types.is_real_type vd.LT.var_type && Vars.mem vd vars_to_print ->
470

    
471
           (* if !debug then Format.eprintf "Registering and producing state assign %a@ " MC.pp_instr hd_instr; *)
472
           (* if !debug then Format.eprintf "Registering and producing state assign %a@ " MC.pp_instr hd_instr; *)
473
           (* if !debug then ( *)
474
	   (*   Format.eprintf "%a@ " MC.pp_instr hd_instr; *)
475
	   (*   Format.eprintf "Selected var %a: producing expression@ " Printers.pp_var vd; *)
476
	   (* ); *)
477
	   let formalEnv' = formal_env_def formalEnv vd vt in (* formelEnv updated with vd = vt *)
478
	   let instrs', ranges', expr_new_locals = (* printing vd = optimized vt *)
479
	     assign_vars printed_vars ranges formalEnv' (Vars.singleton vd)  
480
	   in
481
	   instrs',
482
	   ranges',                          (* no new range computed *)
483
	   formalEnv',                       (* formelEnv already updated *)
484
	   Vars.add vd printed_vars,         (* adding vd to new printed vars *)
485
	   Vars.remove vd vars_to_print,     (* removed vd from variables to print *)
486
	   expr_new_locals                   (* adding sliced vardecl to the list *)
487
	     
488
	 | MT.MStateAssign(vd,vt) when Types.is_real_type vd.LT.var_type (* && Vars.mem vd vars_to_print  *)-> 
489

    
490
	   (* StateAssign are produced since they are required by the function. We still
491
	      keep their definition in the formalEnv in case it can optimize later
492
	      outputs. vd is removed from remaining vars_to_print *)
493
	   (* if !debug then Format.eprintf "Registering and producing state assign %a@ " MC.pp_instr hd_instr; *)
494
           (* if !debug then ( *)
495
	   (*   Format.eprintf "%a@ " MC.pp_instr hd_instr; *)
496
	   (*   Format.eprintf "State assign %a: producing expression@ " Printers.pp_var vd; *)
497
	   (* ); *)
498
	   let formalEnv' = formal_env_def formalEnv vd vt in (* formelEnv updated with vd = vt *) 
499
	   let instrs', ranges', expr_new_locals = (* printing vd = optimized vt *)
500
	     assign_vars printed_vars ranges formalEnv' (Vars.singleton vd)  
501
	   in
502
	   instrs',
503
	   ranges',                          (* no new range computed *)
504
	   formalEnv,                        (* formelEnv already updated *)
505
	   Vars.add vd printed_vars,         (* adding vd to new printed vars *)
506
	   Vars.remove vd vars_to_print,     (* removed vd from variables to print *)
507
	   expr_new_locals                   (* adding sliced vardecl to the list *)
508

    
509
	 | (MT.MLocalAssign(vd,vt) | MT.MStateAssign(vd,vt))  ->
510
	    (* Format.eprintf "other assign %a@." MC.pp_instr hd_instr; *)
511

    
512
	   (* We have to produce the instruction. But we may have to produce as
513
	      well its dependencies *)
514
	   let required_vars = get_expr_real_vars vt in
515
	   let required_vars = Vars.diff required_vars printed_vars in (* remove
516
									  already
517
									  produced
518
									  variables *)
519
	   (* Format.eprintf "Required vars: %a@." Vars.pp required_vars; *)
520
	   let required_vars = Vars.diff required_vars (Vars.of_list m.MT.mmemory) in
521
	   let prefix_instr, ranges, new_expr_dep_locals  = 
522
	     assign_vars printed_vars ranges formalEnv required_vars in
523

    
524
	   let vt', _, il, expr_new_locals = optimize_expr nodename m constEnv (Vars.union required_vars printed_vars) vars_env ranges formalEnv vt in
525
	   let new_instr = 
526
	     match Corelang.get_instr_desc hd_instr with
527
	     | MT.MLocalAssign _ -> Corelang.update_instr_desc hd_instr (MT.MLocalAssign(vd,vt'))
528
	     | _ -> Corelang.update_instr_desc hd_instr (MT.MStateAssign(vd,vt'))
529
	   in
530
	   let written_vars = Vars.add vd required_vars in
531
	   prefix_instr@il@[new_instr],
532
	   ranges,                          (* no new range computed *)
533
	   formalEnv,                       (* formelEnv untouched *)
534
	   Vars.union written_vars printed_vars,  (* adding vd + dependencies to
535
						     new printed vars *)
536
	   Vars.diff vars_to_print written_vars, (* removed vd + dependencies from
537
						   variables to print *)
538
	   (Vars.union new_expr_dep_locals expr_new_locals)
539
	 | MT.MStep(vdl,id,vtl) ->
540
	    (* Format.eprintf "step@."; *)
541

    
542
	   (* if !debug then Format.eprintf "Call to a node %a@ " MC.pp_instr hd_instr; *)
543
	   (* Call of an external function. Input expressions have to be
544
	      optimized, their free variables produced. A fresh range has to be
545
	      computed for each output variable in vdl. Output of the function
546
	      call are removed from vars to be printed *)
547
	   let node =  called_node_id m id in
548
	   let node_id = Corelang.node_name node in
549
	   let tin, tout =  (* special care for arrow *)
550
	     if node_id = "_arrow" then
551
	       match vdl with 
552
	       | [v] -> let t = v.LT.var_type in
553
			[t; t], [t]
554
	       | _ -> assert false (* should not happen *)
555
	     else
556
	       fun_types node
557
	   in
558
	   (* if !debug then Format.eprintf "@[<v 2>... optimizing arguments@ "; *)
559
	   let vtl', vtl_ranges, il, args_new_locals = List.fold_right2 (
560
	     fun e typ_e (exprl, range_l, il_l, new_locals)-> 
561
	       if Types.is_real_type typ_e then
562
		 let e', r', il, new_expr_locals =
563
		   optimize_expr nodename m constEnv printed_vars vars_env ranges formalEnv e
564
		 in
565
		 e'::exprl, r'::range_l, il@il_l, Vars.union new_locals new_expr_locals
566
	       else 
567
		 e::exprl, None::range_l, il_l, new_locals
568
	   ) vtl tin ([], [], [], Vars.empty) 
569
	   in 
570
	   (* if !debug then Format.eprintf "... done@ @]@ "; *)
571

    
572

    
573

    
574
	   (* let required_vars =  *)
575
	   (*   List.fold_left2  *)
576
	   (*     (fun accu e typ_e ->  *)
577
	   (* 	 if Types.is_real_type typ_e then *)
578
	   (* 	   Vars.union accu (get_expr_real_vars e)  *)
579
	   (* 	 else (\* we do not consider non real expressions *\) *)
580
	   (* 	   accu *)
581
	   (*     ) *)
582
 	   (*     Vars.empty  *)
583
	   (*     vtl' tin *)
584
	   (* in *)
585
	   (* if !debug then Format.eprintf "Required vars: [%a]@ Printed vars: [%a]@ Remaining required vars: [%a]@ " *)
586
	   (*   Vars.pp required_vars  *)
587
	   (*   Vars.pp printed_vars *)
588
	   (*   Vars.pp (Vars.diff required_vars printed_vars) *)
589
	   (* ; *)
590
	   (* let required_vars = Vars.diff required_vars printed_vars in (\* remove *)
591
	   (* 								  already *)
592
	   (* 								  produced *)
593
	   (* 								  variables *\) *)
594
	   (* let written_vars = Vars.union required_vars (Vars.of_list vdl) in *)
595
	   (* let instrs', ranges' = assign_vars (Vars.union written_vars printed_vars) ranges formalEnv required_vars in *)
596

    
597
	   (* instrs' @ [Corelang.update_instr_desc hd_instr (MT.MStep(vdl,id,vtl'))], (* New instrs *) *)
598

    
599
	   let written_vars = Vars.of_list vdl in
600
	   
601

    
602
	   
603
	   il @ [Corelang.update_instr_desc hd_instr (MT.MStep(vdl,id,vtl'))], (* New instrs *)
604
	   RangesInt.add_call ranges vdl id vtl_ranges,   (* add information bounding each vdl var *) 
605
	   formalEnv,
606
	   Vars.union written_vars printed_vars,        (* adding vdl to new printed vars *)
607
	   Vars.diff vars_to_print written_vars,
608
	   args_new_locals
609
	     
610
	 | MT.MBranch(vt, branches) ->
611
	    
612
	    (* Required variables to compute vt are introduced. 
613
	       Then each branch is refactored specifically 
614
	    *)
615
	    
616
	    (* if !debug then Format.eprintf "Branching %a@ " MC.pp_instr hd_instr; *)
617
	    let required_vars = get_expr_real_vars vt in
618
	    let required_vars = Vars.diff required_vars printed_vars in (* remove
619
									   already
620
									   produced
621
									   variables *)
622
	    let vt', _, prefix_instr, prefix_new_locals = optimize_expr nodename m constEnv printed_vars vars_env ranges formalEnv vt in
623

    
624
	    let new_locals = prefix_new_locals in
625
	    
626
	   (* let prefix_instr, ranges =  *)
627
	   (*   assign_vars (Vars.union required_vars printed_vars) ranges formalEnv required_vars in *)
628

    
629
	   let printed_vars = Vars.union printed_vars required_vars in
630

    
631

    
632
	   let read_vars_tl = get_read_vars tl_instrs in
633
	   (* if !debug then Format.eprintf "@[<v 2>Dealing with branches@ "; *)
634
	   let branches', written_vars, merged_ranges, new_locals = List.fold_right (
635
	     fun (b_l, b_instrs) (new_branches, written_vars, merged_ranges, new_locals) -> 
636
	       let b_write_vars = get_written_vars b_instrs in
637
	       let b_vars_to_print = Vars.inter b_write_vars (Vars.union read_vars_tl vars_to_print) in 
638
	       let b_fe = formalEnv in               (* because of side effect
639
							data, we copy it for
640
							each branch *)
641
	       let b_instrs', b_ranges, b_formalEnv, b_printed, b_vars, b_new_locals = 
642
		 rewrite_instrs nodename m constEnv  vars_env m b_instrs ranges b_fe printed_vars b_vars_to_print 
643
	       in
644
	       (* b_vars should be empty *)
645
	       let _ = if b_vars != [] then assert false in
646
	       
647
	       (* Producing the refactored branch *)
648
	       (b_l, b_instrs') :: new_branches,
649
	       Vars.union b_printed written_vars, (* They should coincides. We
650
						     use union instead of
651
						     inter to ease the
652
						     bootstrap *)
653
	       RangesInt.merge merged_ranges b_ranges,
654
	       Vars.union new_locals b_new_locals
655
		 
656
	   ) branches ([], required_vars, ranges, new_locals)
657
	   in
658
	   (* if !debug then Format.eprintf "dealing with branches done@ @]@ ";	   *)
659
	   prefix_instr@[Corelang.update_instr_desc hd_instr (MT.MBranch(vt', branches'))],
660
	   merged_ranges, (* Only step functions call within branches may have
661
			     produced new ranges. We merge this data by
662
			     computing the join per variable *)
663
	   formalEnv,    (* Thanks to the computation of var_to_print in each
664
			    branch, no new definition should have been computed
665
			    without being already printed *)
666
	   Vars.union written_vars printed_vars,
667
	   Vars.diff vars_to_print written_vars (* We remove vars that have been
668
						   produced within branches *),
669
	   new_locals
670

    
671

    
672
	 | MT.MReset(_) | MT.MNoReset _ | MT.MComment _ ->
673
	    (* if !debug then Format.eprintf "Untouched %a (non real)@ " MC.pp_instr hd_instr; *)
674

    
675
	   (* Untouched instruction *)
676
	   [ hd_instr ],                    (* unmodified instr *)
677
	   ranges,                          (* no new range computed *)
678
	   formalEnv,                       (* no formelEnv update *)
679
	   printed_vars,
680
	   vars_to_print,                   (* no more or less variables to print *)
681
	   Vars.empty                       (* no new slides vars *)
682
		
683
       in
684
       let tl_instrs, ranges, formalEnv, printed_vars, vars_to_print, tl_new_locals = 
685
	 rewrite_instrs 
686
	   nodename
687
	   m
688
	   constEnv 	  
689
	   vars_env
690
	   m 
691
	   tl_instrs
692
	   ranges
693
	   formalEnv
694
	   printed_vars
695
	   vars_to_print
696
	   
697
       in
698
       hd_instrs @ tl_instrs,
699
       ranges,
700
       formalEnv, 
701
       printed_vars,
702
       vars_to_print,
703
       (Vars.union hd_new_locals tl_new_locals)
704
     end
705

    
706

    
707

    
708

    
709

    
710

    
711
(* TODO: deal with new variables, ie. tmp *)
712
let salsaStep constEnv  m s = 
713
  let ranges = RangesInt.empty (* empty for the moment, should be build from
714
				  machine annotations or externally provided information *) in
715
  let annots = List.fold_left (
716
    fun accu annl -> 
717
      List.fold_left (
718
	fun accu (key, range) ->
719
	  match key with 
720
	  | ["salsa"; "ranges"; var] -> (var, range)::accu
721
	  | _ -> accu
722
      ) accu annl.LT.annots
723
  ) [] m.MT.mannot
724
  in
725
  let ranges = 
726
    List.fold_left (fun ranges (v, value) ->
727
      match value.LT.eexpr_qfexpr.LT.expr_desc with 
728
      | LT.Expr_tuple [minv; maxv] -> (
729
	let get_cst e = match e.LT.expr_desc with 
730
	  | LT.Expr_const (LT.Const_real (c,e,s)) -> 
731
	    (* calculer la valeur c * 10^e *) 
732
	    Num.div_num c (Num.power_num (Num.num_of_int 10) (Num.num_of_int e))
733
	  | _ -> 
734
	    Format.eprintf 
735
	      "Invalid salsa range: %a. It should be a pair of constant floats and %a is not a float.@." 
736
	      Printers.pp_expr value.LT.eexpr_qfexpr
737
	      Printers.pp_expr e
738
	    ; 
739
	    assert false 
740
	in
741
	(* let minv = Salsa.Float.Domain.of_num (get_cst minv) and *)
742
	(*     maxv = Salsa.Float.Domain.of_num (get_cst maxv) in *)
743
	(* if !debug then Format.eprintf "variable %s in [%s, %s]@ " v (Num.string_of_num minv) (Num.string_of_num maxv); *)
744
	RangesInt.enlarge ranges v (Salsa.Float.Domain.inject_nums (get_cst minv) (get_cst maxv))
745
      )
746
      | _ -> 
747
	Format.eprintf 
748
	  "Invalid salsa range: %a. It should be a pair of floats.@." 
749
	  Printers.pp_expr value.LT.eexpr_qfexpr; 
750
	assert false
751
    ) ranges annots
752
  in
753
  let formal_env = FormalEnv.empty () in
754
  let vars_to_print =
755
    Vars.real_vars  
756
      (
757
	Vars.union 
758
	  (Vars.of_list m.MT.mmemory) 
759
	  (Vars.of_list s.MT.step_outputs) 
760
      )
761
  in 
762
  (* TODO: should be at least step output + may be memories *)
763
  
764
  let vars_env = compute_vars_env m in  
765
  (* if !debug then Format.eprintf "@[<v 2>Registering node equations@ ";  *)
766
  let new_instrs, _, _, printed_vars, _, new_locals = 
767
    rewrite_instrs
768
      m.MT.mname
769
      m
770
      constEnv 
771
      vars_env
772
      m
773
      s.MT.step_instrs
774
      ranges
775
      formal_env
776
      (Vars.real_vars (Vars.of_list s.MT.step_inputs (* printed_vars : real
777
							inputs are considered as
778
							already printed *)))
779
      vars_to_print
780
      
781
  in
782
  let all_local_vars = Vars.real_vars (Vars.of_list s.MT.step_locals) in
783
  let unused = (Vars.diff all_local_vars printed_vars) in
784
  let locals =
785
    if not (Vars.is_empty unused) then (
786
      if !debug then Log.report ~level:2 (fun fmt -> Format.fprintf fmt  "Unused local vars: [%a]. Removing them.@ "
787
	Vars.pp unused);
788
      List.filter (fun v -> not (Vars.mem v unused)) s.MT.step_locals
789
    )
790
    else
791
      s.MT.step_locals
792
  in
793
  let locals = locals @ Vars.elements  new_locals in
794
  { s with MT.step_instrs = new_instrs; MT.step_locals = locals } (* we have also to modify local variables to declare new vars *)
795

    
796

    
797
let machine_t2machine_t_optimized_by_salsa constEnv  mt =
798
  try
799
    if !debug then Log.report ~level:2 (fun fmt -> Format.fprintf fmt "@[<v 3>[salsa] Optimizing machine %s@ " mt.MT.mname.LT.node_id);
800
    let new_step = salsaStep constEnv  mt mt.MT.mstep in
801
    if !debug then Log.report ~level:2 (fun fmt -> Format.fprintf fmt "@]@ ");
802
    { mt with MT.mstep = new_step } 
803
    
804
      
805
  with FormalEnv.NoDefinition v as exp -> 
806
    Format.eprintf "No definition for variable %a@.@?" Printers.pp_var v; 
807
    raise exp
808

    
809

    
810
(* Local Variables: *)
811
(* compile-command:"make -C ../../.." *)
812
(* End: *)
813

    
(1-1/3)