Project

General

Profile

Download (19.9 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 Lustre_types
13
open Machine_code_types
14
open Machine_code_common
15
open Spec_types
16
open Spec_common
17
open Corelang
18
open Clocks
19
open Causality
20
open Utils
21

    
22
exception NormalizationError
23

    
24
(* Questions:
25

    
26
   - where are used the mconst. They contain initialization of
27
     constant in nodes. But they do not seem to be used by c_backend *)
28

    
29

    
30
(* translate_<foo> : vars -> context -> <foo> -> machine code/expression *)
31
(* the context contains  m : state aka memory variables  *)
32
(*                      si : initialization instructions *)
33
(*                       j : node aka machine instances  *)
34
(*                       d : local variables             *)
35
(*                       s : step instructions           *)
36

    
37
(* Machine processing requires knowledge about variables and local
38
   variables. Local could be memories while other could not.  *)
39
type machine_env = {
40
  is_local: string -> bool;
41
  get_var: string -> var_decl
42
}
43

    
44

    
45
let build_env inputs locals outputs =
46
  let all = List.sort_uniq VDeclModule.compare (locals @ inputs @ outputs) in
47
  { is_local = (fun id -> List.exists (fun v -> v.var_id = id) locals);
48
    get_var = (fun id -> try List.find (fun v -> v.var_id = id) all with Not_found ->
49
        (* Format.eprintf "Impossible to find variable %s in set %a@.@?"
50
         *   id
51
         *   VSet.pp all; *)
52
        raise Not_found)
53
  }
54

    
55

    
56

    
57
(****************************************************************)
58
(* Basic functions to translate to machine values, instructions *) 
59
(****************************************************************)
60

    
61
let translate_ident env id =
62
  (* Format.eprintf "trnaslating ident: %s@." id; *)
63
  (* id is a var that shall be visible here , ie. in vars *)
64
  try
65
    let var_id = env.get_var id in
66
    vdecl_to_val var_id
67
  with Not_found ->
68

    
69
 (* id is a constant *)
70
  try
71
    let vdecl = (Corelang.var_decl_of_const
72
                   (const_of_top (Hashtbl.find Corelang.consts_table id)))
73
    in
74
    vdecl_to_val vdecl
75
  with Not_found ->
76

    
77
   (* id is a tag, getting its type in the list of declared enums *)
78
  try
79
    id_to_tag id
80
  with Not_found ->
81
    Format.eprintf "internal error: Machine_code.translate_ident %s@.@?" id;
82
    assert false
83

    
84

    
85
(* specialize predefined (polymorphic) operators wrt their instances,
86
   so that the C semantics is preserved *)
87
let specialize_to_c expr =
88
  match expr.expr_desc with
89
  | Expr_appl (id, e, r) ->
90
    if List.exists (fun e -> Types.is_bool_type e.expr_type) (expr_list_of_expr e)
91
    then let id =
92
           match id with
93
           | "="  -> "equi"
94
           | "!=" -> "xor"
95
           | _    -> id in
96
      { expr with expr_desc = Expr_appl (id, e, r) }
97
    else expr
98
  | _ -> expr
99

    
100
let specialize_op expr =
101
  match !Options.output with
102
  | "C" -> specialize_to_c expr
103
  | _   -> expr
104

    
105
let rec translate_expr env expr =
106
  let expr = specialize_op expr in
107
  let translate_expr = translate_expr env in
108
  let value_desc = 
109
    match expr.expr_desc with
110
    | Expr_const v ->
111
      Cst v
112
    | Expr_ident x ->
113
      (translate_ident env x).value_desc
114
    | Expr_array el ->
115
      Array (List.map translate_expr el)
116
    | Expr_access (t, i) ->
117
      Access (translate_expr t, translate_expr (expr_of_dimension i))
118
    | Expr_power  (e, n) ->
119
      Power (translate_expr e, translate_expr (expr_of_dimension n))
120
    | Expr_when (e1, _, _) ->
121
      (translate_expr e1).value_desc
122
    | Expr_appl (id, e, _) when Basic_library.is_expr_internal_fun expr ->
123
      let nd = node_from_name id in
124
      Fun (node_name nd, List.map translate_expr (expr_list_of_expr e))
125
    | Expr_ite (g,t,e) when Backends.is_functional () ->
126
      (* special treatment depending on the active backend. For
127
         functional ones, like horn backend, ite are preserved in
128
         expression. While they are removed for C or Java backends. *)
129
      Fun ("ite", [translate_expr g; translate_expr t; translate_expr e])
130
    | _ ->
131
      Format.eprintf "Normalization error for backend %s: %a@."
132
        !Options.output
133
        Printers.pp_expr expr;
134
      raise NormalizationError
135
  in
136
  mk_val value_desc expr.expr_type
137

    
138
let translate_guard env expr =
139
  match expr.expr_desc with
140
  | Expr_ident x -> translate_ident env x
141
  | _ ->
142
    Format.eprintf "internal error: translate_guard %a@." Printers.pp_expr expr;
143
    assert false
144

    
145
let rec translate_act env (y, expr) =
146
  let translate_act = translate_act env in
147
  let translate_guard = translate_guard env in
148
  (* let translate_ident = translate_ident env in *)
149
  let translate_expr = translate_expr env in
150
  let lustre_eq = Corelang.mkeq Location.dummy_loc ([y.var_id], expr) in
151
  match expr.expr_desc with
152
  | Expr_ite (c, t, e) ->
153
    let c = translate_guard c in
154
    let t, spec_t = translate_act (y, t) in
155
    let e, spec_e = translate_act (y, e) in
156
    mk_conditional ~lustre_eq c [t] [e],
157
    mk_conditional_tr c spec_t spec_e
158
  | Expr_merge (x, hl) ->
159
    let var_x = env.get_var x in
160
    let hl, spec_hl = List.(split (map (fun (t, h) ->
161
        let h, spec_h = translate_act (y, h) in
162
        (t, [h]), (t, spec_h))
163
        hl)) in
164
    mk_branch' ~lustre_eq var_x hl,
165
    mk_branch_tr var_x spec_hl
166
  | _ ->
167
    let e = translate_expr expr in
168
    mk_assign ~lustre_eq y e,
169
    mk_assign_tr y e
170

    
171
let get_memory env mems eq = match eq.eq_lhs, eq.eq_rhs.expr_desc with
172
  | ([x], Expr_pre _ | [x], Expr_fby _) when env.is_local x ->
173
    let var_x = env.get_var x in
174
    VSet.add var_x mems
175
  | _ -> mems
176

    
177
let get_memories env =
178
  List.fold_left (get_memory env) VSet.empty
179

    
180
(* Datastructure updated while visiting equations *)
181
type machine_ctx = {
182
  (* memories *)
183
  m: ISet.t;
184
  (* Reset instructions *)
185
  si: instr_t list;
186
  (* Instances *)
187
  j: (Lustre_types.top_decl * Dimension.dim_expr list) IMap.t;
188
  (* Step instructions *)
189
  s: instr_t list;
190
  (* Memory pack spec *)
191
  mp: mc_formula_t list;
192
  (* Transition spec *)
193
  t: (var_decl list             (* inputs *)
194
      * var_decl list           (* locals *)
195
      * var_decl list           (* outputs *)
196
      * ISet.t                  (* memory footprint *)
197
      * mc_formula_t            (* formula *)
198
     ) list;
199
}
200

    
201
let ctx_init = {
202
  m = ISet.empty;
203
  si = [];
204
  j = IMap.empty;
205
  s = [];
206
  mp = [];
207
  t = []
208
}
209

    
210
(****************************************************************)
211
(* Main function to translate equations into this machine context we
212
   are building *) 
213
(****************************************************************)
214

    
215
let mk_control v l inst =
216
  mkinstr
217
    (MBranch (vdecl_to_val v, [l, [inst]]))
218

    
219
let control_on_clock env ck inst =
220
  let rec aux (fspec, inst as acc) ck =
221
    match (Clocks.repr ck).cdesc with
222
    | Con (ck, cr, l) ->
223
      let id = Clocks.const_of_carrier cr in
224
      let v = env.get_var id in
225
      aux ((fun spec -> Imply (Equal (Var v, Tag l), fspec spec)),
226
           mk_control v l inst)
227
        ck
228
    | _ -> acc
229
  in
230
  let fspec, inst = aux ((fun spec -> spec), inst) ck in
231
  fspec, inst
232

    
233
let reset_instance env i r c =
234
  match r with
235
  | Some r ->
236
    let r = translate_guard env r in
237
    let _, inst = control_on_clock env c
238
        (mk_conditional
239
           r
240
           [mkinstr (MSetReset i)]
241
           [mkinstr (MNoReset i)]) in
242
    Some r, [ inst ]
243
  | None -> None, []
244

    
245
let translate_eq env ctx id inputs locals outputs i eq =
246
  let translate_expr = translate_expr env in
247
  let translate_act = translate_act env in
248
  let locals_pi = Lustre_live.inter_live_i_with id (i-1) locals in
249
  let outputs_pi = Lustre_live.inter_live_i_with id (i-1) outputs in
250
  let locals_i = Lustre_live.inter_live_i_with id i locals in
251
  let outputs_i = Lustre_live.inter_live_i_with id i outputs in
252
  let pred_mp ctx a =
253
    And [mk_memory_pack ~i:(i-1) id; a] :: ctx.mp in
254
  let pred_t ctx a =
255
    (inputs, locals_i, outputs_i, ctx.m,
256
     Exists
257
       (Lustre_live.existential_vars id i eq (locals @ outputs),
258
        And [
259
          mk_transition ~i:(i-1) id
260
            (vdecls_to_vals inputs)
261
            (vdecls_to_vals locals_pi)
262
            (vdecls_to_vals outputs_pi);
263
          a
264
        ]))
265
    :: ctx.t in
266
  let control_on_clock ck inst spec_mp spec_t ctx =
267
    let fspec, inst = control_on_clock env ck inst in
268
    { ctx with
269
      s = { inst with
270
            instr_spec = [
271
              mk_memory_pack ~i id;
272
              mk_transition ~i id
273
                (vdecls_to_vals inputs)
274
                (vdecls_to_vals locals_i)
275
                (vdecls_to_vals outputs_i)
276
            ] }
277
          :: ctx.s;
278
      mp = pred_mp ctx spec_mp;
279
      t = pred_t ctx (fspec spec_t);
280
    }
281
  in
282
  let reset_instance = reset_instance env in
283
  let mkinstr' = mkinstr ~lustre_eq:eq in
284
  let ctl ?(ck=eq.eq_rhs.expr_clock) instr =
285
    control_on_clock ck (mkinstr' instr) in
286

    
287
  (* Format.eprintf "translate_eq %a with clock %a@." 
288
     Printers.pp_node_eq eq Clocks.print_ck eq.eq_rhs.expr_clock;  *)
289
  match eq.eq_lhs, eq.eq_rhs.expr_desc with
290
  | [x], Expr_arrow (e1, e2)                     ->
291
    let var_x = env.get_var x in
292
    let td = Arrow.arrow_top_decl () in
293
    let inst = new_instance td eq.eq_rhs.expr_tag in
294
    let c1 = translate_expr e1 in
295
    let c2 = translate_expr e2 in
296
    assert (c1.value_desc = Cst (Const_tag "true"));
297
    assert (c2.value_desc = Cst (Const_tag "false"));
298
    let ctx = ctl
299
        (MStep ([var_x], inst, [c1; c2]))
300
        (mk_memory_pack ~inst (node_name td))
301
        (mk_transition ~inst (node_name td) [] [] [vdecl_to_val var_x])
302
        ctx
303
    in
304
    { ctx with
305
      si = mkinstr (MSetReset inst) :: ctx.si;
306
      j = IMap.add inst (td, []) ctx.j;
307
    }
308

    
309
  | [x], Expr_pre e when env.is_local x    ->
310
    let var_x = env.get_var x in
311
    let e = translate_expr e in
312
    ctl
313
      (MStateAssign (var_x, e))
314
      (mk_state_variable_pack var_x)
315
      (mk_state_assign_tr var_x e)
316
      { ctx with m = ISet.add x ctx.m }
317

    
318
  | [x], Expr_fby (e1, e2) when env.is_local x ->
319
    let var_x = env.get_var x in
320
    let e2 = translate_expr e2 in
321
    let ctx = ctl
322
        (MStateAssign (var_x, e2))
323
        (mk_state_variable_pack var_x)
324
        (mk_state_assign_tr var_x e2)
325
        { ctx with m = ISet.add x ctx.m }
326
    in
327
    { ctx with
328
      si = mkinstr' (MStateAssign (var_x, translate_expr e1)) :: ctx.si;
329
    }
330

    
331
  | p, Expr_appl (f, arg, r)
332
    when not (Basic_library.is_expr_internal_fun eq.eq_rhs) ->
333
    let var_p = List.map (fun v -> env.get_var v) p in
334
    let el = expr_list_of_expr arg in
335
    let vl = List.map translate_expr el in
336
    let node_f = node_from_name f in
337
    let call_f = node_f, NodeDep.filter_static_inputs (node_inputs node_f) el in
338
    let inst = new_instance node_f eq.eq_rhs.expr_tag in
339
    let env_cks = List.fold_right (fun arg cks -> arg.expr_clock :: cks)
340
        el [eq.eq_rhs.expr_clock] in
341
    let call_ck = Clock_calculus.compute_root_clock
342
        (Clock_predef.ck_tuple env_cks) in
343
    let r, reset_inst = reset_instance inst r call_ck in
344
    let ctx = ctl
345
        ~ck:call_ck
346
        (MStep (var_p, inst, vl))
347
        (mk_memory_pack ~inst (node_name node_f))
348
        (mk_transition ?r ~inst (node_name node_f) vl [] (vdecls_to_vals var_p))
349
        ctx
350
    in
351
    (*Clocks.new_var true in
352
      Clock_calculus.unify_imported_clock (Some call_ck) eq.eq_rhs.expr_clock eq.eq_rhs.expr_loc;
353
      Format.eprintf "call %a: %a: %a@," Printers.pp_expr eq.eq_rhs Clocks.print_ck (Clock_predef.ck_tuple env_cks) Clocks.print_ck call_ck;*)
354
    { ctx with
355
      si = if Stateless.check_node node_f
356
        then ctx.si else mkinstr (MSetReset inst) :: ctx.si;
357
      j = IMap.add inst call_f ctx.j;
358
      s = (if Stateless.check_node node_f then [] else reset_inst)
359
          @ ctx.s;
360
    }
361

    
362
  | [x], _ ->
363
    let var_x = env.get_var x in
364
    let instr, spec = translate_act (var_x, eq.eq_rhs) in
365
    control_on_clock eq.eq_rhs.expr_clock instr True spec ctx
366

    
367
  | _ ->
368
    Format.eprintf "internal error: Machine_code.translate_eq %a@?"
369
      Printers.pp_node_eq eq;
370
    assert false
371

    
372
let constant_equations locals =
373
  List.fold_left (fun eqs vdecl ->
374
      if vdecl.var_dec_const
375
      then
376
        { eq_lhs = [vdecl.var_id];
377
          eq_rhs = desome vdecl.var_dec_value;
378
          eq_loc = vdecl.var_loc
379
        } :: eqs
380
      else eqs)
381
    [] locals
382

    
383
let translate_eqs env ctx id inputs locals outputs eqs =
384
  List.fold_left (fun (ctx, i) eq ->
385
      let ctx = translate_eq env ctx id inputs locals outputs i eq in
386
      ctx, i + 1)
387
    (ctx, 1) eqs
388
  |> fst
389

    
390

    
391
(****************************************************************)
392
(* Processing nodes *) 
393
(****************************************************************)
394

    
395
let process_asserts nd =
396

    
397
  let exprl = List.map (fun assert_ -> assert_.assert_expr ) nd.node_asserts in
398
  if Backends.is_functional () then
399
    [], [], exprl
400
  else (* Each assert(e) is associated to a fresh variable v and declared as
401
          v=e; assert (v); *)
402
    let _, vars, eql, assertl =
403
      List.fold_left (fun (i, vars, eqlist, assertlist) expr ->
404
          let loc = expr.expr_loc in
405
          let var_id = nd.node_id ^ "_assert_" ^ string_of_int i in
406
          let assert_var =
407
            mkvar_decl
408
              loc
409
              ~orig:false (* fresh var *)
410
              (var_id,
411
               mktyp loc Tydec_bool,
412
               mkclock loc Ckdec_any,
413
               false, (* not a constant *)
414
               None, (* no default value *)
415
               Some nd.node_id
416
              )
417
          in
418
          assert_var.var_type <- Type_predef.type_bool (* Types.new_ty (Types.Tbool) *);
419
          let eq = mkeq loc ([var_id], expr) in
420
          (i+1,
421
           assert_var::vars,
422
           eq::eqlist,
423
           {expr with expr_desc = Expr_ident var_id}::assertlist)
424
        ) (1, [], [], []) exprl
425
    in
426
    vars, eql, assertl
427

    
428
let translate_core env nid sorted_eqs inputs locals outputs =
429
  let constant_eqs = constant_equations locals in
430

    
431
  (* Compute constants' instructions  *)
432
  let ctx0 = translate_eqs env ctx_init nid inputs locals outputs constant_eqs in
433
  assert (ctx0.si = []);
434
  assert (IMap.is_empty ctx0.j);
435

    
436
  (* Compute ctx for all eqs *)
437
  let ctx = translate_eqs env ctx_init nid inputs locals outputs sorted_eqs in
438

    
439
  ctx, ctx0.s
440

    
441
let zero = mk_val (Cst (Const_int 0)) Type_predef.type_int
442

    
443
let memory_pack_0 nd =
444
  {
445
    mpname = nd;
446
    mpindex = Some 0;
447
    mpformula = And [StateVarPack ResetFlag; Equal (Memory ResetFlag, Val zero)]
448
  }
449

    
450
let memory_pack_toplevel nd i =
451
  {
452
    mpname = nd;
453
    mpindex = None;
454
    mpformula = Ternary (Memory ResetFlag,
455
                         StateVarPack ResetFlag,
456
                         mk_memory_pack ~i nd.node_id)
457
  }
458

    
459
let transition_0 nd =
460
  {
461
    tname = nd;
462
    tindex = Some 0;
463
    tinputs = nd.node_inputs;
464
    tlocals = [];
465
    toutputs = [];
466
    tformula = True;
467
    tfootprint = ISet.empty
468
  }
469

    
470
let transition_toplevel nd i =
471
  {
472
    tname = nd;
473
    tindex = None;
474
    tinputs = nd.node_inputs;
475
    tlocals = [];
476
    toutputs = nd.node_outputs;
477
    tformula = ExistsMem (nd.node_id,
478
                          Predicate (ResetCleared nd.node_id),
479
                          mk_transition nd.node_id ~i
480
                            (vdecls_to_vals (nd.node_inputs))
481
                            []
482
                            (vdecls_to_vals nd.node_outputs));
483
    tfootprint = ISet.empty;
484
  }
485

    
486
let translate_decl nd sch =
487
  (* Format.eprintf "Translating node %s@." nd.node_id; *)
488
  (* Extracting eqs, variables ..  *)
489
  let eqs, auts = get_node_eqs nd in
490
  assert (auts = []); (* Automata should be expanded by now *)
491

    
492
  (* In case of non functional backend (eg. C), additional local variables have
493
     to be declared for each assert *)
494
  let new_locals, assert_instrs, nd_node_asserts = process_asserts nd in
495

    
496
  (* Build the env: variables visible in the current scope *)
497
  let locals = nd.node_locals @ new_locals in
498
  (* let locals = VSet.of_list locals_list in *)
499
  (* let inout_vars = nd.node_inputs @ nd.node_outputs in *)
500
  let env = build_env nd.node_inputs locals nd.node_outputs in
501

    
502
  (* Format.eprintf "Node content is %a@." Printers.pp_node nd; *)
503

    
504
  (* Computing main content *)
505
  (* Format.eprintf "ok1@.@?"; *)
506
  let schedule = sch.Scheduling_type.schedule in
507
  (* Format.eprintf "ok2@.@?"; *)
508
  let sorted_eqs, unused = Scheduling.sort_equations_from_schedule eqs schedule in
509
  (* Format.eprintf "ok3@.locals=%a@.inout:%a@?"
510
   *   VSet.pp locals
511
   *   VSet.pp inout_vars
512
   * ; *)
513

    
514
  let equations = assert_instrs @ sorted_eqs in
515
  let mems = get_memories env equations in
516
  (* Removing computed memories from locals. We also removed unused variables. *)
517
  let locals = List.filter
518
      (fun v -> not (VSet.mem v mems) && not (List.mem v.var_id unused)) locals in
519
  (* Compute live sets for spec *)
520
  Lustre_live.set_live_of nd.node_id nd.node_outputs locals equations;
521

    
522
  (* Translate equations *)
523
  let ctx, ctx0_s = translate_core env nd.node_id equations
524
     nd.node_inputs locals nd.node_outputs in
525

    
526
  (* Format.eprintf "ok4@.@?"; *)
527

    
528
  (* Build the machine *)
529
  let mmap = IMap.bindings ctx.j in
530
  let mmemory_packs =
531
    memory_pack_0 nd
532
    :: List.mapi (fun i f ->
533
      {
534
        mpname = nd;
535
        mpindex = Some (i + 1);
536
        mpformula = red f
537
      }) (List.rev ctx.mp)
538
    @ [memory_pack_toplevel nd (List.length ctx.mp)]
539
  in
540
  let mtransitions =
541
    transition_0 nd
542
    :: List.mapi (fun i (tinputs, tlocals, toutputs, tfootprint, f) ->
543
        {
544
          tname = nd;
545
          tindex = Some (i + 1);
546
          tinputs;
547
          tlocals;
548
          toutputs;
549
          tformula = red f;
550
          tfootprint
551
        }) (List.rev ctx.t)
552
    @ [transition_toplevel nd (List.length ctx.t)]
553
  in
554
  let clear_reset = mkinstr ~instr_spec:[
555
      mk_memory_pack ~i:0 nd.node_id;
556
      mk_transition ~i:0 nd.node_id
557
        (vdecls_to_vals nd.node_inputs)
558
        []
559
        []] MClearReset in
560
  {
561
    mname = nd;
562
    mmemory = VSet.elements mems;
563
    mcalls = mmap;
564
    minstances = List.filter (fun (_, (n,_)) -> not (Stateless.check_node n)) mmap;
565
    minit = List.rev ctx.si;
566
    mconst = List.rev ctx0_s;
567
    mstatic = List.filter (fun v -> v.var_dec_const) nd.node_inputs;
568
    mstep = {
569
      step_inputs = nd.node_inputs;
570
      step_outputs = nd.node_outputs;
571
      step_locals = locals;
572
      step_checks = List.map (fun d -> d.Dimension.dim_loc,
573
                                       translate_expr env
574
                                         (expr_of_dimension d))
575
          nd.node_checks;
576
      step_instrs = clear_reset ::
577
                    (* special treatment depending on the active backend. For horn backend,
578
                       common branches are not merged while they are in C or Java
579
                       backends. *)
580
                    (if !Backends.join_guards then
581
                       join_guards_list (List.rev ctx.s)
582
                     else
583
                       List.rev ctx.s);
584
      step_asserts = List.map (translate_expr env) nd_node_asserts;
585
    };
586

    
587
    (* Processing spec: there is no processing performed here. Contract
588
       have been processed already. Either one of the other machine is a
589
       cocospec node, or the current one is a cocospec node. Contract do
590
       not contain any statement or import. *)
591

    
592
    mspec = { mnode_spec = nd.node_spec; mtransitions; mmemory_packs };
593
    mannot = nd.node_annot;
594
    msch = Some sch;
595
  }
596

    
597
(** takes the global declarations and the scheduling associated to each node *)
598
let translate_prog decls node_schs =
599
  let nodes = get_nodes decls in
600
  let machines =
601
    List.map
602
      (fun decl ->
603
         let node = node_of_top decl in
604
         let sch = IMap.find node.node_id node_schs in
605
         translate_decl node sch
606
      ) nodes
607
  in
608
  machines
609

    
610
(* Local Variables: *)
611
(* compile-command:"make -C .." *)
612
(* End: *)
(31-31/66)