Project

General

Profile

Download (17.7 KB) Statistics
| Branch: | Tag: | Revision:
1
open Format
2
open LustreSpec
3
open Corelang
4
open Machine_code
5
open C_backend_common
6

    
7
type pp_instr = (string * bool * LustreSpec.top_decl list) list ->
8
         Machine_code.machine_t ->
9
         string -> Format.formatter -> Machine_code.instr_t -> unit
10

    
11
module type MODIFIERS_SRC =
12
sig
13
  val print_step_code_prefix : pp_instr -> bool -> Format.formatter -> machine_t -> unit
14
  val print_step_code_midfix : pp_instr -> bool -> Format.formatter -> machine_t -> unit
15
  val print_step_code_postfix : pp_instr -> bool -> Format.formatter -> machine_t -> unit
16
  val print_init_code_postfix : pp_instr -> Format.formatter -> machine_t -> unit
17
  val print_instr_prefix : Machine_code.machine_t -> Format.formatter -> Machine_code.instr_t -> unit
18
  val print_instr_postfix : Machine_code.machine_t -> Format.formatter -> Machine_code.instr_t -> unit
19
end
20

    
21
module EmptyMod =
22
struct
23
  let print_step_code_prefix f x fmt m = ()
24
  let print_step_code_midfix f x fmt m = ()
25
  let print_step_code_postfix f x fmt m = ()
26
  let print_init_code_postfix f fmt m = ()
27
  let print_instr_prefix m fmt x = ()
28
  let print_instr_postfix m fmt x = ()
29
end
30

    
31

    
32
(********************************************************************************************)
33
(*                    Instruction Printing functions                                        *)
34
(********************************************************************************************)
35

    
36
(* Computes the depth to which multi-dimension array assignments should be expanded.
37
   It equals the maximum number of nested static array constructions accessible from root [v].
38
*)
39
let rec expansion_depth v =
40
 match v with
41
 | Cst (Const_array cl) -> 1 + List.fold_right (fun c -> max (expansion_depth (Cst c))) cl 0
42
 | Cst _
43
 | LocalVar _
44
 | StateVar _  -> 0
45
 | Fun (_, vl) -> List.fold_right (fun v -> max (expansion_depth v)) vl 0
46
 | Array vl    -> 1 + List.fold_right (fun v -> max (expansion_depth v)) vl 0
47
 | Access (v, i) -> max 0 (expansion_depth v - 1)
48
 | Power (v, n)  -> 0 (*1 + expansion_depth v*)
49

    
50
type loop_index = LVar of ident | LInt of int ref
51

    
52
(* Computes the list of nested loop variables together with their dimension bounds.
53
   - LInt r stands for loop expansion (no loop variable, but int loop index)
54
   - LVar v stands for loop variable v
55
*)
56
let rec mk_loop_variables m ty depth =
57
 match (Types.repr ty).Types.tdesc, depth with
