Project

General

Profile

Download (34.5 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
13
open Format
14
open Lustre_types
15
open Machine_code_types
16
open Corelang
17
open Machine_code_common
18
open C_backend_common
19
module Mpfr = Lustrec_mpfr
20

    
21
module type MODIFIERS_SRC = sig
22
  module GhostProto : MODIFIERS_GHOST_PROTO
23

    
24
  val pp_predicates : formatter -> machine_t list -> unit
25

    
26
  val pp_set_reset_spec : formatter -> ident -> ident -> machine_t -> unit
27

    
28
  val pp_clear_reset_spec : formatter -> ident -> ident -> machine_t -> unit
29

    
30
  val pp_step_spec :
31
    formatter -> machine_t list -> ident -> ident -> machine_t -> unit
32

    
33
  val pp_step_instr_spec :
34
    machine_t -> ident -> ident -> formatter -> instr_t -> unit
35

    
36
  val pp_ghost_parameter : ident -> formatter -> ident option -> unit
37

    
38
  val pp_contract : formatter -> machine_t list -> ident -> ident -> machine_t -> unit
39
end
40

    
41
module EmptyMod = struct
42
  module GhostProto = EmptyGhostProto
43

    
44
  let pp_predicates _ _ = ()
45

    
46
  let pp_set_reset_spec _ _ _ _ = ()
47

    
48
  let pp_clear_reset_spec _ _ _ _ = ()
49

    
50
  let pp_step_spec _ _ _ _ _ = ()
51

    
52
  let pp_step_instr_spec _ _ _ _ _ = ()
53

    
54
  let pp_ghost_parameter _ _ _ = ()
55

    
56
  let pp_contract _ _ _ _ _ = ()
57
end
58

    
59
module Main (Mod : MODIFIERS_SRC) = struct
60
  module Protos = Protos (Mod.GhostProto)
61

    
62
  (********************************************************************************************)
63
  (* Instruction Printing functions *)
64
  (********************************************************************************************)
65

    
66
  (* XXX: UNUSED *)
67
  (* let rec merge_static_loop_profiles lp1 lp2 =
68
   *   match lp1, lp2 with
69
   *   | [], _ ->
70
   *     lp2
71
   *   | _, [] ->
72
   *     lp1
73
   *   | p1 :: q1, p2 :: q2 ->
74
   *     (p1 || p2) :: merge_static_loop_profiles q1 q2 *)
75

    
76
  (* XXX: UNUSED *)
77
  (* Returns a list of bool values, indicating whether the indices must be
78
     static or not *)
79
  (* let rec static_loop_profile v =
80
   *   match v.value_desc with
81
   *   | Cst cst ->
82
   *     static_loop_profile_cst cst
83
   *   | Var _ | ResetFlag ->
84
   *     []
85
   *   | Fun (_, vl) ->
86
   *     List.fold_right
87
   *       (fun v lp -> merge_static_loop_profiles lp (static_loop_profile v))
88
   *       vl []
89
   *   | Array vl ->
90
   *     true
91
   *     ::
92
   *     List.fold_right
93
   *       (fun v lp -> merge_static_loop_profiles lp (static_loop_profile v))
94
   *       vl []
95
   *   | Access (v, _) -> (
96
   *       match static_loop_profile v with [] -> [] | _ :: q -> q)
97
   *   | Power (v, _) ->
98
   *     false :: static_loop_profile v
99
   *
100
   * and static_loop_profile_cst cst =
101
   *   match cst with
102
   *   | Const_array cl ->
103
   *     List.fold_right
104
   *       (fun c lp ->
105
   *          merge_static_loop_profiles lp (static_loop_profile_cst c))
106
   *       cl []
107
   *   | _ ->
108
   *     [] *)
109

    
110
  (* Subsumes C_backend_common.pp_c_val to cope with aggressive substitution
111
     which may yield constant arrays in expressions. Type is needed to correctly
112
     print constant arrays. *)
113
  let pp_c_val m self pp_var fmt v =
114
    pp_value_suffix m self v.value_type [] pp_var fmt v
115

    
116
  let pp_machine_ pp_machine_name fn_name m fmt ?inst self mem =
117
    let name, is_arrow, static =
118
      match inst with
119
      | Some inst ->
120
        let node, static =
121
          try List.assoc inst m.minstances
122
          with Not_found ->
123
            eprintf
124
              "internal error: %s %s %s %s:@."
125
              fn_name
126
              m.mname.node_id
127
              self
128
              inst;
129
            raise Not_found
130
        in
131
        node_name node, Arrow.td_is_arrow node, static
132
      | None ->
133
        m.mname.node_id, false, []
134
    in
135
    let is_arrow_reset = is_arrow && fn_name = "pp_machine_set_reset" in
136
    fprintf
137
      fmt
138
      "%a(%a%s%a)%a;"
139
      (if is_arrow_reset then fun fmt -> fprintf fmt "%s_reset"
140
      else pp_machine_name)
141
      name
142
      (pp_comma_list ~pp_eol:pp_print_comma Dimension.pp)
143
      static
144
      self
145
      (pp_print_option (fun fmt -> fprintf fmt "->%s"))
146
      inst
147
      (if is_arrow_reset then pp_print_nothing else Mod.pp_ghost_parameter mem)
148
      inst
149

    
150
  let pp_machine_set_reset m self mem fmt inst =
151
    pp_machine_
152
      pp_machine_set_reset_name
153
      "pp_machine_set_reset"
154
      m
155
      fmt
156
      ~inst
157
      self
158
      mem
159

    
160
  let pp_machine_clear_reset m self mem fmt =
161
    pp_machine_
162
      pp_machine_clear_reset_name
163
      "pp_machine_clear_reset"
164
      m
165
      fmt
166
      self
167
      mem
168

    
169
  let pp_machine_init m self mem fmt inst =
170
    pp_machine_ pp_machine_init_name "pp_machine_init" m fmt ~inst self mem
171

    
172
  let pp_machine_clear m self mem fmt inst =
173
    pp_machine_ pp_machine_clear_name "pp_machine_clear" m fmt ~inst self mem
174

    
175
  let pp_call m self mem pp_read pp_write fmt i inputs outputs =
176
    try
177
      (* stateful node instance *)
178
      let n, _ = List.assoc i m.minstances in
179
      fprintf
180
        fmt
181
        "%a(%a%a%s->%s)%a;"
182
        pp_machine_step_name
183
        (node_name n)
184
        (pp_comma_list ~pp_eol:pp_print_comma (pp_c_val m self pp_read))
185
        inputs
186
        (pp_comma_list ~pp_eol:pp_print_comma pp_write)
187
        outputs
188
        self
189
        i
190
        (Mod.pp_ghost_parameter mem)
191
        (Some i)
192
    with Not_found ->
193
      (* stateless node instance *)
194
      let n, _ = List.assoc i m.mcalls in
195
      fprintf
196
        fmt
197
        "%a(%a%a);"
198
        pp_machine_step_name
199
        (node_name n)
200
        (pp_comma_list ~pp_eol:pp_print_comma (pp_c_val m self pp_read))
201
        inputs
202
        (pp_comma_list pp_write)
203
        outputs
204

    
205
  let pp_basic_instance_call m self mem =
206
    pp_call m self mem (pp_c_var_read m) (pp_c_var_write m)
207

    
208
  let pp_arrow_call m self mem fmt i outputs =
209
    match outputs with
210
    | [ x ] ->
211
      fprintf
212
        fmt
213
        "%a = %a(%s->%s)%a;"
214
        (pp_c_var_read m)
215
        x
216
        pp_machine_step_name
217
        Arrow.arrow_id
218
        self
219
        i
220
        (Mod.pp_ghost_parameter mem)
221
        (Some i)
222
    | _ ->
223
      assert false
224

    
225
  let pp_instance_call m self mem fmt i inputs outputs =
226
    let pp_offset pp_var indices fmt var =
227
      fprintf
228
        fmt
229
        "%a%a"
230
        pp_var
231
        var
232
        (pp_print_list ~pp_sep:pp_print_nothing (fun fmt -> fprintf fmt "[%s]"))
233
        indices
234
    in
235
    let rec aux indices fmt typ =
236
      if Types.is_array_type typ then
237
        let dim = Types.array_type_dimension typ in
238
        let idx = mk_loop_var m () in
239
        fprintf
240
          fmt
241
          "@[<v 2>{@,int %s;@,for(%s=0;%s<%a;%s++)@,%a @]@,}"
242
          idx
243
          idx
244
          idx
245
          pp_c_dimension
246
          dim
247
          idx
248
          (aux (idx :: indices))
249
          (Types.array_element_type typ)
250
      else
251
        let pp_read = pp_offset (pp_c_var_read m) indices in
252
        let pp_write = pp_offset (pp_c_var_write m) indices in
253
        pp_call m self mem pp_read pp_write fmt i inputs outputs
254
    in
255
    reset_loop_counter ();
256
    aux [] fmt (List.hd inputs).Machine_code_types.value_type
257

    
258
  let rec pp_conditional dependencies m self mem fmt c tl el =
259
    let pp_machine_instrs =
260
      pp_print_list
261
        ~pp_open_box:pp_open_vbox0
262
        ~pp_prologue:pp_print_cut
263
        (pp_machine_instr dependencies m self mem)
264
    in
265
    let pp_cond = pp_c_val m self (pp_c_var_read m) in
266
    match tl, el with
267
    | [], _ :: _ ->
268
      fprintf fmt "@[<v 2>if (!%a) {%a@]@,}" pp_cond c pp_machine_instrs el
269
    | _, [] ->
270
      fprintf fmt "@[<v 2>if (%a) {%a@]@,}" pp_cond c pp_machine_instrs tl
271
    | _, _ ->
272
      fprintf
273
        fmt
274
        "@[<v 2>if (%a) {%a@]@,@[<v 2>} else {%a@]@,}"
275
        pp_cond
276
        c
277
        pp_machine_instrs
278
        tl
279
        pp_machine_instrs
280
        el
281

    
282
  and pp_machine_instr dependencies m self mem fmt instr =
283
    let pp_instr fmt instr =
284
      match get_instr_desc instr with
285
      | MNoReset _ ->
286
        ()
287
      | MSetReset inst ->
288
        pp_machine_set_reset m self mem fmt inst
289
      | MClearReset ->
290
        if not (fst (get_stateless_status m)) then
291
          fprintf
292
            fmt
293
            "%t@,%a"
294
            (pp_machine_clear_reset m self mem)
295
            pp_label
296
            reset_label
297
      | MResetAssign b ->
298
        pp_reset_assign self fmt b
299
      | MLocalAssign (i, v) ->
300
        pp_assign m self (pp_c_var_read m) fmt (i, v)
301
      | MStateAssign (i, v) ->
302
        pp_assign m self (pp_c_var_read m) fmt (i, v)
303
      | MStep ([ i0 ], i, vl)
304
        when Basic_library.is_value_internal_fun
305
               (mk_val (Fun (i, vl)) i0.var_type) ->
306
        pp_machine_instr
307
          dependencies
308
          m
309
          self
310
          mem
311
          fmt
312
          (update_instr_desc
313
             instr
314
             (MLocalAssign (i0, mk_val (Fun (i, vl)) i0.var_type)))
315
      | MStep (il, i, vl) when !Options.mpfr && Mpfr.is_homomorphic_fun i ->
316
        pp_instance_call m self mem fmt i vl il
317
      | MStep ([ i0 ], i, vl) when has_c_prototype i dependencies ->
318
        fprintf
319
          fmt
320
          "%a = %s%a;"
321
          (pp_c_val m self (pp_c_var_read m))
322
          (mk_val (Var i0) i0.var_type)
323
          i
324
          (pp_print_parenthesized (pp_c_val m self (pp_c_var_read m)))
325
          vl
326
      | MStep (il, i, vl) ->
327
        let td, _ = List.assoc i m.minstances in
328
        if Arrow.td_is_arrow td then pp_arrow_call m self mem fmt i il
329
        else pp_basic_instance_call m self mem fmt i vl il
330
      | MBranch (_, []) ->
331
        eprintf
332
          "internal error: C_backend_src.pp_machine_instr %a@."
333
          (pp_instr m)
334
          instr;
335
        assert false
336
      | MBranch (g, hl) ->
337
        if
338
          let t = fst (List.hd hl) in
339
          t = tag_true || t = tag_false
340
        then
341
          (* boolean case, needs special treatment in C because truth value is
342
             not unique *)
343
          (* may disappear if we optimize code by replacing last branch test
344
             with default *)
345
          let tl = try List.assoc tag_true hl with Not_found -> [] in
346
          let el = try List.assoc tag_false hl with Not_found -> [] in
347
          let no_noreset =
348
            List.filter (fun i ->
349
                match i.instr_desc with MNoReset _ -> false | _ -> true)
350
          in
351
          pp_conditional
352
            dependencies
353
            m
354
            self
355
            mem
356
            fmt
357
            g
358
            (no_noreset tl)
359
            (no_noreset el)
360
        else
361
          (* enum type case *)
362
          (*let g_typ = Typing.type_const Location.dummy_loc (Const_tag (fst
363
            (List.hd hl))) in*)
364
          fprintf
365
            fmt
366
            "@[<v 2>switch(%a) {@,%a@,}@]"
367
            (pp_c_val m self (pp_c_var_read m))
368
            g
369
            (pp_print_list
370
               ~pp_open_box:pp_open_vbox0
371
               (pp_machine_branch dependencies m self mem))
372
            hl
373
      | MSpec s ->
374
        fprintf fmt "@[/*@@ %s */@]@ " s
375
      | MComment s ->
376
        fprintf fmt "/*%s*/@ " s
377
    in
378
    fprintf fmt "%a%a" pp_instr instr (Mod.pp_step_instr_spec m self mem) instr
379

    
380
  and pp_machine_branch dependencies m self mem fmt (t, h) =
381
    fprintf
382
      fmt
383
      "@[<v 2>case %a:@,%a@,break;@]"
384
      pp_c_tag
385
      t
386
      (pp_print_list
387
         ~pp_open_box:pp_open_vbox0
388
         (pp_machine_instr dependencies m self mem))
389
      h
390

    
391
  (* let pp_machine_nospec_instr dependencies m self fmt instr =
392
   *   pp_machine_instr dependencies m self fmt instr
393
   *
394
   * let pp_machine_step_instr dependencies m self mem fmt instr =
395
   *   fprintf fmt "%a%a"
396
   *     (pp_machine_instr dependencies m self) instr
397
   *     (Mod.pp_step_instr_spec m self mem) instr *)
398

    
399
  (********************************************************************************************)
400
  (* C file Printing functions *)
401
  (********************************************************************************************)
402

    
403
  let pp_const_def fmt tdecl =
404
    let cdecl = const_of_top tdecl in
405
    if !Options.mpfr && Types.(is_real_type (array_base_type cdecl.const_type))
406
    then
407
      fprintf
408
        fmt
409
        "%a;"
410
        (pp_c_type cdecl.const_id)
411
        (Types.dynamic_type cdecl.const_type)
412
    else
413
      fprintf
414
        fmt
415
        "%a = %a;"
416
        (pp_c_type cdecl.const_id)
417
        cdecl.const_type
418
        pp_c_const
419
        cdecl.const_value
420

    
421
  let pp_alloc_instance fmt (i, (m, static)) =
422
    fprintf
423
      fmt
424
      "_alloc->%s = %a %a;"
425
      i
426
      pp_machine_alloc_name
427
      (node_name m)
428
      (pp_print_parenthesized Dimension.pp)
429
      static
430

    
431
  let pp_dealloc_instance fmt (i, (m, _)) =
432
    fprintf fmt "%a (_alloc->%s);" pp_machine_dealloc_name (node_name m) i
433

    
434
  let const_locals m =
435
    List.filter (fun vdecl -> vdecl.var_dec_const) m.mstep.step_locals
436

    
437
  let pp_c_decl_array_mem self fmt id =
438
    fprintf
439
      fmt
440
      "%a = (%a) (%s->_reg.%s)"
441
      (pp_c_type (sprintf "(*%s)" id.var_id))
442
      id.var_type
443
      (pp_c_type "(*)")
444
      id.var_type
445
      self
446
      id.var_id
447

    
448
  let pp_alloc_const fmt m =
449
    pp_print_list
450
      ~pp_sep:(pp_print_endcut ";")
451
      ~pp_eol:(pp_print_endcut ";")
452
      (pp_c_decl_local_var m)
453
      fmt
454
      (const_locals m)
455

    
456
  let pp_alloc_array fmt vdecl =
457
    let base_type = Types.array_base_type vdecl.var_type in
458
    let size_types = Types.array_type_multi_dimension vdecl.var_type in
459
    let size_type = Dimension.multi_product vdecl.var_loc size_types in
460
    fprintf
461
      fmt
462
      "_alloc->_reg.%s = (%a*) malloc((%a)*sizeof(%a));@,assert(_alloc->%s);"
463
      vdecl.var_id
464
      (pp_c_type "")
465
      base_type
466
      Dimension.pp
467
      size_type
468
      (pp_c_type "")
469
      base_type
470
      vdecl.var_id
471

    
472
  let pp_dealloc_array fmt vdecl =
473
    fprintf fmt "free (_alloc->_reg.%s);" vdecl.var_id
474

    
475
  let array_mems m =
476
    List.filter (fun v -> Types.is_array_type v.var_type) m.mmemory
477

    
478
  let pp_alloc_code fmt m =
479
    fprintf
480
      fmt
481
      "%a *_alloc;@,\
482
       _alloc = (%a *) malloc(sizeof(%a));@,\
483
       assert(_alloc);@,\
484
       %a%areturn _alloc;"
485
      (pp_machine_memtype_name ~ghost:false)
486
      m.mname.node_id
487
      (pp_machine_memtype_name ~ghost:false)
488
      m.mname.node_id
489
      (pp_machine_memtype_name ~ghost:false)
490
      m.mname.node_id
491
      (pp_print_list ~pp_sep:pp_print_nothing pp_alloc_array)
492
      (array_mems m)
493
      (pp_print_list ~pp_sep:pp_print_nothing pp_alloc_instance)
494
      m.minstances
495

    
496
  let pp_dealloc_code fmt m =
497
    fprintf
498
      fmt
499
      "%a%afree (_alloc);@,return;"
500
      (pp_print_list ~pp_sep:pp_print_nothing pp_dealloc_array)
501
      (array_mems m)
502
      (pp_print_list ~pp_sep:pp_print_nothing pp_dealloc_instance)
503
      m.minstances
504

    
505
  (* let print_stateless_init_code fmt m self =
506
   *   let minit = List.map (fun i -> match get_instr_desc i with MReset i -> i | _ -> assert false) m.minit in
507
   *   let array_mems = List.filter (fun v -> Types.is_array_type v.var_type) m.mmemory in
508
   *   fprintf fmt "@[<v 2>%a {@,%a%t%a%t%a%treturn;@]@,}@.@."
509
   *     (print_init_prototype self) (m.mname.node_id, m.mstatic)
510
   *     (\* array mems *\)
511
   *     (Utils.fprintf_list ~sep:";@," (pp_c_decl_array_mem self)) array_mems
512
   *     (Utils.pp_final_char_if_non_empty ";@," array_mems)
513
   *     (\* memory initialization *\)
514
   *     (Utils.fprintf_list ~sep:"@," (pp_initialize m self (pp_c_var_read m))) m.mmemory
515
   *     (Utils.pp_newline_if_non_empty m.mmemory)
516
   *     (\* sub-machines initialization *\)
517
   *     (Utils.fprintf_list ~sep:"@," (pp_machine_init m self)) minit
518
   *     (Utils.pp_newline_if_non_empty m.minit)
519
   *
520
   * let print_stateless_clear_code fmt m self =
521
   *   let minit = List.map (fun i -> match get_instr_desc i with MReset i -> i | _ -> assert false) m.minit in
522
   *   let array_mems = List.filter (fun v -> Types.is_array_type v.var_type) m.mmemory in
523
   *   fprintf fmt "@[<v 2>%a {@,%a%t%a%t%a%treturn;@]@,}@.@."
524
   *     (print_clear_prototype self) (m.mname.node_id, m.mstatic)
525
   *     (\* array mems *\)
526
   *     (Utils.fprintf_list ~sep:";@," (pp_c_decl_array_mem self)) array_mems
527
   *     (Utils.pp_final_char_if_non_empty ";@," array_mems)
528
   *     (\* memory clear *\)
529
   *     (Utils.fprintf_list ~sep:"@," (pp_clear m self (pp_c_var_read m))) m.mmemory
530
   *     (Utils.pp_newline_if_non_empty m.mmemory)
531
   *     (\* sub-machines clear*\)
532
   *     (Utils.fprintf_list ~sep:"@," (pp_machine_clear m self)) minit
533
   *     (Utils.pp_newline_if_non_empty m.minit) *)
534

    
535
  let pp_c_check m self fmt (loc, check) =
536
    fprintf
537
      fmt
538
      "@[<v>%a@,assert (%a);@]"
539
      Location.pp_c
540
      loc
541
      (pp_c_val m self (pp_c_var_read m))
542
      check
543

    
544
  let pp_print_function ~pp_prototype ~prototype ?(is_contract = false)
545
      ?(pp_spec = pp_print_nothing)
546
      ?(pp_local = pp_print_nothing) ?(base_locals = [])
547
      ?(pp_array_mem = pp_print_nothing) ?(array_mems = [])
548
      ?(pp_init_mpfr_local = pp_print_nothing)
549
      ?(pp_clear_mpfr_local = pp_print_nothing) ?(mpfr_locals = [])
550
      ?(pp_check = pp_print_nothing) ?(checks = [])
551
      ?(pp_extra = pp_print_nothing)
552
      ?(pp_instr = fun fmt _ -> pp_print_nothing fmt ()) ?(instrs = []) fmt =
553
    fprintf
554
      fmt
555
      "%t%a@[<v 2>%a {@,%a%a%a%a%a%a%areturn;@]@,}%t"
556
      (fun fmt -> if is_contract then fprintf fmt "@[<v 2>/*%@ ghost@;")
557
      pp_spec
558
      ()
559
      pp_prototype
560
      prototype
561
      (* locals *)
562
      (pp_print_list
563
         ~pp_open_box:pp_open_vbox0
564
         ~pp_sep:pp_print_semicolon
565
         ~pp_eol:pp_print_semicolon
566
         pp_local)
567
      base_locals
568
      (* array mems *)
569
      (pp_print_list
570
         ~pp_open_box:pp_open_vbox0
571
         ~pp_sep:pp_print_semicolon
572
         ~pp_eol:pp_print_semicolon
573
         pp_array_mem)
574
      array_mems
575
      (* locals initialization *)
576
      (pp_print_list ~pp_epilogue:pp_print_cut pp_init_mpfr_local)
577
      (mpfr_vars mpfr_locals)
578
      (* check assertions *)
579
      (pp_print_list pp_check)
580
      checks
581
      (* instrs *)
582
      (pp_print_list
583
         ~pp_open_box:pp_open_vbox0
584
         ~pp_epilogue:pp_print_cut
585
         pp_instr)
586
      instrs
587
      (* locals clear *)
588
      (pp_print_list ~pp_epilogue:pp_print_cut pp_clear_mpfr_local)
589
      (mpfr_vars mpfr_locals) (* extra *)
590
      pp_extra
591
      ()
592
      (fun fmt -> if is_contract then fprintf fmt "@]@;*/")
593

    
594
  let node_of_machine m =
595
    {
596
      top_decl_desc = Node m.mname;
597
      top_decl_loc = Location.dummy;
598
      top_decl_owner = "";
599
      top_decl_itf = false;
600
    }
601

    
602
  let pp_stateless_code machines dependencies fmt m =
603
    let self = "__ERROR__" in
604
    let is_contract = m.mis_contract in
605
    if not (!Options.ansi && is_generic_node (node_of_machine m)) then
606
      (* C99 code *)
607
      pp_print_function
608
        ~is_contract
609
        ~pp_spec:(fun fmt () -> Mod.pp_step_spec fmt machines self self m)
610
        ~pp_prototype:Protos.pp_stateless_prototype
611
        ~prototype:(m.mname.node_id, m.mstep.step_inputs, m.mstep.step_outputs)
612
        ~pp_local:(pp_c_decl_local_var m)
613
        ~base_locals:m.mstep.step_locals
614
        ~pp_init_mpfr_local:(pp_initialize m self (pp_c_var_read m))
615
        ~pp_clear_mpfr_local:(pp_clear m self (pp_c_var_read m))
616
        ~mpfr_locals:m.mstep.step_locals
617
        ~pp_check:(pp_c_check m self)
618
        ~checks:m.mstep.step_checks
619
        ~pp_instr:(pp_machine_instr dependencies m self self)
620
        ~instrs:m.mstep.step_instrs
621
        ~pp_extra:(fun fmt () -> Mod.pp_contract fmt machines self self m)
622
        fmt
623
    else
624
      (* C90 code *)
625
      let gen_locals, base_locals =
626
        List.partition
627
          (fun v -> Types.is_generic_type v.var_type)
628
          m.mstep.step_locals
629
      in
630
      let gen_calls =
631
        List.map
632
          (fun e ->
633
            let id, _, _ = call_of_expr e in
634
            mk_call_var_decl e.expr_loc id)
635
          m.mname.node_gencalls
636
      in
637
      pp_print_function
638
        ~is_contract
639
        ~pp_prototype:Protos.pp_stateless_prototype
640
        ~prototype:
641
          ( m.mname.node_id,
642
            m.mstep.step_inputs @ gen_locals @ gen_calls,
643
            m.mstep.step_outputs )
644
        ~pp_local:(pp_c_decl_local_var m)
645
        ~base_locals
646
        ~pp_init_mpfr_local:(pp_initialize m self (pp_c_var_read m))
647
        ~pp_clear_mpfr_local:(pp_clear m self (pp_c_var_read m))
648
        ~mpfr_locals:m.mstep.step_locals
649
        ~pp_check:(pp_c_check m self)
650
        ~checks:m.mstep.step_checks
651
        ~pp_instr:(pp_machine_instr dependencies m self self)
652
        ~instrs:m.mstep.step_instrs
653
        ~pp_extra:(fun fmt () -> Mod.pp_contract fmt machines self self m)
654
        fmt
655

    
656
  let pp_clear_reset_code dependencies self mem fmt m =
657
    pp_print_function
658
      ~pp_spec:(fun fmt () -> Mod.pp_clear_reset_spec fmt self mem m)
659
      ~pp_prototype:(Protos.pp_clear_reset_prototype self mem)
660
      ~prototype:(m.mname.node_id, m.mstatic)
661
      ~pp_local:(pp_c_decl_local_var m)
662
      ~base_locals:(const_locals m)
663
      ~pp_instr:(pp_machine_instr dependencies m self mem)
664
      ~instrs:
665
        [
666
          mk_branch
667
            (mk_val ResetFlag Type_predef.type_bool)
668
            [ "true", mkinstr (MResetAssign false) :: m.minit ];
669
        ]
670
      fmt
671

    
672
  let pp_set_reset_code dependencies self mem fmt m =
673
    pp_print_function
674
      ~pp_spec:(fun fmt () -> Mod.pp_set_reset_spec fmt self mem m)
675
      ~pp_prototype:(Protos.pp_set_reset_prototype self mem)
676
      ~prototype:(m.mname.node_id, m.mstatic)
677
      ~pp_instr:(pp_machine_instr dependencies m self mem)
678
      ~instrs:[ mkinstr (MResetAssign true) ]
679
      fmt
680

    
681
  let pp_init_code self fmt m =
682
    let minit =
683
      List.map
684
        (fun i ->
685
          match get_instr_desc i with MSetReset i -> i | _ -> assert false)
686
        m.minit
687
    in
688
    pp_print_function
689
      ~pp_prototype:(Protos.pp_init_prototype self)
690
      ~prototype:(m.mname.node_id, m.mstatic)
691
      ~pp_array_mem:(pp_c_decl_array_mem self)
692
      ~array_mems:(array_mems m)
693
      ~pp_init_mpfr_local:(pp_initialize m self (pp_c_var_read m))
694
      ~mpfr_locals:m.mmemory
695
      ~pp_extra:(fun fmt () ->
696
        pp_print_list
697
          ~pp_open_box:pp_open_vbox0
698
          ~pp_epilogue:pp_print_cut
699
          (pp_machine_init m self self)
700
          fmt
701
          minit)
702
      fmt
703

    
704
  let pp_clear_code self fmt m =
705
    let minit =
706
      List.map
707
        (fun i ->
708
          match get_instr_desc i with MSetReset i -> i | _ -> assert false)
709
        m.minit
710
    in
711
    pp_print_function
712
      ~pp_prototype:(Protos.pp_clear_prototype self)
713
      ~prototype:(m.mname.node_id, m.mstatic)
714
      ~pp_array_mem:(pp_c_decl_array_mem self)
715
      ~array_mems:(array_mems m)
716
      ~pp_clear_mpfr_local:(pp_clear m self (pp_c_var_read m))
717
      ~mpfr_locals:m.mmemory
718
      ~pp_extra:(fun fmt () ->
719
        pp_print_list
720
          ~pp_open_box:pp_open_vbox0
721
          ~pp_epilogue:pp_print_cut
722
          (pp_machine_clear m self self)
723
          fmt
724
          minit)
725
      fmt
726

    
727
  let pp_step_code machines dependencies self mem fmt m =
728
    if not (!Options.ansi && is_generic_node (node_of_machine m)) then
729
      (* C99 code *)
730
      pp_print_function
731
        ~pp_spec:(fun fmt () -> Mod.pp_step_spec fmt machines self mem m)
732
        ~pp_prototype:(Protos.pp_step_prototype self mem)
733
        ~prototype:(m.mname.node_id, m.mstep.step_inputs, m.mstep.step_outputs)
734
        ~pp_local:(pp_c_decl_local_var m)
735
        ~base_locals:m.mstep.step_locals
736
        ~pp_array_mem:(pp_c_decl_array_mem self)
737
        ~array_mems:(array_mems m)
738
        ~pp_init_mpfr_local:(pp_initialize m self (pp_c_var_read m))
739
        ~pp_clear_mpfr_local:(pp_clear m self (pp_c_var_read m))
740
        ~mpfr_locals:m.mstep.step_locals
741
        ~pp_check:(pp_c_check m self)
742
        ~checks:m.mstep.step_checks
743
        ~pp_instr:(pp_machine_instr dependencies m self mem)
744
        ~instrs:m.mstep.step_instrs
745
        ~pp_extra:(fun fmt () -> Mod.pp_contract fmt machines self mem m)
746
        fmt
747
    else
748
      (* C90 code *)
749
      let gen_locals, base_locals =
750
        List.partition
751
          (fun v -> Types.is_generic_type v.var_type)
752
          m.mstep.step_locals
753
      in
754
      let gen_calls =
755
        List.map
756
          (fun e ->
757
            let id, _, _ = call_of_expr e in
758
            mk_call_var_decl e.expr_loc id)
759
          m.mname.node_gencalls
760
      in
761
      pp_print_function
762
        ~pp_spec:(fun fmt () -> Mod.pp_step_spec fmt machines self mem m)
763
        ~pp_prototype:(Protos.pp_step_prototype self mem)
764
        ~prototype:
765
          ( m.mname.node_id,
766
            m.mstep.step_inputs @ gen_locals @ gen_calls,
767
            m.mstep.step_outputs )
768
        ~pp_local:(pp_c_decl_local_var m)
769
        ~base_locals
770
        ~pp_init_mpfr_local:(pp_initialize m self (pp_c_var_read m))
771
        ~pp_clear_mpfr_local:(pp_clear m self (pp_c_var_read m))
772
        ~mpfr_locals:m.mstep.step_locals
773
        ~pp_check:(pp_c_check m self)
774
        ~checks:m.mstep.step_checks
775
        ~pp_instr:(pp_machine_instr dependencies m self mem)
776
        ~instrs:m.mstep.step_instrs
777
        ~pp_extra:(fun fmt () -> Mod.pp_contract fmt machines self mem m)
778
        fmt
779

    
780
  (********************************************************************************************)
781
  (* MAIN C file Printing functions *)
782
  (********************************************************************************************)
783

    
784
  let pp_const_initialize m pp_var fmt const =
785
    let var =
786
      Machine_code_common.mk_val
787
        (Var (Corelang.var_decl_of_const const))
788
        const.const_type
789
    in
790
    let rec aux indices value fmt typ =
791
      if Types.is_array_type typ then
792
        let dim = Types.array_type_dimension typ in
793
        let szl = Utils.enumerate (Dimension.size_const dim) in
794
        let typ' = Types.array_element_type typ in
795
        let value =
796
          match value with Const_array ca -> List.nth ca | _ -> assert false
797
        in
798
        pp_print_list
799
          (fun fmt i -> aux (string_of_int i :: indices) (value i) fmt typ')
800
          fmt
801
          szl
802
      else
803
        let indices = List.rev indices in
804
        let pp_var_suffix fmt var =
805
          fprintf fmt "%a%a" (pp_c_val m "" pp_var) var pp_array_suffix indices
806
        in
807
        fprintf
808
          fmt
809
          "%a@,%a"
810
          (Mpfr.pp_inject_init pp_var_suffix)
811
          var
812
          (Mpfr.pp_inject_real pp_var_suffix pp_c_const)
813
          (var, value)
814
    in
815
    reset_loop_counter ();
816
    aux [] const.const_value fmt const.const_type
817

    
818
  let pp_const_clear pp_var fmt const =
819
    let m = Machine_code_common.empty_machine in
820
    let var = Corelang.var_decl_of_const const in
821
    let rec aux indices fmt typ =
822
      if Types.is_array_type typ then
823
        let dim = Types.array_type_dimension typ in
824
        let idx = mk_loop_var m () in
825
        fprintf
826
          fmt
827
          "@[<v 2>{@,int %s;@,for(%s=0;%s<%a;%s++)@,%a @]@,}"
828
          idx
829
          idx
830
          idx
831
          pp_c_dimension
832
          dim
833
          idx
834
          (aux (idx :: indices))
835
          (Types.array_element_type typ)
836
      else
837
        let indices = List.rev indices in
838
        let pp_var_suffix fmt var =
839
          fprintf fmt "%a%a" (pp_c_var m "" pp_var) var pp_array_suffix indices
840
        in
841
        Mpfr.pp_inject_clear pp_var_suffix fmt var
842
    in
843
    reset_loop_counter ();
844
    aux [] fmt var.var_type
845

    
846
  let pp_import_init fmt dep =
847
    let baseNAME = file_to_module_name dep.name in
848
    fprintf fmt "%a();" pp_global_init_name baseNAME
849

    
850
  let pp_import_clear fmt dep =
851
    let baseNAME = file_to_module_name dep.name in
852
    fprintf fmt "%a();" pp_global_clear_name baseNAME
853

    
854
  let pp_global_init_code fmt (basename, prog, dependencies) =
855
    let baseNAME = file_to_module_name basename in
856
    let constants = List.map const_of_top (get_consts prog) in
857
    fprintf
858
      fmt
859
      "@[<v 2>%a {@,\
860
       static %s init = 0;@,\
861
       @[<v 2>if (!init) { @,\
862
       init = 1;%a%a@]@,\
863
       }@,\
864
       return;@]@,\
865
       }"
