Project

General

Profile

Download (16.1 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 Utils.Format
13
open Lustre_types
14
open Corelang
15
open Machine_code_types
16
open Machine_code_common
17
open C_backend_common
18

    
19
(********************************************************************************************)
20
(*                         Header Printing functions                                        *)
21
(********************************************************************************************)
22

    
23

    
24
module type MODIFIERS_HDR = sig
25
  val print_machine_decl_prefix: Format.formatter -> machine_t -> unit
26
  val pp_import_standard_spec: formatter -> unit -> unit
27
end
28

    
29
module EmptyMod = struct
30
  let print_machine_decl_prefix = fun _ _ -> ()
31
  let pp_import_standard_spec _ _ = ()
32
end
33

    
34
module Main = functor (Mod: MODIFIERS_HDR) -> struct
35

    
36
  let print_import_standard fmt () =
37
    (* if Machine_types.has_machine_type () then *)
38
    fprintf fmt
39
      "#include <stdint.h>@,\
40
       %a\
41
       #include \"%s/arrow.h%s\"\
42
       %a"
43
      (if !Options.mpfr then
44
         pp_print_endcut "#include <mpfr.h>"
45
       else pp_print_nothing) ()
46
      (Arrow.arrow_top_decl ()).top_decl_owner
47
      (if !Options.cpp then "pp" else "")
48
      Mod.pp_import_standard_spec ()
49

    
50
  let rec print_static_val pp_var fmt v =
51
    match v.value_desc with
52
    | Cst c ->
53
      pp_c_const fmt c
54
    | Var v ->
55
      pp_var fmt v
56
    | Fun (n, vl) ->
57
      pp_basic_lib_fun (Types.is_int_type v.value_type) n
58
        (print_static_val pp_var) fmt vl
59
    | _ ->
60
      (* TODO: raise proper error *)
61
      eprintf "Internal error: C_backend_header.print_static_val";
62
      assert false
63

    
64
  let print_constant_decl (m, attr, inst) pp_var fmt v =
65
    fprintf fmt "%s %a = %a"
66
      attr
67
      (pp_c_type (sprintf "%s ## %s" inst v.var_id)) v.var_type
68
      (print_static_val pp_var) (get_const_assign m v)
69

    
70
  let pp_var inst const_locals fmt v =
71
    if List.mem v const_locals then
72
      fprintf fmt "%s ## %s" inst v.var_id
73
    else fprintf fmt "%s" v.var_id
74

    
75
  let print_static_constant_decl (_, _, inst as macro) fmt const_locals =
76
    pp_print_list ~pp_open_box:pp_open_vbox0
77
      ~pp_sep:(pp_print_endcut ";\\")  ~pp_eol:(pp_print_endcut ";\\")
78
      (print_constant_decl macro (pp_var inst const_locals))
79
      fmt
80
      const_locals
81

    
82
  let print_static_declare_instance
83
      (m, attr, inst) const_locals fmt (i, (n, static)) =
84
    let values = List.map (value_of_dimension m) static in
85
    fprintf fmt "%a(%s, %a%s)"
86
      pp_machine_static_declare_name (node_name n)
87
      attr
88
      (pp_print_list ~pp_open_box:pp_open_hbox ~pp_sep:pp_print_comma
89
         ~pp_eol:pp_print_comma (print_static_val (pp_var inst const_locals)))
90
      values
91
      i
92

    
93
  let print_static_declare_macro fmt (m, attr, inst as macro) =
94
    let const_locals =
95
      List.filter (fun vdecl -> vdecl.var_dec_const) m.mstep.step_locals in
96
    let array_mem =
97
      List.filter (fun v -> Types.is_array_type v.var_type) m.mmemory in
98
    fprintf fmt
99
      "@[<v 2>\
100
       #define %a(%s, %a%s)\\@,\
101
       %a%s %a %s;\\@,\
102
       %a%a;\
103
       @]"
104
      pp_machine_static_declare_name m.mname.node_id
