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 Machine_code_types
|
15
|
open Corelang
|
16
|
open Normalization
|
17
|
open Machine_code_common
|
18
|
|
19
|
let mpfr_module = mktop (Open(false, "mpfr_lustre"))
|
20
|
let cpt_fresh = ref 0
|
21
|
|
22
|
let mpfr_rnd () = "MPFR_RNDN"
|
23
|
|
24
|
let mpfr_prec () = !Options.mpfr_prec
|
25
|
|
26
|
let inject_id = "MPFRId"
|
27
|
|
28
|
let inject_copy_id = "mpfr_set"
|
29
|
|
30
|
let inject_real_id = "mpfr_set_flt"
|
31
|
|
32
|
let inject_init_id = "mpfr_init2"
|
33
|
|
34
|
let inject_clear_id = "mpfr_clear"
|
35
|
|
36
|
let mpfr_t = "mpfr_t"
|
37
|
|
38
|
let unfoldable_value value =
|
39
|
not (Types.is_real_type value.value_type && is_const_value value)
|
40
|
|
41
|
let inject_id_id expr =
|
42
|
let e = mkpredef_call expr.expr_loc inject_id [expr] in
|
43
|
{ e with
|
44
|
expr_type = Type_predef.type_real;
|
45
|
expr_clock = expr.expr_clock;
|
46
|
}
|
47
|
|
48
|
let pp_inject_real pp_var pp_val fmt var value =
|
49
|
Format.fprintf fmt "%s(%a, %a, %s);"
|
50
|
inject_real_id
|
51
|
pp_var var
|
52
|
pp_val value
|
53
|
(mpfr_rnd ())
|
54
|
|
55
|
let inject_assign expr =
|
56
|
let e = mkpredef_call expr.expr_loc inject_copy_id [expr] in
|
57
|
{ e with
|
58
|
expr_type = Type_predef.type_real;
|
59
|
expr_clock = expr.expr_clock;
|
60
|
}
|
61
|
|
62
|
let pp_inject_copy pp_var fmt var value =
|
63
|
Format.fprintf fmt "%s(%a, %a, %s);"
|
64
|
inject_copy_id
|
65
|
pp_var var
|
66
|
pp_var value
|
67
|
(mpfr_rnd ())
|
68
|
|
69
|
let rec pp_inject_assign pp_var fmt var value =
|
70
|
if is_const_value value
|
71
|
then
|
72
|
pp_inject_real pp_var pp_var fmt var value
|
73
|
else
|
74
|
pp_inject_copy pp_var fmt var value
|
75
|
|
76
|
let pp_inject_init pp_var fmt var =
|
77
|
Format.fprintf fmt "%s(%a, %i);"
|
78
|
inject_init_id
|
79
|
pp_var var
|
80
|
(mpfr_prec ())
|
81
|
|
82
|
let pp_inject_clear pp_var fmt var =
|
83
|
Format.fprintf fmt "%s(%a);"
|
84
|
inject_clear_id
|
85
|
pp_var var
|
86
|
|
87
|
let base_inject_op id =
|
88
|
match id with
|
89
|
| "+" -> "MPFRPlus"
|
90
|
| "-" -> "MPFRMinus"
|
91
|
| "*" -> "MPFRTimes"
|
92
|
| "/" -> "MPFRDiv"
|
93
|
| "uminus" -> "MPFRUminus"
|
94
|
| "<=" -> "MPFRLe"
|
95
|
| "<" -> "MPFRLt"
|
96
|
| ">=" -> "MPFRGe"
|
97
|
| ">" -> "MPFRGt"
|
98
|
| "=" -> "MPFREq"
|
99
|
| "!=" -> "MPFRNeq"
|
100
|
(* Math library functions *)
|
101
|
| "acos" -> "MPFRacos"
|
102
|
| "acosh" -> "MPFRacosh"
|
103
|
| "asin" -> "MPFRasin"
|
104
|
| "asinh" -> "MPFRasinh"
|
105
|
| "atan" -> "MPFRatan"
|
106
|
| "atan2" -> "MPFRatan2"
|
107
|
| "atanh" -> "MPFRatanh"
|
108
|
| "cbrt" -> "MPFRcbrt"
|
109
|
| "cos" -> "MPFRcos"
|
110
|
| "cosh" -> "MPFRcosh"
|
111
|
| "ceil" -> "MPFRceil"
|
112
|
| "erf" -> "MPFRerf"
|
113
|
| "exp" -> "MPFRexp"
|
114
|
| "fabs" -> "MPFRfabs"
|
115
|
| "floor" -> "MPFRfloor"
|
116
|
| "fmod" -> "MPFRfmod"
|
117
|
| "log" -> "MPFRlog"
|
118
|
| "log10" -> "MPFRlog10"
|
119
|
| "pow" -> "MPFRpow"
|
120
|
| "round" -> "MPFRround"
|
121
|
| "sin" -> "MPFRsin"
|
122
|
| "sinh" -> "MPFRsinh"
|
123
|
| "sqrt" -> "MPFRsqrt"
|
124
|
| "trunc" -> "MPFRtrunc"
|
125
|
| "tan" -> "MPFRtan"
|
126
|
|
127
|
|
128
|
| "pow" -> "MPFRpow"
|
129
|
| _ -> raise Not_found
|
130
|
|
131
|
let inject_op id =
|
132
|
Format.eprintf "trying to inject mpfr into function %s@." id;
|
133
|
try
|
134
|
base_inject_op id
|
135
|
with Not_found -> id
|
136
|
|
137
|
let homomorphic_funs =
|
138
|
List.fold_right (fun id res -> try base_inject_op id :: res with Not_found -> res) Basic_library.internal_funs []
|
139
|
|
140
|
let is_homomorphic_fun id =
|
141
|
List.mem id homomorphic_funs
|
142
|
|
143
|
let inject_call expr =
|
144
|
match expr.expr_desc with
|
145
|
| Expr_appl (id, args, None) when not (Basic_library.is_expr_internal_fun expr) ->
|
146
|
{ expr with expr_desc = Expr_appl (inject_op id, args, None) }
|
147
|
| _ -> expr
|
148
|
|
149
|
let expr_of_const_array expr =
|
150
|
match expr.expr_desc with
|
151
|
| Expr_const (Const_array cl) ->
|
152
|
let typ = Types.array_element_type expr.expr_type in
|
153
|
let expr_of_const c =
|
154
|
{ expr_desc = Expr_const c;
|
155
|
expr_type = typ;
|
156
|
expr_clock = expr.expr_clock;
|
157
|
expr_loc = expr.expr_loc;
|
158
|
expr_delay = Delay.new_var ();
|
159
|
expr_annot = None;
|
160
|
expr_tag = new_tag ();
|
161
|
}
|
162
|
in { expr with expr_desc = Expr_array (List.map expr_of_const cl) }
|
163
|
| _ -> assert false
|
164
|
|
165
|
(* inject_<foo> : defs * used vars -> <foo> -> (updated defs * updated vars) * normalized <foo> *)
|
166
|
let rec inject_list alias node inject_element defvars elist =
|
167
|
List.fold_right
|
168
|
(fun t (defvars, qlist) ->
|
169
|
let defvars, norm_t = inject_element alias node defvars t in
|
170
|
(defvars, norm_t :: qlist)
|
171
|
) elist (defvars, [])
|
172
|
|
173
|
let rec inject_expr ?(alias=true) node defvars expr =
|
174
|
let res =
|
175
|
match expr.expr_desc with
|
176
|
| Expr_const (Const_real _) -> mk_expr_alias_opt alias node defvars expr
|
177
|
| Expr_const (Const_array _) -> inject_expr ~alias:alias node defvars (expr_of_const_array expr)
|
178
|
| Expr_const (Const_struct _) -> assert false
|
179
|
| Expr_ident _
|
180
|
| Expr_const _ -> defvars, expr
|
181
|
| Expr_array elist ->
|
182
|
let defvars, norm_elist = inject_list alias node (fun _ -> inject_expr ~alias:true) defvars elist in
|
183
|
let norm_expr = { expr with expr_desc = Expr_array norm_elist } in
|
184
|
defvars, norm_expr
|
185
|
| Expr_power (e1, d) ->
|
186
|
let defvars, norm_e1 = inject_expr node defvars e1 in
|
187
|
let norm_expr = { expr with expr_desc = Expr_power (norm_e1, d) } in
|
188
|
defvars, norm_expr
|
189
|
| Expr_access (e1, d) ->
|
190
|
let defvars, norm_e1 = inject_expr node defvars e1 in
|
191
|
let norm_expr = { expr with expr_desc = Expr_access (norm_e1, d) } in
|
192
|
defvars, norm_expr
|
193
|
| Expr_tuple elist ->
|
194
|
let defvars, norm_elist =
|
195
|
inject_list alias node (fun alias -> inject_expr ~alias:alias) defvars elist in
|
196
|
let norm_expr = { expr with expr_desc = Expr_tuple norm_elist } in
|
197
|
defvars, norm_expr
|
198
|
| Expr_appl (id, args, r) ->
|
199
|
let defvars, norm_args = inject_expr node defvars args in
|
200
|
let norm_expr = { expr with expr_desc = Expr_appl (id, norm_args, r) } in
|
201
|
mk_expr_alias_opt alias node defvars (inject_call norm_expr)
|
202
|
| Expr_arrow _ -> defvars, expr
|
203
|
| Expr_pre e ->
|
204
|
let defvars, norm_e = inject_expr node defvars e in
|
205
|
let norm_expr = { expr with expr_desc = Expr_pre norm_e } in
|
206
|
defvars, norm_expr
|
207
|
| Expr_fby (e1, e2) ->
|
208
|
let defvars, norm_e1 = inject_expr node defvars e1 in
|
209
|
let defvars, norm_e2 = inject_expr node defvars e2 in
|
210
|
let norm_expr = { expr with expr_desc = Expr_fby (norm_e1, norm_e2) } in
|
211
|
defvars, norm_expr
|
212
|
| Expr_when (e, c, l) ->
|
213
|
let defvars, norm_e = inject_expr node defvars e in
|
214
|
let norm_expr = { expr with expr_desc = Expr_when (norm_e, c, l) } in
|
215
|
defvars, norm_expr
|
216
|
| Expr_ite (c, t, e) ->
|
217
|
let defvars, norm_c = inject_expr node defvars c in
|
218
|
let defvars, norm_t = inject_expr node defvars t in
|
219
|
let defvars, norm_e = inject_expr node defvars e in
|
220
|
let norm_expr = { expr with expr_desc = Expr_ite (norm_c, norm_t, norm_e) } in
|
221
|
defvars, norm_expr
|
222
|
| Expr_merge (c, hl) ->
|
223
|
let defvars, norm_hl = inject_branches node defvars hl in
|
224
|
let norm_expr = { expr with expr_desc = Expr_merge (c, norm_hl) } in
|
225
|
defvars, norm_expr
|
226
|
in
|
227
|
(*Format.eprintf "inject_expr %B %a = %a@." alias Printers.pp_expr expr Printers.pp_expr (snd res);*)
|
228
|
res
|
229
|
|
230
|
and inject_branches node defvars hl =
|
231
|
List.fold_right
|
232
|
(fun (t, h) (defvars, norm_q) ->
|
233
|
let (defvars, norm_h) = inject_expr node defvars h in
|
234
|
defvars, (t, norm_h) :: norm_q
|
235
|
)
|
236
|
hl (defvars, [])
|
237
|
|
238
|
|
239
|
let rec inject_eq node defvars eq =
|
240
|
let (defs', vars'), norm_rhs = inject_expr ~alias:false node defvars eq.eq_rhs in
|
241
|
let norm_eq = { eq with eq_rhs = norm_rhs } in
|
242
|
norm_eq::defs', vars'
|
243
|
|
244
|
(* let inject_eexpr ee =
|
245
|
* { ee with eexpr_qfexpr = inject_expr ee.eexpr_qfexpr }
|
246
|
*
|
247
|
* let inject_spec s =
|
248
|
* { s with
|
249
|
* assume = List.map inject_eexpr s.assume;
|
250
|
* guarantees = List.map inject_eexpr s.guarantees;
|
251
|
* modes = List.map (fun m ->
|
252
|
* { m with
|
253
|
* require = List.map inject_eexpr m.require;
|
254
|
* ensure = List.map inject_eexpr m.ensure
|
255
|
* }
|
256
|
* ) s.modes
|
257
|
* } *)
|
258
|
|
259
|
(** normalize_node node returns a normalized node,
|
260
|
ie.
|
261
|
- updated locals
|
262
|
- new equations
|
263
|
-
|
264
|
*)
|
265
|
let inject_node node =
|
266
|
cpt_fresh := 0;
|
267
|
let inputs_outputs = node.node_inputs@node.node_outputs in
|
268
|
let is_local v =
|
269
|
List.for_all ((!=) v) inputs_outputs in
|
270
|
let orig_vars = inputs_outputs@node.node_locals in
|
271
|
let defs, vars =
|
272
|
let eqs, auts = get_node_eqs node in
|
273
|
if auts != [] then assert false; (* Automata should be expanded by now. *)
|
274
|
List.fold_left (inject_eq node) ([], orig_vars) eqs in
|
275
|
(* Normalize the asserts *)
|
276
|
let vars, assert_defs, asserts =
|
277
|
List.fold_left (
|
278
|
fun (vars, def_accu, assert_accu) assert_ ->
|
279
|
let assert_expr = assert_.assert_expr in
|
280
|
let (defs, vars'), expr =
|
281
|
inject_expr
|
282
|
~alias:false
|
283
|
node
|
284
|
([], vars) (* defvar only contains vars *)
|
285
|
assert_expr
|
286
|
in
|
287
|
vars', defs@def_accu, {assert_ with assert_expr = expr}::assert_accu
|
288
|
) (vars, [], []) node.node_asserts in
|
289
|
let new_locals = List.filter is_local vars in
|
290
|
(* Compute traceability info:
|
291
|
- gather newly bound variables
|
292
|
- compute the associated expression without aliases
|
293
|
*)
|
294
|
(* let diff_vars = List.filter (fun v -> not (List.mem v node.node_locals)) new_locals in *)
|
295
|
(* See comment below
|
296
|
* let spec = match node.node_spec with
|
297
|
* | None -> None
|
298
|
* | Some spec -> Some (inject_spec spec)
|
299
|
* in *)
|
300
|
let node =
|
301
|
{ node with
|
302
|
node_locals = new_locals;
|
303
|
node_stmts = List.map (fun eq -> Eq eq) (defs @ assert_defs);
|
304
|
(* Incomplete work: TODO. Do we have to inject MPFR code here?
|
305
|
Does it make sense for annotations? For me, only if we produce
|
306
|
C code for annotations. Otherwise the various verification
|
307
|
backend should have their own understanding, but would not
|
308
|
necessarily require this additional normalization. *)
|
309
|
(*
|
310
|
node_spec = spec;
|
311
|
node_annot = List.map (fun ann -> {ann with
|
312
|
annots = List.map (fun (ids, ee) -> ids, inject_eexpr ee) ann.annots}
|
313
|
) node.node_annot *)
|
314
|
}
|
315
|
in ((*Printers.pp_node Format.err_formatter node;*) node)
|
316
|
|
317
|
let inject_decl decl =
|
318
|
match decl.top_decl_desc with
|
319
|
| Node nd ->
|
320
|
{decl with top_decl_desc = Node (inject_node nd)}
|
321
|
| Open _ | ImportedNode _ | Const _ | TypeDef _ -> decl
|
322
|
|
323
|
let inject_prog decls =
|
324
|
List.map inject_decl decls
|
325
|
|
326
|
|
327
|
(* Local Variables: *)
|
328
|
(* compile-command:"make -C .." *)
|
329
|
(* End: *)
|