866
      pp_global_init_prototype
867
      baseNAME
868
      (pp_c_basic_type_desc Type_predef.type_bool)
869
      (* constants *)
870
      (pp_print_list
871
         ~pp_prologue:pp_print_cut
872
         (pp_const_initialize empty_machine (pp_c_var_read empty_machine)))
873
      (mpfr_consts constants)
874
      (* dependencies initialization *)
875
      (pp_print_list ~pp_prologue:pp_print_cut pp_import_init)
876
      (List.filter (fun dep -> dep.local) dependencies)
877

    
878
  let pp_global_clear_code fmt (basename, prog, dependencies) =
879
    let baseNAME = file_to_module_name basename in
880
    let constants = List.map const_of_top (get_consts prog) in
881
    fprintf
882
      fmt
883
      "@[<v 2>%a {@,\
884
       static %s clear = 0;@,\
885
       @[<v 2>if (!clear) { @,\
886
       clear = 1;%a%a@]@,\
887
       }@,\
888
       return;@]@,\
889
       }"
890
      pp_global_clear_prototype
891
      baseNAME
892
      (pp_c_basic_type_desc Type_predef.type_bool)
893
      (* constants *)
894
      (pp_print_list
895
         ~pp_prologue:pp_print_cut
896
         (pp_const_clear (pp_c_var_read empty_machine)))