105
      attr
106
      (pp_print_list ~pp_sep:pp_print_comma ~pp_eol:pp_print_comma
107
         (pp_c_var_read m)) m.mstatic
108
      inst
109
      (* constants *)
110
      (print_static_constant_decl macro) const_locals
111
      attr
112
      (pp_machine_memtype_name ~ghost:false) m.mname.node_id
113
      inst
114
      (pp_print_list ~pp_open_box:pp_open_vbox0
115
         ~pp_sep:(pp_print_endcut ";\\") ~pp_eol:(pp_print_endcut ";\\")
116
         (pp_c_decl_local_var m)) array_mem
117
      (pp_print_list ~pp_open_box:pp_open_vbox0
118
         ~pp_sep:(pp_print_endcut ";\\")
119
         (fun fmt (i', m') ->
120
            let path = sprintf "%s ## _%s" inst i' in
121
            fprintf fmt "%a"
122
              (print_static_declare_instance macro const_locals)
123
              (path, m'))) m.minstances
124

    
125
  let print_static_link_instance fmt (i, (m, _)) =
126
    fprintf fmt "%a(%s)" pp_machine_static_link_name (node_name m) i
127

    
128
  (* Allocation of a node struct:
129
     - if node memory is an array/matrix/etc, we cast it to a pointer (see pp_registers_struct)
130
  *)
131
  let print_static_link_macro fmt (m, _, inst) =
132
    let array_mem = List.filter (fun v -> Types.is_array_type v.var_type)
133
        m.mmemory in
134
    fprintf fmt
135
      "@[<v>@[<v 2>\
136
       #define %a(%s) do {\\@,\
137
       %a%a;\\@]@,\
138
       } while (0)\
139
       @]"
140
      pp_machine_static_link_name m.mname.node_id
141
      inst
142
      (pp_print_list ~pp_open_box:pp_open_vbox0
143
         ~pp_sep:(pp_print_endcut ";\\") ~pp_eol:(pp_print_endcut ";\\")
144
         (fun fmt v ->
145
            fprintf fmt "%s._reg.%s = (%a*) &%s"
146
              inst
147
              v.var_id
148
              (fun fmt v -> pp_c_type "" fmt (Types.array_base_type v.var_type)) v
149
              v.var_id)) array_mem
150
      (pp_print_list ~pp_open_box:pp_open_vbox0
151
         ~pp_sep:(pp_print_endcut ";\\")
152
         (fun fmt (i',m') ->
153
            let path = sprintf "%s ## _%s" inst i' in
154
            fprintf fmt "%a;\\@,%s.%s = &%s"
155
              print_static_link_instance (path,m')
156
              inst
157
              i'
158
              path)) m.minstances
159

    
160
  let print_static_alloc_macro fmt (m, attr, inst) =
161
    fprintf fmt
162
      "@[<v>@[<v 2>\
163
       #define %a(%s, %a%s)\\@,\
164
       %a(%s, %a%s);\\@,\
165
       %a(%s);\
166
       @]@]"
167
      pp_machine_static_alloc_name m.mname.node_id
168
      attr
169
      (pp_print_list ~pp_sep:pp_print_comma ~pp_eol:pp_print_comma
170
         (pp_c_var_read m)) m.mstatic
171
      inst
172
      pp_machine_static_declare_name m.mname.node_id
173
      attr
174
      (pp_print_list ~pp_sep:pp_print_comma ~pp_eol:pp_print_comma
175
         (pp_c_var_read m)) m.mstatic
176
      inst
177
      pp_machine_static_link_name m.mname.node_id
178
      inst
179

    
180
  (* TODO: ACSL
181
     we do multiple things:
182
     - provide the semantics of the node as a predicate: function step and reset are associated to ACSL predicate
183
     - the node is associated to a refinement contract, wrt its ACSL sem
184
     - if the node is a regular node associated to a contract, print the contract as function contract.
185
     - do not print anything if this is a contract node
186
  *)
