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 Format
|
13
|
open LustreSpec
|
14
|
open Corelang
|
15
|
open Machine_code
|
16
|
|
17
|
|
18
|
let print_version fmt =
|
19
|
Format.fprintf fmt
|
20
|
"/* @[<v>C code generated by %s@,SVN version number %s@,Code is %s compliant */@,@]@."
|
21
|
(Filename.basename Sys.executable_name)
|
22
|
Version.number
|
23
|
(if !Options.ansi then "ANSI C90" else "C99")
|
24
|
|
25
|
(* Generation of a non-clashing name for the self memory variable (for step and reset functions) *)
|
26
|
let mk_self m =
|
27
|
let used name =
|
28
|
(List.exists (fun v -> v.var_id = name) m.mstep.step_inputs)
|
29
|
|| (List.exists (fun v -> v.var_id = name) m.mstep.step_outputs)
|
30
|
|| (List.exists (fun v -> v.var_id = name) m.mstep.step_locals)
|
31
|
|| (List.exists (fun v -> v.var_id = name) m.mmemory) in
|
32
|
mk_new_name used "self"
|
33
|
|
34
|
(* Generation of a non-clashing name for the instance variable of static allocation macro *)
|
35
|
let mk_instance m =
|
36
|
let used name =
|
37
|
(List.exists (fun v -> v.var_id = name) m.mstep.step_inputs)
|
38
|
|| (List.exists (fun v -> v.var_id = name) m.mmemory) in
|
39
|
mk_new_name used "inst"
|
40
|
|
41
|
(* Generation of a non-clashing name for the attribute variable of static allocation macro *)
|
42
|
let mk_attribute m =
|
43
|
let used name =
|
44
|
(List.exists (fun v -> v.var_id = name) m.mstep.step_inputs)
|
45
|
|| (List.exists (fun v -> v.var_id = name) m.mmemory) in
|
46
|
mk_new_name used "attr"
|
47
|
|
48
|
let mk_call_var_decl loc id =
|
49
|
{ var_id = id;
|
50
|
var_orig = false;
|
51
|
var_dec_type = mktyp Location.dummy_loc Tydec_any;
|
52
|
var_dec_clock = mkclock Location.dummy_loc Ckdec_any;
|
53
|
var_dec_const = false;
|
54
|
var_type = Type_predef.type_arrow (Types.new_var ()) (Types.new_var ());
|
55
|
var_clock = Clocks.new_var true;
|
56
|
var_loc = loc }
|
57
|
|
58
|
(* counter for loop variable creation *)
|
59
|
let loop_cpt = ref (-1)
|
60
|
|
61
|
let reset_loop_counter () =
|
62
|
loop_cpt := -1
|
63
|
|
64
|
let mk_loop_var m () =
|
65
|
let vars = m.mstep.step_inputs@m.mstep.step_outputs@m.mstep.step_locals@m.mmemory in
|
66
|
let rec aux () =
|
67
|
incr loop_cpt;
|
68
|
let s = Printf.sprintf "__%s_%d" "i" !loop_cpt in
|
69
|
if List.exists (fun v -> v.var_id = s) vars then aux () else s
|
70
|
in aux ()
|
71
|
(*
|
72
|
let addr_cpt = ref (-1)
|
73
|
|
74
|
let reset_addr_counter () =
|
75
|
addr_cpt := -1
|
76
|
|
77
|
let mk_addr_var m var =
|
78
|
let vars = m.mmemory in
|
79
|
let rec aux () =
|
80
|
incr addr_cpt;
|
81
|
let s = Printf.sprintf "%s_%s_%d" var "addr" !addr_cpt in
|
82
|
if List.exists (fun v -> v.var_id = s) vars then aux () else s
|
83
|
in aux ()
|
84
|
*)
|
85
|
let pp_machine_memtype_name fmt id = fprintf fmt "struct %s_mem" id
|
86
|
let pp_machine_regtype_name fmt id = fprintf fmt "struct %s_reg" id
|
87
|
let pp_machine_alloc_name fmt id = fprintf fmt "%s_alloc" id
|
88
|
let pp_machine_static_declare_name fmt id = fprintf fmt "%s_DECLARE" id
|
89
|
let pp_machine_static_link_name fmt id = fprintf fmt "%s_LINK" id
|
90
|
let pp_machine_static_alloc_name fmt id = fprintf fmt "%s_ALLOC" id
|
91
|
let pp_machine_reset_name fmt id = fprintf fmt "%s_reset" id
|
92
|
let pp_machine_step_name fmt id = fprintf fmt "%s_step" id
|
93
|
|
94
|
let pp_c_dimension fmt d =
|
95
|
fprintf fmt "%a" Dimension.pp_dimension d
|
96
|
|
97
|
let is_basic_c_type t =
|
98
|
match (Types.repr t).Types.tdesc with
|
99
|
| Types.Tbool | Types.Treal | Types.Tint -> true
|
100
|
| _ -> false
|
101
|
|
102
|
let pp_basic_c_type fmt t =
|
103
|
match (Types.repr t).Types.tdesc with
|
104
|
| Types.Tbool -> fprintf fmt "_Bool"
|
105
|
| Types.Treal -> fprintf fmt "double"
|
106
|
| Types.Tint -> fprintf fmt "int"
|
107
|
| _ -> assert false (* Not a basic C type. Do not handle arrays or pointers *)
|
108
|
|
109
|
let pp_c_type var fmt t =
|
110
|
let rec aux t pp_suffix =
|
111
|
match (Types.repr t).Types.tdesc with
|
112
|
| Types.Tclock t' -> aux t' pp_suffix
|
113
|
| Types.Tbool | Types.Treal | Types.Tint
|
114
|
-> fprintf fmt "%a %s%a" pp_basic_c_type t var pp_suffix ()
|
115
|
| Types.Tarray (d, t') ->
|
116
|
let pp_suffix' fmt () = fprintf fmt "%a[%a]" pp_suffix () pp_c_dimension d in
|
117
|
aux t' pp_suffix'
|
118
|
| Types.Tstatic (_, t') -> fprintf fmt "const "; aux t' pp_suffix
|
119
|
| Types.Tconst ty -> fprintf fmt "%s %s" ty var
|
120
|
| Types.Tarrow (_, _) -> fprintf fmt "void (*%s)()" var
|
121
|
| _ -> eprintf "internal error: pp_c_type %a@." Types.print_ty t; assert false
|
122
|
in aux t (fun fmt () -> ())
|
123
|
|
124
|
let rec pp_c_initialize fmt t =
|
125
|
match (Types.repr t).Types.tdesc with
|
126
|
| Types.Tint -> pp_print_string fmt "0"
|
127
|
| Types.Tclock t' -> pp_c_initialize fmt t'
|
128
|
| Types.Tbool -> pp_print_string fmt "0"
|
129
|
| Types.Treal -> pp_print_string fmt "0."
|
130
|
| Types.Tarray (d, t') when Dimension.is_dimension_const d ->
|
131
|
fprintf fmt "{%a}"
|
132
|
(Utils.fprintf_list ~sep:"," (fun fmt _ -> pp_c_initialize fmt t'))
|
133
|
(Utils.duplicate 0 (Dimension.size_const_dimension d))
|
134
|
| _ -> assert false
|
135
|
|
136
|
(* Declaration of an input variable:
|
137
|
- if its type is array/matrix/etc, then declare it as a mere pointer,
|
138
|
in order to cope with unknown/parametric array dimensions,
|
139
|
as it is the case for generics
|
140
|
*)
|
141
|
let pp_c_decl_input_var fmt id =
|
142
|
if !Options.ansi && Types.is_address_type id.var_type
|
143
|
then pp_c_type (sprintf "(*%s)" id.var_id) fmt (Types.array_base_type id.var_type)
|
144
|
else pp_c_type id.var_id fmt id.var_type
|
145
|
|
146
|
(* Declaration of an output variable:
|
147
|
- if its type is scalar, then pass its address
|
148
|
- if its type is array/matrix/struct/etc, then declare it as a mere pointer,
|
149
|
in order to cope with unknown/parametric array dimensions,
|
150
|
as it is the case for generics
|
151
|
*)
|
152
|
let pp_c_decl_output_var fmt id =
|
153
|
if (not !Options.ansi) && Types.is_address_type id.var_type
|
154
|
then pp_c_type id.var_id fmt id.var_type
|
155
|
else pp_c_type (sprintf "(*%s)" id.var_id) fmt (Types.array_base_type id.var_type)
|
156
|
|
157
|
(* Declaration of a local/mem variable:
|
158
|
- if it's an array/matrix/etc, its size(s) should be
|
159
|
known in order to statically allocate memory,
|
160
|
so we print the full type
|
161
|
*)
|
162
|
let pp_c_decl_local_var fmt id =
|
163
|
pp_c_type id.var_id fmt id.var_type
|
164
|
|
165
|
let pp_c_decl_array_mem self fmt id =
|
166
|
fprintf fmt "%a = (%a) (%s->_reg.%s)"
|
167
|
(pp_c_type (sprintf "(*%s)" id.var_id)) id.var_type
|
168
|
(pp_c_type "(*)") id.var_type
|
169
|
self
|
170
|
id.var_id
|
171
|
|
172
|
(* Declaration of a struct variable:
|
173
|
- if it's an array/matrix/etc, we declare it as a pointer
|
174
|
*)
|
175
|
let pp_c_decl_struct_var fmt id =
|
176
|
if Types.is_array_type id.var_type
|
177
|
then pp_c_type (sprintf "(*%s)" id.var_id) fmt (Types.array_base_type id.var_type)
|
178
|
else pp_c_type id.var_id fmt id.var_type
|
179
|
|
180
|
(* Access to the value of a variable:
|
181
|
- if it's not a scalar output, then its name is enough
|
182
|
- otherwise, dereference it (it has been declared as a pointer,
|
183
|
despite its scalar Lustre type)
|
184
|
- moreover, dereference memory array variables.
|
185
|
*)
|
186
|
let pp_c_var_read m fmt id =
|
187
|
if Types.is_address_type id.var_type
|
188
|
then
|
189
|
if is_memory m id
|
190
|
then fprintf fmt "(*%s)" id.var_id
|
191
|
else fprintf fmt "%s" id.var_id
|
192
|
else
|
193
|
if is_output m id
|
194
|
then fprintf fmt "*%s" id.var_id
|
195
|
else fprintf fmt "%s" id.var_id
|
196
|
|
197
|
(* Addressable value of a variable, the one that is passed around in calls:
|
198
|
- if it's not a scalar non-output, then its name is enough
|
199
|
- otherwise, reference it (it must be passed as a pointer,
|
200
|
despite its scalar Lustre type)
|
201
|
*)
|
202
|
let pp_c_var_write m fmt id =
|
203
|
if Types.is_address_type id.var_type
|
204
|
then
|
205
|
fprintf fmt "%s" id.var_id
|
206
|
else
|
207
|
if is_output m id
|
208
|
then
|
209
|
fprintf fmt "%s" id.var_id
|
210
|
else
|
211
|
fprintf fmt "&%s" id.var_id
|
212
|
|
213
|
let pp_c_decl_instance_var fmt (name, (node, static)) =
|
214
|
fprintf fmt "%a *%s" pp_machine_memtype_name (node_name node) name
|
215
|
|
216
|
let pp_c_tag fmt t =
|
217
|
pp_print_string fmt (if t = tag_true then "1" else if t = tag_false then "0" else t)
|
218
|
|
219
|
(* Prints a constant value *)
|
220
|
let rec pp_c_const fmt c =
|
221
|
match c with
|
222
|
| Const_int i -> pp_print_int fmt i
|
223
|
| Const_real r -> pp_print_string fmt r
|
224
|
| Const_float r -> pp_print_float fmt r
|
225
|
| Const_tag t -> pp_c_tag fmt t
|
226
|
| Const_array ca -> fprintf fmt "{%a }" (Utils.fprintf_list ~sep:", " pp_c_const) ca
|
227
|
| Const_struct fl -> fprintf fmt "{%a }" (Utils.fprintf_list ~sep:", " (fun fmt (f, c) -> pp_c_const fmt c)) fl
|
228
|
| Const_string _ -> assert false (* string occurs in annotations not in C *)
|
229
|
|
230
|
(* Prints a value expression [v], with internal function calls only.
|
231
|
[pp_var] is a printer for variables (typically [pp_c_var_read]),
|
232
|
but an offset suffix may be added for array variables
|
233
|
*)
|
234
|
let rec pp_c_val self pp_var fmt v =
|
235
|
match v with
|
236
|
| Cst c -> pp_c_const fmt c
|
237
|
| Array vl -> fprintf fmt "{%a}" (Utils.fprintf_list ~sep:", " (pp_c_val self pp_var)) vl
|
238
|
| Access (t, i) -> fprintf fmt "%a[%a]" (pp_c_val self pp_var) t (pp_c_val self pp_var) i
|
239
|
| Power (v, n) -> assert false
|
240
|
| LocalVar v -> pp_var fmt v
|
241
|
| StateVar v ->
|
242
|
(* array memory vars are represented by an indirection to a local var with the right type,
|
243
|
in order to avoid casting everywhere. *)
|
244
|
if Types.is_array_type v.var_type
|
245
|
then fprintf fmt "%a" pp_var v
|
246
|
else fprintf fmt "%s->_reg.%a" self pp_var v
|
247
|
| Fun (n, vl) -> Basic_library.pp_c n (pp_c_val self pp_var) fmt vl
|
248
|
|
249
|
let pp_c_checks self fmt m =
|
250
|
Utils.fprintf_list ~sep:""
|
251
|
(fun fmt (loc, check) ->
|
252
|
fprintf fmt
|
253
|
"@[<v>%a@,assert (%a);@]@,"
|
254
|
Location.pp_c_loc loc
|
255
|
(pp_c_val self (pp_c_var_read m)) check
|
256
|
)
|
257
|
fmt
|
258
|
m.mstep.step_checks
|
259
|
|
260
|
(********************************************************************************************)
|
261
|
(* Struct Printing functions *)
|
262
|
(********************************************************************************************)
|
263
|
|
264
|
let pp_registers_struct fmt m =
|
265
|
if m.mmemory <> []
|
266
|
then
|
267
|
fprintf fmt "@[%a {@[%a; @]}@] _reg; "
|
268
|
pp_machine_regtype_name m.mname.node_id
|
269
|
(Utils.fprintf_list ~sep:"; " pp_c_decl_struct_var) m.mmemory
|
270
|
else
|
271
|
()
|
272
|
|
273
|
let print_machine_struct fmt m =
|
274
|
if fst (get_stateless_status m) then
|
275
|
begin
|
276
|
end
|
277
|
else
|
278
|
begin
|
279
|
(* Define struct *)
|
280
|
fprintf fmt "@[%a {@[%a%a%t@]};@]@."
|
281
|
pp_machine_memtype_name m.mname.node_id
|
282
|
pp_registers_struct m
|
283
|
(Utils.fprintf_list ~sep:"; " pp_c_decl_instance_var) m.minstances
|
284
|
(Utils.pp_final_char_if_non_empty "; " m.minstances)
|
285
|
end
|
286
|
|
287
|
let print_machine_struct_from_header fmt inode =
|
288
|
if inode.nodei_stateless then
|
289
|
begin
|
290
|
end
|
291
|
else
|
292
|
begin
|
293
|
(* Declare struct *)
|
294
|
fprintf fmt "@[%a;@]@."
|
295
|
pp_machine_memtype_name inode.nodei_id
|
296
|
end
|
297
|
|
298
|
(********************************************************************************************)
|
299
|
(* Prototype Printing functions *)
|
300
|
(********************************************************************************************)
|
301
|
|
302
|
let print_alloc_prototype fmt (name, static) =
|
303
|
fprintf fmt "%a * %a (%a)"
|
304
|
pp_machine_memtype_name name
|
305
|
pp_machine_alloc_name name
|
306
|
(Utils.fprintf_list ~sep:",@ " pp_c_decl_input_var) static
|
307
|
|
308
|
let print_reset_prototype self fmt (name, static) =
|
309
|
fprintf fmt "void %a (@[<v>%a%t%a *%s@])"
|
310
|
pp_machine_reset_name name
|
311
|
(Utils.fprintf_list ~sep:",@ " pp_c_decl_input_var) static
|
312
|
(Utils.pp_final_char_if_non_empty ",@," static)
|
313
|
pp_machine_memtype_name name
|
314
|
self
|
315
|
|
316
|
let print_stateless_prototype fmt (name, inputs, outputs) =
|
317
|
fprintf fmt "void %a (@[<v>@[%a%t@]@,@[%a@]@,@])"
|
318
|
pp_machine_step_name name
|
319
|
(Utils.fprintf_list ~sep:",@ " pp_c_decl_input_var) inputs
|
320
|
(Utils.pp_final_char_if_non_empty ",@ " inputs)
|
321
|
(Utils.fprintf_list ~sep:",@ " pp_c_decl_output_var) outputs
|
322
|
|
323
|
let print_step_prototype self fmt (name, inputs, outputs) =
|
324
|
fprintf fmt "void %a (@[<v>@[%a%t@]@,@[%a@]%t@[%a *%s@]@])"
|
325
|
pp_machine_step_name name
|
326
|
(Utils.fprintf_list ~sep:",@ " pp_c_decl_input_var) inputs
|
327
|
(Utils.pp_final_char_if_non_empty ",@ " inputs)
|
328
|
(Utils.fprintf_list ~sep:",@ " pp_c_decl_output_var) outputs
|
329
|
(Utils.pp_final_char_if_non_empty ",@," outputs)
|
330
|
pp_machine_memtype_name name
|
331
|
self
|
332
|
|
333
|
let print_stateless_C_prototype fmt (name, inputs, outputs) =
|
334
|
let output =
|
335
|
match outputs with
|
336
|
| [hd] -> hd
|
337
|
| _ -> assert false
|
338
|
in
|
339
|
fprintf fmt "%a %s (@[<v>@[%a@]@,@])"
|
340
|
pp_basic_c_type output.var_type
|
341
|
name
|
342
|
(Utils.fprintf_list ~sep:",@ " pp_c_decl_input_var) inputs
|
343
|
|
344
|
|
345
|
|
346
|
let print_import_prototype fmt (Dep (_, s, _, _)) =
|
347
|
fprintf fmt "#include \"%s.h\"@," s
|
348
|
|
349
|
let print_import_alloc_prototype fmt (Dep (_, s, _, stateful)) =
|
350
|
if stateful then
|
351
|
fprintf fmt "#include \"%s_alloc.h\"@," s
|
352
|
|
353
|
let print_extern_alloc_prototypes fmt (Dep (_,_, header,_)) =
|
354
|
List.iter (fun decl -> match decl.top_decl_desc with
|
355
|
| ImportedNode ind when not ind.nodei_stateless ->
|
356
|
let static = List.filter (fun v -> v.var_dec_const) ind.nodei_inputs
|
357
|
in fprintf fmt "extern %a;@." print_alloc_prototype (ind.nodei_id, static)
|
358
|
| _ -> ()
|
359
|
) header
|
360
|
|
361
|
(* Local Variables: *)
|
362
|
(* compile-command:"make -C ../../.." *)
|
363
|
(* End: *)
|