58
 | Types.Tarray (d, ty'), 0       ->
59
   let v = mk_loop_var m () in
60
   (d, LVar v) :: mk_loop_variables m ty' 0
61
 | Types.Tarray (d, ty'), _       ->
62
   let r = ref (-1) in
63
   (d, LInt r) :: mk_loop_variables m ty' (depth - 1)
64
 | _                    , 0       -> []
65
 | _                              -> assert false
66

    
67
let reorder_loop_variables loop_vars =
68
  let (int_loops, var_loops) = 
69
    List.partition (function (d, LInt _) -> true | _ -> false) loop_vars 
70
  in
71
  var_loops @ int_loops
72
    
73
(* Prints a one loop variable suffix for arrays *)
74
let pp_loop_var fmt lv =
75
 match snd lv with
76
 | LVar v -> fprintf fmt "[%s]" v
77
 | LInt r -> fprintf fmt "[%d]" !r
78

    
79
(* Prints a suffix of loop variables for arrays *)
80
let pp_suffix fmt loop_vars =
81
 Utils.fprintf_list ~sep:"" pp_loop_var fmt loop_vars
82

    
83
(* Prints a [value] indexed by the suffix list [loop_vars] *)
84
let rec pp_value_suffix self loop_vars pp_value fmt value =
85
 match loop_vars, value with
86
 | (_, LInt r) :: q, Array vl     ->
87
   pp_value_suffix self q pp_value fmt (List.nth vl !r)
88
 | _           :: q, Power (v, n) ->
89
   pp_value_suffix self loop_vars pp_value fmt v
90
 | _               , Fun (n, vl)  ->
91
   Basic_library.pp_c n (pp_value_suffix self loop_vars pp_value) fmt vl
92
 | _               , _            ->
93
   let pp_var_suffix fmt v = fprintf fmt "%a%a" pp_value v pp_suffix loop_vars in
94
   pp_c_val self pp_var_suffix fmt value
95

    
96
(* type_directed assignment: array vs. statically sized type
97
   - [var_type]: type of variable to be assigned
98
   - [var_name]: name of variable to be assigned
99
   - [value]: assigned value
100
   - [pp_var]: printer for variables
101
*)
102
let pp_assign m self pp_var fmt var_type var_name value =
103
  let depth = expansion_depth value in
104
(*eprintf "pp_assign %a %a %d@." Types.print_ty var_type pp_val value depth;*)
105
  let loop_vars = mk_loop_variables m var_type depth in
106
  let reordered_loop_vars = reorder_loop_variables loop_vars in
107
  let rec aux fmt vars =
108
    match vars with
109
    | [] ->
110
      fprintf fmt "%a = %a;" 
111
	(pp_value_suffix self loop_vars pp_var) var_name
112
	(pp_value_suffix self loop_vars pp_var) value
113
    | (d, LVar i) :: q ->
114
(*eprintf "pp_aux %a %s@." Dimension.pp_dimension d i;*)
115
      fprintf fmt "@[<v 2>{@,int %s;@,for(%s=0;%s<%a;%s++)@,%a @]@,}"
116
	i i i Dimension.pp_dimension d i
117
	aux q
118
    | (d, LInt r) :: q ->
119
(*eprintf "pp_aux %a %d@." Dimension.pp_dimension d (!r);*)
120
      let szl = Utils.enumerate (Dimension.size_const_dimension d) in
121
      fprintf fmt "@[<v 2>{@,%a@]@,}"
122
	(Utils.fprintf_list ~sep:"@," (fun fmt i -> r := i; aux fmt q)) szl
123
  in
124
  begin
125
    reset_loop_counter ();
126
    (*reset_addr_counter ();*)
127
    aux fmt reordered_loop_vars
128
  end
129

    
130
let pp_instance_call m self fmt i (inputs: value_t list) (outputs: var_decl list) =
131
 try (* stateful node instance *)
132
   let (n,_) = List.assoc i m.minstances in
133
   fprintf fmt "%a (%a%t%a%t%s%s->%s);"
134
     pp_machine_step_name (node_name n)
135
     (Utils.fprintf_list ~sep:", " (pp_c_val self (pp_c_var_read m))) inputs
136
     (Utils.pp_final_char_if_non_empty ", " inputs) 
137
     (Utils.fprintf_list ~sep:", " (pp_c_var_write m)) outputs
138
     (Utils.pp_final_char_if_non_empty ", " outputs)
139
     (if !Options.no_pointer then "&" else "")
140
     self
141
     i
142
 with Not_found -> (* stateless node instance *)
143
   let (n,_) = List.assoc i m.mcalls in
144
   fprintf fmt "%a (%a%t%a);"
145
     pp_machine_step_name (node_name n)
146
     (Utils.fprintf_list ~sep:", " (pp_c_val self (pp_c_var_read m))) inputs
147
     (Utils.pp_final_char_if_non_empty ", " inputs) 
148
     (Utils.fprintf_list ~sep:", " (pp_c_var_write m)) outputs 
149

    
150
let pp_machine_reset (m: machine_t) self fmt inst =
151
  let (node, static) = List.assoc inst m.minstances in
152
  fprintf fmt "%a(%a%t%s%s->%s);"
153
    pp_machine_reset_name (node_name node)
154
    (Utils.fprintf_list ~sep:", " Dimension.pp_dimension) static
155
    (Utils.pp_final_char_if_non_empty ", " static)
156
    (if !Options.no_pointer then "&" else "")
157
    self inst
158

    
159
let has_c_prototype funname dependencies =
160
  let imported_node_opt = (* We select the last imported node with the name funname.
161
			       The order of evaluation of dependencies should be
162
			       compatible with overloading. (Not checked yet) *) 
163
      List.fold_left
164
	(fun res (_, _, decls) -> 
165
	  match res with
166
	  | Some _ -> res
167
	  | None -> 
168
	    let matched = fun t -> match t.top_decl_desc with 
169
	      | ImportedNode nd -> nd.nodei_id = funname 
170
	      | _ -> false
171
	    in
172
	    if List.exists matched decls then (
173
	      match (List.find matched decls).top_decl_desc with
174
	      | ImportedNode nd -> Some nd
175
	      | _ -> assert false
176
	    )
177
	    else
178
	      None
179
	) None dependencies in
180
    match imported_node_opt with
181
    | None -> false
182
    | Some nd -> (match nd.nodei_prototype with Some "C" -> true | _ -> false)
183

    
184

    
185
let rec pp_conditional dependencies (m: machine_t) self fmt c tl el =
186
  fprintf fmt "@[<v 2>if (%a) {%t%a@]@,@[<v 2>} else {%t%a@]@,}"
187
    (pp_c_val self (pp_c_var_read m)) c
188
    (Utils.pp_newline_if_non_empty tl)
189
    (Utils.fprintf_list ~sep:"@," (pp_machine_instr_internal dependencies m self)) tl
190
    (Utils.pp_newline_if_non_empty el)
191
    (Utils.fprintf_list ~sep:"@," (pp_machine_instr_internal dependencies m self)) el
192

    
193
and pp_machine_instr_internal dependencies (m: machine_t) self fmt instr =
194
  match instr with 
195
  | MReset i ->
196
    pp_machine_reset m self fmt i
197
  | MLocalAssign (i,v) ->
198
    pp_assign
199
      m self (pp_c_var_read m) fmt
200
      i.var_type (LocalVar i) v
201
  | MStateAssign (i,v) ->
202
    pp_assign
203
      m self (pp_c_var_read m) fmt
204
      i.var_type (StateVar i) v
205
  | MStep ([i0], i, vl) when Basic_library.is_internal_fun i  ->
206
    pp_machine_instr_internal dependencies m self fmt (MLocalAssign (i0, Fun (i, vl)))
207
  | MStep ([i0], i, vl) when has_c_prototype i dependencies -> 
208
    fprintf fmt "%a = %s(%a);" 
209
      (pp_c_val self (pp_c_var_read m)) (LocalVar i0) 
210
      i
211
      (Utils.fprintf_list ~sep:", " (pp_c_val self (pp_c_var_read m))) vl
212
  | MStep (il, i, vl) ->
213
    pp_instance_call m self fmt i vl il
214
  | MBranch (g,hl) ->
215
    if hl <> [] && let t = fst (List.hd hl) in t = tag_true || t = tag_false
216
    then (* boolean case, needs special treatment in C because truth value is not unique *)
217
	 (* may disappear if we optimize code by replacing last branch test with default *)
218
      let tl = try List.assoc tag_true  hl with Not_found -> [] in
219
      let el = try List.assoc tag_false hl with Not_found -> [] in
220
      pp_conditional dependencies m self fmt g tl el
221
    else (* enum type case *)
222
      fprintf fmt "@[<v 2>switch(%a) {@,%a@,}@]"
223
	(pp_c_val self (pp_c_var_read m)) g
224
	(Utils.fprintf_list ~sep:"@," (pp_machine_branch dependencies m self)) hl
225

    
226
and pp_machine_branch dependencies m self fmt (t, h) =
227
  fprintf fmt "@[<v 2>case %a:@,%a@,break;@]" pp_c_tag t (Utils.fprintf_list ~sep:"@," (pp_machine_instr_internal dependencies m self)) h
228

    
229

    
230
module Main = functor (Mod: MODIFIERS_SRC) -> 
231
struct
232

    
233
(********************************************************************************************)
234
(*                         C file Printing functions                                        *)
235
(********************************************************************************************)
236

    
237
let pp_machine_instr dependencies (m: machine_t) self fmt instr =
238
  fprintf fmt "%a%a%a"
239
    (Mod.print_instr_prefix m) instr
240
    (pp_machine_instr_internal dependencies (m: machine_t) self) instr
241
    (Mod.print_instr_postfix m) instr
242

    
243
let print_const_def fmt cdecl =
244
  fprintf fmt "%a = %a;@." 
245
    (pp_c_type cdecl.const_id) cdecl.const_type
246
    pp_c_const cdecl.const_value 
247

    
248

    
249
let print_alloc_instance fmt (i, (m, static)) =
250
  fprintf fmt "%t%a (%s%s%a);@,"
251
    (fun fmt-> if !Options.no_pointer then fprintf fmt "" else fprintf fmt "_alloc->%s = " i)
252
    pp_machine_alloc_name (node_name m)
253
    (if !Options.no_pointer then "0" else "")
254
    (if !Options.no_pointer && List.length static != 0 then ", " else "")
255
    (Utils.fprintf_list ~sep:", " Dimension.pp_dimension) static
256

    
257
let print_alloc_array fmt vdecl =
258
  let base_type = Types.array_base_type vdecl.var_type in
259
  let size_types = Types.array_type_multi_dimension vdecl.var_type in
260
  let size_type = Dimension.multi_dimension_product vdecl.var_loc size_types in
261
  fprintf fmt "_alloc->_reg.%s = (%a*) malloc((%a)*sizeof(%a));@,assert(_alloc->%s);@,"
262
    vdecl.var_id
263
    (pp_c_type "") base_type
264
    Dimension.pp_dimension size_type
265
    (pp_c_type "") base_type
266
    vdecl.var_id
267

    
268
let print_alloc_code fmt m =
269
  let array_mem = List.filter (fun v -> Types.is_array_type v.var_type) m.mmemory in
270
  fprintf fmt "%a *_alloc = 0;@,%s_alloc = (%a *) malloc(sizeof(%a));@,assert(_alloc);%s@,%a%areturn _alloc;"
271
    pp_machine_memtype_name m.mname.node_id
272
    (if !Options.no_pointer then "if (allocStruct) {" else "")
273
    pp_machine_memtype_name m.mname.node_id
274
    pp_machine_memtype_name m.mname.node_id
275
    (if !Options.no_pointer then "}" else "")
276
    (Utils.fprintf_list ~sep:"" print_alloc_array) array_mem
277
    (Utils.fprintf_list ~sep:"" print_alloc_instance) m.minstances
278

    
279
let print_stateless_code dependencies fmt m =
280
  let self = "__ERROR__" in
281
  if not (!Options.ansi && is_generic_node { top_decl_desc = Node m.mname; top_decl_loc = Location.dummy_loc })
282
  then
283
    (* C99 code *)
284
    fprintf fmt "@[<v 2>%a {@,%t@,%a%t@,%t@,%a%a%t%t%t@]@,}@.@."
285
      print_stateless_prototype (m.mname.node_id, m.mstep.step_inputs, m.mstep.step_outputs)
286
      (* locals *)
287
      (fun fmt -> Mod.print_step_code_prefix pp_machine_instr true fmt m)
288
      (Utils.fprintf_list ~sep:";@," pp_c_decl_local_var) m.mstep.step_locals
289
      (Utils.pp_final_char_if_non_empty ";@," m.mstep.step_locals)
290
      (fun fmt -> Mod.print_step_code_midfix pp_machine_instr true fmt m)
291
      (* check assertions *)
292
      (pp_c_checks self) m
293
      (* instrs *)
294
      (Utils.fprintf_list ~sep:"@," (pp_machine_instr dependencies m self)) m.mstep.step_instrs
295
      (Utils.pp_newline_if_non_empty m.mstep.step_instrs)
296
      (* Postfix modifier *)
297
      (fun fmt -> Mod.print_step_code_postfix pp_machine_instr true fmt m)
298
      (fun fmt -> fprintf fmt "return;")
299
  else
300
    (* C90 code *)
301
    let (gen_locals, base_locals) = List.partition (fun v -> Types.is_generic_type v.var_type) m.mstep.step_locals in
302
    let gen_calls = List.map (fun e -> let (id, _, _) = call_of_expr e in mk_call_var_decl e.expr_loc id) m.mname.node_gencalls in
303
    fprintf fmt "@[<v 2>%a {@,%t@,%a%t@,%t@,%a%a%t%t%t@]@,}@.@."
304
      print_stateless_prototype (m.mname.node_id, (m.mstep.step_inputs@gen_locals@gen_calls), m.mstep.step_outputs)
305
      (* locals *)
306
      (fun fmt -> Mod.print_step_code_prefix pp_machine_instr true fmt m)
307
      (Utils.fprintf_list ~sep:";@," pp_c_decl_local_var) base_locals
308
      (Utils.pp_final_char_if_non_empty ";" base_locals)
309
      (fun fmt -> Mod.print_step_code_midfix pp_machine_instr true fmt m)
310
      (* check assertions *)
311
      (pp_c_checks self) m
312
      (* instrs *)
313
      (Utils.fprintf_list ~sep:"@," (pp_machine_instr dependencies m self)) m.mstep.step_instrs
314
      (Utils.pp_newline_if_non_empty m.mstep.step_instrs)
315
      (* Postfix modifier *)
316
      (fun fmt -> Mod.print_step_code_postfix pp_machine_instr true fmt m)
317
      (fun fmt -> fprintf fmt "return;")
318

    
319
let print_reset_code dependencies fmt m self =
320
  fprintf fmt "@[<v 2>%a {@,%a%t%treturn;@]@,}@.@."
321
    (print_reset_prototype self) (m.mname.node_id, m.mstatic)
322
    (Utils.fprintf_list ~sep:"@," (pp_machine_instr dependencies m self)) m.minit
323
    (Utils.pp_newline_if_non_empty m.minit)
324
    (* Postfix modifier *)
325
    (fun fmt -> Mod.print_init_code_postfix pp_machine_instr fmt m)
326

    
327
let print_step_code dependencies fmt m self =
328
  if not (!Options.ansi && is_generic_node { top_decl_desc = Node m.mname; top_decl_loc = Location.dummy_loc })
329
  then
330
    (* C99 code *)
331
    let array_mems = List.filter (fun v -> Types.is_array_type v.var_type) m.mmemory in
332
    fprintf fmt "@[<v 2>%a {@,%t@,%a%t@,%t@,%a%t@,%a%a%t%t%t@]@,}@.@."
333
      (print_step_prototype self) (m.mname.node_id, m.mstep.step_inputs, m.mstep.step_outputs)
334
      (* locals *)
335
      (fun fmt -> Mod.print_step_code_prefix pp_machine_instr false fmt m)
336
      (Utils.fprintf_list ~sep:";@," pp_c_decl_local_var) m.mstep.step_locals
337
      (Utils.pp_final_char_if_non_empty ";@," m.mstep.step_locals)
338
      (fun fmt -> Mod.print_step_code_midfix pp_machine_instr false fmt m)
339
      (* array mems *)
340
      (Utils.fprintf_list ~sep:";@," (pp_c_decl_array_mem self)) array_mems
341
      (Utils.pp_final_char_if_non_empty ";@," array_mems)
342
      (* check assertions *)
343
      (pp_c_checks self) m
344
      (* instrs *)
345
      (Utils.fprintf_list ~sep:"@," (pp_machine_instr dependencies m self)) m.mstep.step_instrs
346
      (Utils.pp_newline_if_non_empty m.mstep.step_instrs)
347
      (* Postfix modifier *)
348
      (fun fmt -> Mod.print_step_code_postfix pp_machine_instr false fmt m)
349
      (fun fmt -> fprintf fmt "return;")
350
  else
351
    (* C90 code *)
352
    let (gen_locals, base_locals) = List.partition (fun v -> Types.is_generic_type v.var_type) m.mstep.step_locals in
353
    let gen_calls = List.map (fun e -> let (id, _, _) = call_of_expr e in mk_call_var_decl e.expr_loc id) m.mname.node_gencalls in
354
    fprintf fmt "@[<v 2>%a {@,%t@,%a%t@,%t@,%a%a%t%t%t@]@,}@.@."
355
      (print_step_prototype self) (m.mname.node_id, (m.mstep.step_inputs@gen_locals@gen_calls), m.mstep.step_outputs)
356
      (* locals *)
357
      (fun fmt -> Mod.print_step_code_prefix pp_machine_instr false fmt m)
358
      (Utils.fprintf_list ~sep:";@," pp_c_decl_local_var) base_locals
359
      (Utils.pp_final_char_if_non_empty ";" base_locals)
360
      (fun fmt -> Mod.print_step_code_midfix pp_machine_instr false fmt m)
361
      (* check assertions *)
362
      (pp_c_checks self) m
363
      (* instrs *)
364
      (Utils.fprintf_list ~sep:"@," (pp_machine_instr dependencies m self)) m.mstep.step_instrs
365
      (Utils.pp_newline_if_non_empty m.mstep.step_instrs)
366
      (* Postfix modifier *)
367
      (fun fmt -> Mod.print_step_code_postfix pp_machine_instr false fmt m)
368
      (fun fmt -> fprintf fmt "return;")
369

    
370

    
371
(********************************************************************************************)
372
(*                     MAIN C file Printing functions                                       *)
373
(********************************************************************************************)
374

    
375
let print_machine dependencies fmt m =
376
  if fst (get_stateless_status m) then
377
    begin
378
      (* Step function *)
379
      print_stateless_code dependencies fmt m
380
    end
381
  else
382
    begin
383
      (* Alloc function, only if non static mode *)
384
      if (not !Options.static_mem) then  
385
	(
386
	  fprintf fmt "@[<v 2>%a {@,%a@]@,}@.@."
387
	    print_alloc_prototype (m.mname.node_id, m.mstatic)
388
	    print_alloc_code m;
389
	);
390
      let self = mk_self m in
391
      (* Reset function *)
392
      print_reset_code dependencies fmt m self;
393
      (* Step function *)
394
      print_step_code dependencies fmt m self
395
    end
396

    
397

    
398
let print_lib_c source_fmt basename prog machines dependencies =
399

    
400
  fprintf source_fmt "#include <stdlib.h>@.#include <assert.h>@.#include \"%s\"@.@." (basename^".h");
401
  (* Print the svn version number and the supported C standard (C90 or C99) *)
402
  print_version source_fmt;
403
  (* Print the prototype of imported nodes *)
404
  fprintf source_fmt "/* Imported nodes declarations */@.";
405
  fprintf source_fmt "@[<v>";
406
  List.iter (print_import_prototype source_fmt) dependencies;
407
  fprintf source_fmt "@]@.";
408
  (* Print consts *)
409
  fprintf source_fmt "/* Global constants (definitions) */@.";
410
  List.iter (fun c -> print_const_def source_fmt c) (get_consts prog);
411
  pp_print_newline source_fmt ();
412
  (* Print nodes one by one (in the previous order) *)
413
  List.iter (print_machine dependencies source_fmt) machines;
414
 end
415

    
416
(* Local Variables: *)
417
(* compile-command:"make -C ../../.." *)
418
(* End: *)
(9-9/9)