187
  let print_machine_alloc_decl fmt m =
188
    Mod.print_machine_decl_prefix fmt m;
189
    if not (fst (get_stateless_status m)) then
190
      if !Options.static_mem then
191
        (* Static allocation *)
192
        let macro = (m, mk_attribute m, mk_instance m) in
193
        fprintf fmt "%a@,%a@,%a"
194
          print_static_declare_macro macro
195
          print_static_link_macro macro
196
          print_static_alloc_macro macro
197
      else
198
        (* Dynamic allocation *)
199
        fprintf fmt "extern %a;@,extern %a"
200
          print_alloc_prototype (m.mname.node_id, m.mstatic)
201
          print_dealloc_prototype m.mname.node_id
202

    
203
  let print_machine_struct_top_decl_from_header fmt tdecl =
204
    let inode = imported_node_of_top tdecl in
205
    if not inode.nodei_stateless then
206
      (* Declare struct *)
207
      fprintf fmt "%a;"
208
        (pp_machine_memtype_name ~ghost:false) inode.nodei_id
209

    
210
  let print_stateless_C_prototype fmt (name, inputs, outputs) =
211
    let output =
212
      match outputs with
213
      | [hd] -> hd
214
      | _ -> assert false
215
    in
216
    fprintf fmt "%a %s %a"
217
      (pp_basic_c_type ~pp_c_basic_type_desc ~var_opt:None) output.var_type
218
      name
219
      (pp_print_parenthesized pp_c_decl_input_var) inputs
220

    
221
  let print_machine_decl_top_decl_from_header fmt tdecl =
222
    let inode = imported_node_of_top tdecl in
223
    (*Mod.print_machine_decl_prefix fmt m;*)
224
    let prototype = (inode.nodei_id, inode.nodei_inputs, inode.nodei_outputs) in
225
    if inode.nodei_prototype = Some "C" then
226
      if inode.nodei_stateless then
227
        fprintf fmt "extern %a;" print_stateless_C_prototype prototype
228
      else begin
229
        (* TODO: raise proper error *)
230
        Format.eprintf "internal error: print_machine_decl_top_decl_from_header";
231
        assert false
232
      end
233
    else if inode.nodei_stateless then
234
      fprintf fmt "extern %a;" print_stateless_prototype prototype
235
    else
236
      let static_inputs = List.filter (fun v -> v.var_dec_const)
237
          inode.nodei_inputs in
238
      let used name =
239
        List.exists (fun v -> v.var_id = name)
240
          (inode.nodei_inputs @ inode.nodei_outputs) in
241
      let self = mk_new_name used "self" in
242
      let static_prototype = (inode.nodei_id, static_inputs) in
243
      fprintf fmt
244
        "extern %a;@,\
245
         extern %a;@,\
246
         extern %a;@,\
247
         extern %a;"
248
        (print_reset_prototype self) static_prototype
249
        (print_init_prototype self) static_prototype
250
        (print_clear_prototype self) static_prototype
251
        (print_step_prototype self) prototype
252

    
253
  let print_const_top_decl fmt tdecl =
254
    let cdecl = const_of_top tdecl in
255
    fprintf fmt "extern %a;"
256
      (pp_c_type cdecl.const_id)
257
      (if !Options.mpfr && Types.(is_real_type (array_base_type cdecl.const_type))
258
       then Types.dynamic_type cdecl.const_type
259
       else cdecl.const_type)
260

    
261
  let rec pp_c_type_decl filename cpt var fmt tdecl =
262
    match tdecl with
263
    | Tydec_any ->
264
      assert false
265
    | Tydec_int ->
266
      fprintf fmt "int %s" var
267
    | Tydec_real when !Options.mpfr ->
268
      fprintf fmt "%s %s" Mpfr.mpfr_t var
269
    | Tydec_real ->
270
      fprintf fmt "double %s" var
271
    (* | Tydec_float         -> fprintf fmt "float %s" var *)