897
      (mpfr_consts constants)
898
      (* dependencies initialization *)
899
      (pp_print_list ~pp_prologue:pp_print_cut pp_import_clear)
900
      (List.filter (fun dep -> dep.local) dependencies)
901

    
902
  let pp_alloc_function fmt m =
903
    if not !Options.static_mem then
904
      (* Alloc functions, only if non static mode *)
905
      fprintf
906
        fmt
907
        "@[<v 2>%a {@,%a%a@]@,}@,@[<v 2>%a {@,%a%a@]@,@,"
908
        pp_alloc_prototype
909
        (m.mname.node_id, m.mstatic)
910
        pp_alloc_const
911
        m
912
        pp_alloc_code
913
        m
914
        pp_dealloc_prototype
915
        m.mname.node_id
916
        pp_alloc_const
917
        m
918
        pp_dealloc_code
919
        m
920

    
921
  let pp_mpfr_code self fmt m =
922
    if !Options.mpfr then
923
      fprintf
924
        fmt
925
        "@,@[<v>%a@,%a@]"
926
        (* Init function *)
927
        (pp_init_code self)
928
        m
929
        (* Clear function *)
930
        (pp_clear_code self)
931
        m
932

    
933
  (* TODO: ACSL - a contract machine shall not be directly printed in the C
934
     source - but a regular machine associated to a contract machine shall
935
     integrate the associated statements, updating its memories, at the end of
936
     the function body. - last one may print intermediate comment/acsl if/when
937
     they are present in the sequence of instruction *)
