Project

General

Profile

Download (14.8 KB) Statistics
| Branch: | Tag: | Revision:
1
(* EMF backend *)
2
(* This backup is initially motivated by the need to express Spacer computed
3
   invariants as Matlab Simulink executable evidences.
4

    
5
   Therefore the input language is more restricted. We do not expect fancy
6
   datastructure, complex function calls, etc.
7

    
8
   In case of error, use -node foo -inline to eliminate function calls that are
9
   not seriously handled yet.
10
   
11

    
12
   In terms of algorithm, the process was initially based on printing normalized
13
   code. We now rely on machine code printing. The old code is preserved for
14
   reference.
15
*)
16

    
17
open LustreSpec
18
open Machine_code
19
open Format
20
open Utils
21

    
22
exception Unhandled of string
23
    
24

    
25
(* Basic printing functions *)
26
    
27
let pp_var_string fmt v = fprintf fmt "\"%s\"" v
28
let pp_var_name fmt v = fprintf fmt "\"%a\"" Printers.pp_var_name v
29
let pp_node_args = fprintf_list ~sep:", " pp_var_name
30

    
31
    
32
(* Matlab starting counting from 1.
33
   simple function to extract the element id in the list. Starts from 1. *)
34
let rec get_idx x l =
35
  match l with
36
  | hd::tl -> if hd = x then 1 else 1+(get_idx x tl)
37
  | [] -> assert false