272
    | Tydec_bool ->
273
      fprintf fmt "_Bool %s" var
274
    | Tydec_clock ty ->
275
      pp_c_type_decl filename cpt var fmt ty
276
    | Tydec_const c ->
277
      fprintf fmt "%s %s" c var
278
    | Tydec_array (d, ty) ->
279
      fprintf fmt "%a[%a]" (pp_c_type_decl filename cpt var) ty pp_c_dimension d
280
    | Tydec_enum tl ->
281
      incr cpt;
282
      fprintf fmt "enum _enum_%s_%d %a %s" (protect_filename filename) !cpt
283
        (pp_print_braced pp_print_string) tl var
284
    | Tydec_struct fl ->
285
      incr cpt;
286
      fprintf fmt "struct _struct_%s_%d %a %s" (protect_filename filename) !cpt
287
        (pp_print_braced ~pp_sep:pp_print_semicolon
288
           (fun fmt (label, tdesc) -> pp_c_type_decl filename cpt label fmt tdesc))
289
        fl var
290

    
291
  (* let print_type_definitions fmt filename =
292
   *   let cpt_type = ref 0 in
293
   *   Hashtbl.iter (fun typ decl ->
294
   *       match typ with
295
   *       | Tydec_const var ->
296
   *         begin match decl.top_decl_desc with
297
   *           | TypeDef tdef ->
298
   *             fprintf fmt "typedef %a;@.@."
299
   *               (pp_c_type_decl filename cpt_type var) tdef.tydef_desc
300
   *           | _ -> assert false
301
   *         end
302
   *       | _ -> ()) type_table *)
303

    
304
  let reset_type_definitions, print_type_definition_top_decl_from_header =
305
    let cpt_type = ref 0 in
306
    (fun () -> cpt_type := 0),
307
    (fun filename fmt tdecl ->
308
       let typ = typedef_of_top tdecl in
309
       fprintf fmt "typedef %a;"
310
         (pp_c_type_decl filename cpt_type typ.tydef_id) typ.tydef_desc)
311

    
312
  (********************************************************************************************)
313
  (*                         MAIN Header Printing functions                                   *)
314
  (********************************************************************************************)
315

    
316
  let print_alloc_header header_fmt basename _prog machines dependencies spec =
317
    (* Include once: start *)
318
    let baseNAME = file_to_module_name basename in
319
    fprintf header_fmt
320
      "@[<v>\
321
       %a@,\
322
       #ifndef _%s_alloc@,\
323
       #define _%s_alloc@,\
324
       @,\
325
       /* Import header from %s */@,\
326
       %a@,\
327
       @,\
328
       %a\
329
       %a\
330
       %a\
331
       #endif\
332
       @]"
333

    
334
      (* Print the svn version number and the supported C standard (C90 or C99) *)
335
      pp_print_version ()
336

    
337
      baseNAME baseNAME
338

    
339
      (* Import the header *)
340
      basename
341
      print_import_prototype
342
      {
343
        local = true;
344
        name = basename;
345
        content = [];
346
        is_stateful = true  (* assuming it is staful *);
347
      }
348

    
349
      (* Print dependencies *)
350
      (pp_print_list
351
         ~pp_open_box:pp_open_vbox0
352
         ~pp_prologue:(pp_print_endcut "/* Import dependencies */")
353
         print_import_alloc_prototype
354
         ~pp_epilogue:pp_print_cutcut) dependencies
355

    
356
      (* Print the struct definitions of all machines. *)
357
      (pp_print_list
358
         ~pp_open_box:pp_open_vbox0
359
         ~pp_prologue:(pp_print_endcut "/* Struct definitions */")
360
         ~pp_sep:pp_print_cutcut
361
         print_machine_struct
362
         ~pp_epilogue:pp_print_cutcut) machines
363

    
364
      (* Print the prototypes of all machines *)