938
  let pp_machine machines dependencies fmt m =
939
    if fst (get_stateless_status m) then
940
      (* Step function *)
941
      pp_stateless_code machines dependencies fmt m
942
    else
943
      let self = mk_self m in
944
      let mem = mk_mem m in
945
      fprintf
946
        fmt
947
        "@[<v>%a%a@,@,%a@,@,%a%a@]"
948
        pp_alloc_function
949
        m
950
        (* Reset functions *)
951
        (pp_clear_reset_code dependencies self mem)
952
        m
953
        (pp_set_reset_code dependencies self mem)
954
        m
955
        (* Step function *)
956
        (pp_step_code machines dependencies self mem)
957
        m
958
        (pp_mpfr_code self)
959
        m
960

    
961
  let pp_import_standard source_fmt () =
962
    fprintf
963
      source_fmt
964
      "@[<v>#include <assert.h>@,%a%a%a@]"
965
      (if Machine_types.has_machine_type () then
966
       pp_print_endcut "#include <stdint.h>"
967
      else pp_print_nothing)
968
      ()
969
      (if not !Options.static_mem then pp_print_endcut "#include <stdlib.h>"
970
      else pp_print_nothing)
971
      ()
972
      (if !Options.mpfr then pp_print_endcut "#include <mpfr.h>"
973
      else pp_print_nothing)