38

    
39
(**********************************************)
40
(* Old stuff: printing normalized code as EMF *)     
41
(**********************************************)
42

    
43
(*
44
let pp_expr vars fmt expr =
45
  let rec pp_expr fmt expr =
46
    match expr.expr_desc with
47
    | Expr_const c -> Printers.pp_const fmt c
48
    | Expr_ident id ->
49
       if List.mem id vars then
50
	 Format.fprintf fmt "u%i" (get_idx id vars)
51
       else
52
	 assert false (* impossible to find element id in var list *)
53
    | Expr_array a -> fprintf fmt "[%a]" pp_tuple a
54
    | Expr_access (a, d) -> fprintf fmt "%a[%a]" pp_expr a Dimension.pp_dimension d
55
    | Expr_power (a, d) -> fprintf fmt "(%a^%a)" pp_expr a Dimension.pp_dimension d
56
    | Expr_tuple el -> fprintf fmt "(%a)" pp_tuple el
57
    | Expr_ite (c, t, e) -> fprintf fmt "if %a; y=(%a); else y=(%a); end" pp_expr c pp_expr t pp_expr e
58
    | Expr_arrow (e1, e2) ->(
59
      match e1.expr_desc, e2.expr_desc with
60
      | Expr_const c1, Expr_const c2 -> if c1 = Corelang.const_of_bool true && c2 = Corelang.const_of_bool false then fprintf fmt "STEP" else assert false (* only handle true -> false *)
61
      | _ -> assert false (* only handle true -> false *)
62
    )
63
    | Expr_fby (e1, e2) -> assert false (* not covered yet *)
64
    | Expr_pre e -> fprintf fmt "UNITDELAY"
65
    | Expr_when (e, id, l) -> assert false (* clocked based expressions are not handled yet *)
66
    | Expr_merge (id, hl) -> assert false (* clocked based expressions are not handled yet *)
67
    | Expr_appl (id, e, r) -> pp_app fmt id e r
68

    
69
  and pp_tuple fmt el =
70
    fprintf_list ~sep:"," pp_expr fmt el
71

    
72
  and pp_app fmt id e r =
73
    match r with
74
    | None -> pp_call fmt id e
75
    | Some c -> assert false (* clocked based expressions are not handled yet *)
76

    
77
  and pp_call fmt id e =
78
    match id, e.expr_desc with
79
    | "+", Expr_tuple([e1;e2]) -> fprintf fmt "(%a + %a)" pp_expr e1 pp_expr e2
80
    | "uminus", _ -> fprintf fmt "(- %a)" pp_expr e
81
    | "-", Expr_tuple([e1;e2]) -> fprintf fmt "(%a - %a)" pp_expr e1 pp_expr e2
82
    | "*", Expr_tuple([e1;e2]) -> fprintf fmt "(%a * %a)" pp_expr e1 pp_expr e2
83
    | "/", Expr_tuple([e1;e2]) -> fprintf fmt "(%a / %a)" pp_expr e1 pp_expr e2
84
    | "mod", Expr_tuple([e1;e2]) -> fprintf fmt "mod (%a, %a)" pp_expr e1 pp_expr e2
85
    | "&&", Expr_tuple([e1;e2]) -> fprintf fmt "(%a & %a)" pp_expr e1 pp_expr e2
86
    | "||", Expr_tuple([e1;e2]) -> fprintf fmt "(%a | %a)" pp_expr e1 pp_expr e2
87
    | "xor", Expr_tuple([e1;e2]) -> fprintf fmt "xor (%a, %a)" pp_expr e1 pp_expr e2
88
    | "impl", Expr_tuple([e1;e2]) -> fprintf fmt "((~%a) | %a)" pp_expr e1 pp_expr e2
89
    | "<", Expr_tuple([e1;e2]) -> fprintf fmt "(%a < %a)" pp_expr e1 pp_expr e2
90
    | "<=", Expr_tuple([e1;e2]) -> fprintf fmt "(%a <= %a)" pp_expr e1 pp_expr e2
91
    | ">", Expr_tuple([e1;e2]) -> fprintf fmt "(%a > %a)" pp_expr e1 pp_expr e2
92
    | ">=", Expr_tuple([e1;e2]) -> fprintf fmt "(%a >= %a)" pp_expr e1 pp_expr e2
93
    | "!=", Expr_tuple([e1;e2]) -> fprintf fmt "(%a ~= %a)" pp_expr e1 pp_expr e2
94
    | "=", Expr_tuple([e1;e2]) -> fprintf fmt "(%a == %a)" pp_expr e1 pp_expr e2
95
    | "not", _ -> fprintf fmt "(~%a)" pp_expr e
96
    | _, Expr_tuple _ -> fprintf fmt "%s %a" id pp_expr e
97
    | _ -> fprintf fmt "%s (%a)" id pp_expr e
98

    
99
  in
100
  pp_expr fmt expr
101

    
102
let pp_stmt fmt stmt =
103
  match stmt with
104
  | Eq eq -> (
105
    match eq.eq_lhs with
106
      [var] -> (
107
     (* first, we extract the expression and associated variables *)
108
	let vars = Utils.ISet.elements (Corelang.get_expr_vars eq.eq_rhs) in
109

    
110
	fprintf fmt "\"%s\": @[<v 2>{ \"expr\": \"%a\",@ \"vars\": [%a] @]}"
111
	  var
112
	  (pp_expr vars) eq.eq_rhs (* todo_pp_expr expr *)
113
	  (fprintf_list ~sep:", " pp_var_string) vars
114
      )
115
    | _ -> assert false (* should not happen for input of EMF backend (cocospec generated nodes *)
116
  )
117
  | _ -> assert false (* should not happen with EMF backend *)
118

    
119
let pp_node fmt nd =
120
  fprintf fmt "@[<v 2>\"%s\": {@ \"inputs\": [%a],@ \"outputs\": [%a],@ "
121
    nd.node_id
122
    pp_node_args nd.node_inputs
123
    pp_node_args nd.node_outputs;
124
  fprintf fmt "\"exprs\": {@[<v 1> %a@]@ }"
125
    (fprintf_list ~sep:",@ " pp_stmt ) nd.node_stmts;
126
  fprintf fmt "@]@ }"
127

    
128
let pp_decl fmt decl =
129
  match decl.top_decl_desc with
130
  | Node nd -> fprintf fmt "%a@ " pp_node nd
131
  | ImportedNode _
132
  | Const _
133
  | Open _
134
  | TypeDef _ -> eprintf "should not happen in EMF backend"
135
*)
136

    
137

    
138
(**********************************************)
139
(*   Printing machine code as EMF             *)
140
(**********************************************)
141

    
142
(* Print machine code values as matlab expressions. Variable identifiers are
143
   replaced by uX where X is the index of the variables in the list vars of input
144
   variables. *)
145
let rec pp_val vars fmt v =
146
  match v.value_desc with
147
  | Cst c -> Printers.pp_const fmt c
148
  | LocalVar v
149
  | StateVar v ->
150
     let id = v.var_id in
151
     if List.mem id vars then
152
       Format.fprintf fmt "u%i" (get_idx id vars)
153
     else
154
       assert false (* impossible to find element id in var list *)
155
  | Fun (n, vl) -> pp_fun vars n fmt vl
156
  | _ -> assert false (* not available in EMF backend *)
157
and pp_fun vars id fmt vl =
158
  (* eprintf "print %s with %i args@.@?" id (List.length vl);*)
159
  match id, vl with
160
    | "+", [v1;v2] -> fprintf fmt "(%a + %a)" (pp_val vars) v1 (pp_val vars) v2
161
    | "uminus", [v] -> fprintf fmt "(- %a)" (pp_val vars) v
162
    | "-", [v1;v2] -> fprintf fmt "(%a - %a)" (pp_val vars) v1 (pp_val vars) v2
163
    | "*",[v1;v2] -> fprintf fmt "(%a * %a)" (pp_val vars) v1 (pp_val vars) v2
164
    | "/", [v1;v2] -> fprintf fmt "(%a / %a)" (pp_val vars) v1 (pp_val vars) v2
165
    | "mod", [v1;v2] -> fprintf fmt "mod (%a, %a)" (pp_val vars) v1 (pp_val vars) v2
166
    | "&&", [v1;v2] -> fprintf fmt "(%a & %a)" (pp_val vars) v1 (pp_val vars) v2
167
    | "||", [v1; v2] -> fprintf fmt "(%a | %a)" (pp_val vars) v1 (pp_val vars) v2
168
    | "xor", [v1; v2] -> fprintf fmt "xor (%a, %a)" (pp_val vars) v1 (pp_val vars) v2
169
    | "impl", [v1; v2] -> fprintf fmt "((~%a) | %a)" (pp_val vars) v1 (pp_val vars) v2
170
    | "<", [v1; v2] -> fprintf fmt "(%a < %a)" (pp_val vars) v1 (pp_val vars) v2
171
    | "<=", [v1; v2] -> fprintf fmt "(%a <= %a)" (pp_val vars) v1 (pp_val vars) v2
172
    | ">", [v1; v2] -> fprintf fmt "(%a > %a)" (pp_val vars) v1 (pp_val vars) v2
173
    | ">=", [v1; v2] -> fprintf fmt "(%a >= %a)" (pp_val vars) v1 (pp_val vars) v2
174
    | "!=", [v1; v2] -> fprintf fmt "(%a != %a)" (pp_val vars) v1 (pp_val vars) v2
175
    | "=", [v1; v2] -> fprintf fmt "(%a = %a)" (pp_val vars) v1 (pp_val vars) v2
176
    | "not", [v] -> fprintf fmt "(~%a)" (pp_val vars) v
177
    | _ -> fprintf fmt "%s (%a)" id  (Utils.fprintf_list ~sep:", " (pp_val vars)) vl 
178

    
179
     
180
(* detect whether the instruction i represents an ARROW, ie an arrow with true -> false *)
181
let is_arrow_fun m i =
182
  match Corelang.get_instr_desc i with
183
  | MStep ([var], i, vl)  -> (
184
    let name = try (Machine_code.get_node_def i m).node_id with Not_found -> Format.eprintf "Impossible to find node %s@.@?" i; raise Not_found in
185
    match name, vl with
186
    | "_arrow", [v1; v2] -> (
187
	match v1.value_desc, v2.value_desc with
188
	| Cst c1, Cst c2 ->
189
	   if c1 = Corelang.const_of_bool true && c2 = Corelang.const_of_bool false then
190
	     true
191
	   else
192
	     assert false (* only handle true -> false *)
193
	| _ -> assert false
194
    )
195
    | _ -> false
196
  )
197
  | _ -> false
198

    
199
(* pp_basic_instr prints regular instruction. These do not contain MStep which
200
   should have been already filtered out. Another restriction which is supposed
201
   to be enforced is that branching statement contain a single instruction (in
202
   practice it has to be an assign) *)
203
let rec pp_basic_instr m vars fmt i =
204
  match Corelang.get_instr_desc i with
205
  | MLocalAssign (var,v) 
206
  | MStateAssign (var,v) -> fprintf fmt "y = %a" (pp_val vars) v
207
  | MBranch (g,[(tag1,[case1]);(tag2,[case2])])     ->
208
     (* Thanks to normalization with join_guards = false, branches shall contain
209
	a single expression *)
210
     let then_case, else_case =
211
       if tag1 = Corelang.tag_true then
212
	 case1, case2
213
       else
214
	 case2, case1
215
     in
216
     fprintf fmt "if %a; %a; else %a; end"
217
       (pp_val vars) g
218
       (pp_basic_instr m vars) then_case
219
       (pp_basic_instr m vars) else_case
220
  | MBranch _ (* EMF backend only accept true/false ite *)
221
    -> Format.eprintf "unhandled branch in EMF@.@?"; assert false
222
  | MReset _           
223
    -> Format.eprintf "unhandled reset in EMF@.@?"; assert false
224
  | MNoReset _
225
    -> Format.eprintf "unhandled noreset in EMF@.@?"; assert false
226
  | MStep _ (* function calls already handled, including STEP *)
227
    -> Format.eprintf "unhandled function call in EMF (should have been filtered out before)@.@?";
228
      assert false
229
  | MComment _ 
230
    -> Format.eprintf "unhandled comment in EMF@.@?"; assert false
231
      (* not  available for EMF output *)
232

    
233

    
234

    
235
let rec get_instr_var i =
236
  match Corelang.get_instr_desc i with
237
  | MLocalAssign (var,_) 
238
  | MStateAssign (var,_) 
239
  | MStep ([var], _, _)  -> var 
240
  | MBranch (_,[(tag1,case1);(tag2,case2)])     ->
241
     get_instrs_var case1 (* assuming case1 and case2 define the same variable *)
242
  | MStep _ (* only single output for function call *)
243
  | MBranch _ (* EMF backend only accept true/false ite *)
244
  | MReset _           
245
  | MNoReset _
246
  | MComment _ -> assert false (* not  available for EMF output *)
247
and get_instrs_var il =
248
  match il with
249
  | i::_ -> get_instr_var i (* looking for the first instr *)
250
  | _ -> assert false
251

    
252
  
253
let rec  get_val_vars v =
254
  match v.value_desc with
255
  | Cst c -> Utils.ISet.empty
256
  | LocalVar v
257
  | StateVar v -> Utils.ISet.singleton v.var_id
258
  | Fun (n, vl) -> List.fold_left (fun res v -> Utils.ISet.union (get_val_vars v) res) Utils.ISet.empty vl
259
  | _ -> assert false (* not available in EMF backend *)
260

    
261
let rec get_instr_vars i =
262
  match Corelang.get_instr_desc i with
263
  | MLocalAssign (_,v)  
264
  | MStateAssign (_,v) -> get_val_vars v
265
  | MStep (_, _, vl)  -> List.fold_left (fun res v -> Utils.ISet.union res (get_val_vars v)) Utils.ISet.empty vl 
266
  | MBranch (c,[(_,[case1]);(_,[case2])])     ->
267
     Utils.ISet.union
268
       (get_val_vars c)
269
       (
270
	 Utils.ISet.union
271
	   (get_instr_vars case1)
272
	   (get_instr_vars case2)
273
       )
274
  | MBranch _ (* EMF backend only accept true/false ite *)
275
  | MReset _           
276
  | MNoReset _
277
  | MComment _ -> failwith "Error in compiling some constructs into EMF. Have you considered -node foo -inline options ?" (* not  available for EMF output *)
278
(* and get_instrs_vars il = *)
279
(*   List.fold_left (fun res i -> Utils.ISet.union res (get_instr_vars i)) *)
280
(*     Utils.ISet.empty *)
281
(*     il *)
282

    
283

    
284
let pp_original_lustre_expression m fmt i =
285
  match Corelang.get_instr_desc i with
286
  | MLocalAssign _ | MStateAssign _ 
287
  | MBranch _
288
    -> ( match i.lustre_eq with None -> () | Some e -> Printers.pp_node_eq fmt e) 
289
  | MStep _ when is_arrow_fun m i -> () (* we print nothing, this is a STEP *)
290
  | MStep _ -> (match i.lustre_eq with None -> () | Some eq -> Printers.pp_node_eq fmt eq)
291
  | _ -> ()
292
    
293
let pp_emf_instrs m fmt i =
294
  (* Either it is a Step function non arrow, then we have a dedicated treatment,
295
     or it has to be a single variable assigment *)
296
  let arguments_vars = Utils.ISet.elements (get_instr_vars i) in	
297
  
298
  match Corelang.get_instr_desc i with
299
    (* Regular node call either a statuful node or a functional one *)
300
    MStep (outputs, f, inputs) when not (is_arrow_fun m i) -> (
301
      fprintf fmt "\"__functioncall\": @[<v 2>{ \"node\": \"%s\",@ \"inputs\": [%a],@ \"vars\": [%a]@ \"outputs\": [%a],@ \"original_lustre_expr\": [%a]@]}"
302
	((Machine_code.get_node_def f m).node_id) (* Node name *)
303
        (Utils.fprintf_list ~sep:", " (fun fmt _val -> fprintf fmt "\"%a\"" (pp_val arguments_vars) _val)) inputs                  (* inputs *)
304
	(fprintf_list ~sep:", " pp_var_string) arguments_vars
305
	(fprintf_list ~sep:", " (fun fmt v -> pp_var_string fmt v.var_id)) outputs  (* outputs *)
306
	(pp_original_lustre_expression m) i         (* original lustre expr *)
307
    )
308
  | _ ->
309
     (* Other expressions, including "pre" *)
310
     ( 
311
    (* first, we extract the expression and associated variables *)
312
    let var = get_instr_var i in
313
    fprintf fmt "\"%s\": @[<v 2>{ \"expr\": \"%a\",@ \"vars\": [%a] @ \"original_lustre_expr\": [%a]@]}"
314
      var.var_id
315
      (fun fmt i -> match Corelang.get_instr_desc i with
316
      | MStep _ -> fprintf fmt "STEP"
317
      | _ -> pp_basic_instr m arguments_vars fmt i) i
318
      (fprintf_list ~sep:", " pp_var_string) arguments_vars
319
      (pp_original_lustre_expression m) i
320
  )
321
    
322
     
323
let pp_machine fmt m =
324
  try
325
    fprintf fmt "@[<v 2>\"%s\": {@ \"inputs\": [%a],@ \"outputs\": [%a],@ "
326
      m.mname.node_id
327
      pp_node_args m.mstep.step_inputs
328
      pp_node_args m.mstep.step_outputs;
329
    fprintf fmt "\"exprs\": {@[<v 1> %a@]@ }"
330
      (fprintf_list ~sep:",@ " (pp_emf_instrs m)) m.mstep.step_instrs;
331
    fprintf fmt "@]@ }"
332
  with Unhandled msg -> (
333
    eprintf "[Error] @[<v 0>EMF backend@ Issues while translating node %s@ "
334
      m.mname.node_id;
335
    eprintf "%s@ " msg;
336
    eprintf "node skipped - no output generated@ @]@."
337
  )
338

    
339
(****************************************************)
340
(* Main function: iterates over node and print them *)
341
(****************************************************)
342
let pp_meta fmt basename =
343
  fprintf fmt "\"meta\": @[<v 0>{@ ";
344
  Utils.fprintf_list ~sep:",@ "
345
    (fun fmt (k, v) -> fprintf fmt "\"%s\": \"%s\"" k v)
346
    fmt
347
    ["compiler-name", (Filename.basename Sys.executable_name);
348
     "compiler-version", Version.number;
349
     "command", (String.concat " " (Array.to_list Sys.argv));
350
     "source_file", basename
351
    ]
352
  ;
353
  fprintf fmt "@ @]},@ "
354
    
355
let translate fmt basename prog machines =
356
  fprintf fmt "@[<v 0>{@ ";
357
  pp_meta fmt basename;
358
  fprintf fmt "\"nodes\": @[<v 0>{@ ";
359
  (* Previous alternative: mapping normalized lustre to EMF: 
360
     fprintf_list ~sep:",@ " pp_decl fmt prog; *)
361
  fprintf_list ~sep:",@ " pp_machine fmt machines;
362
  fprintf fmt "@ @]}";
363
  fprintf fmt "@ @]}"
364

    
365
(* Local Variables: *)
366
(* compile-command: "make -C ../.." *)
367
(* End: *)
(1-1/2)