365
      (pp_print_list
366
         ~pp_open_box:pp_open_vbox0
367
         ~pp_prologue:(pp_print_endcut
368
                         "/* Node allocation function/macro prototypes */")
369
         ~pp_sep:pp_print_cutcut
370
         print_machine_alloc_decl
371
         ~pp_epilogue:pp_print_cutcut) machines
372
  (* Include once: end *)
373

    
374
  (* Function called when compiling a lusi file and generating the associated C
375
     header. *)
376
  let print_header_from_header header_fmt basename header =
377
    (* Include once: start *)
378
    let baseNAME = file_to_module_name basename in
379
    let types = get_typedefs header in
380
    let consts = get_consts header in
381
    let nodes = get_imported_nodes header in
382
    let dependencies = get_dependencies header in
383
    reset_type_definitions ();
384
    fprintf header_fmt
385
      "@[<v>\
386
       %a@,\
387
       #ifndef _%s@,\
388
       #define _%s@,\
389
       @,\
390
       /* Import standard library */@,\
391
       %a@,\
392
       @,\
393
       %a\
394
       %a\
395
       %a\
396
       %a\
397
       %a\
398
       %a\
399
       #endif\
400
       @]@."
401

    
402
      (* Print the version number and the supported C standard (C90 or C99) *)
403
      pp_print_version ()
404

    
405
      baseNAME baseNAME
406

    
407
      (* imports standard library definitions (arrow) *)
408
      print_import_standard ()
409

    
410
      (* imports dependencies *)
411
      (pp_print_list
412
         ~pp_open_box:pp_open_vbox0
413
         ~pp_prologue:(pp_print_endcut "/* Import dependencies */")
414
         (fun fmt dep ->
415
            let local, name = dependency_of_top dep in
416
            print_import_prototype fmt
417
              {
418
                local;
419
                name;
420
                content = [];
421
                is_stateful = true (* assuming it is stateful *)
422
              })
423
         ~pp_epilogue:pp_print_cutcut)
424
      dependencies
425

    
426
      (* Print the type definitions from the type table *)
427
      (pp_print_list
428
         ~pp_open_box:pp_open_vbox0
429
         ~pp_prologue:(pp_print_endcut "/* Types definitions */")
430
         (print_type_definition_top_decl_from_header basename)
431
         ~pp_epilogue:pp_print_cutcut)
432
      types
433

    
434
      (* Print the global constant declarations. *)
435
      (pp_print_list
436
         ~pp_open_box:pp_open_vbox0
437
         ~pp_prologue:
438
           (pp_print_endcut
439
              "/* Global constants (declarations, definitions are in C file) */")
440
         print_const_top_decl
441
         ~pp_epilogue:pp_print_cutcut)
442
      consts
443

    
444
      (* MPFR *)
445
      (if !Options.mpfr then
446
         fun fmt () -> fprintf fmt
447
             "/* Global initialization declaration */@,\
448
              extern %a;@,@,\
449
              /* Global clear declaration */@,\
450
              extern %a;@,@,"
451
             print_global_init_prototype baseNAME
452
             print_global_clear_prototype baseNAME
453
       else pp_print_nothing) ()
454

    
455
      (* Print the struct declarations of all machines. *)
456
      (pp_print_list
457
         ~pp_open_box:pp_open_vbox0
458
         ~pp_prologue:(pp_print_endcut "/* Struct declarations */")
459
         print_machine_struct_top_decl_from_header
460
         ~pp_epilogue:pp_print_cutcut)
461
      nodes
462

    
463
      (* Print the prototypes of all machines *)
464
      (pp_print_list
465
         ~pp_open_box:pp_open_vbox0
466
         ~pp_prologue:(pp_print_endcut "/* Nodes declarations */")
467
         ~pp_sep:pp_print_cutcut
468
         print_machine_decl_top_decl_from_header
469
         ~pp_epilogue:pp_print_cutcut)
470
      nodes
471

    
472
end
473
(* Local Variables: *)
474
(* compile-command:"make -C ../../.." *)
475
(* End: *)
(4-4/9)