974
      ()
975

    
976
  let pp_extern_alloc_prototype fmt ind =
977
    let static = List.filter (fun v -> v.var_dec_const) ind.nodei_inputs in
978
    fprintf
979
      fmt
980
      "extern %a;@,extern %a;"
981
      pp_alloc_prototype
982
      (ind.nodei_id, static)
983
      pp_dealloc_prototype
984
      ind.nodei_id
985

    
986
  let pp_lib_c source_fmt basename prog machines dependencies =
987
    fprintf
988
      source_fmt
989
      "@[<v>%a%a@,@,%a@,%a%a%a%a%a%a%a@]@."
990
      pp_import_standard
991
      ()
992
      pp_import_prototype
993
      {
994
        local = true;
995
        name = basename;
996
        content = [];
997
        is_stateful = true (* assuming it is stateful *);
998
      }
999
      (* Print the svn version number and the supported C standard (C90 or C99) *)
1000
      pp_print_version
1001
      ()
1002
      (* Print dependencies *)
1003
      (pp_print_list
1004
         ~pp_open_box:pp_open_vbox0
1005
         ~pp_prologue:(pp_print_endcut "/* Import dependencies */")
1006
         pp_import_prototype
1007
         ~pp_epilogue:pp_print_cutcut)
1008
      dependencies
1009
      (* Print consts *)
1010
      (pp_print_list
1011
         ~pp_open_box:pp_open_vbox0
1012
         ~pp_prologue:(pp_print_endcut "/* Global constants (definitions) */")
1013
         pp_const_def
1014
         ~pp_epilogue:pp_print_cutcut)
1015
      (get_consts prog)
1016
      (* MPFR *)
1017
      (if !Options.mpfr then fun fmt () ->
1018
       fprintf
1019
         fmt
1020
         "@[<v>/* Global constants initialization */@,\
1021
          %a@,\
1022
          @,\
1023
          /* Global constants clearing */@,\
1024
          %a@]@,\
1025
          @,"
1026
         pp_global_init_code
1027
         (basename, prog, dependencies)
1028
         pp_global_clear_code
1029
         (basename, prog, dependencies)
1030
      else pp_print_nothing)
1031
      ()
1032
      (if not !Options.static_mem then fun fmt () ->
1033
       fprintf
1034
         fmt
1035
         "@[<v>%a%a@]@,@,"
1036
         (pp_print_list
1037
            ~pp_open_box:pp_open_vbox0
1038
            ~pp_epilogue:pp_print_cut
1039
            ~pp_prologue:
1040
              (pp_print_endcut "/* External allocation function prototypes */")
1041
            (fun fmt dep ->
1042
              pp_print_list
1043
                ~pp_open_box:pp_open_vbox0
1044
                ~pp_epilogue:pp_print_cut
1045
                pp_extern_alloc_prototype
1046
                fmt
1047
                (List.filter_map
1048
                   (fun decl ->
1049
                     match decl.top_decl_desc with
1050
                     | ImportedNode ind when not ind.nodei_stateless ->
1051
                       Some ind
1052
                     | _ ->
1053
                       None)
1054
                   dep.content)))
1055
         dependencies
1056
         (pp_print_list
1057
            ~pp_open_box:pp_open_vbox0
1058
            ~pp_prologue:
1059
              (pp_print_endcut "/* Node allocation function prototypes */")
1060
            ~pp_sep:pp_print_cutcut
1061
            (fun fmt m ->
1062
              fprintf
1063
                fmt
1064
                "%a;@,%a;"
1065
                pp_alloc_prototype
1066
                (m.mname.node_id, m.mstatic)
1067
                pp_dealloc_prototype
1068
                m.mname.node_id))
1069
         machines
1070
      else pp_print_nothing)
1071
      ()
1072
      (* Print the struct definitions of all machines. *)
1073
      (pp_print_list
1074
         ~pp_open_box:pp_open_vbox0
1075
         ~pp_prologue:(pp_print_endcut "/* Struct definitions */")
1076
         ~pp_sep:pp_print_cutcut
1077
         pp_machine_struct
1078
         ~pp_epilogue:pp_print_cutcut)
1079
      machines
1080
      (* Print the spec predicates *) Mod.pp_predicates
1081
      machines
1082
      (* Print nodes one by one (in the previous order) *)
1083
      (pp_print_list
1084
         ~pp_open_box:pp_open_vbox0
1085
         ~pp_sep:pp_print_cutcut
1086
         (pp_machine machines dependencies))
1087
      machines
1088
end
1089

    
1090
(* Local Variables: *)
1091
(* compile-command:"make -C ../../.." *)
1092
(* End: *)
(17-17/18)