Project

General

Profile

Statistics
| Branch: | Tag: | Revision:

lustrec / src / compiler_stages.ml @ f4050bef

History | View | Annotate | Download (10.7 KB)

1
open Format
2
open Utils
3
open Compiler_common
4
open LustreSpec
5

    
6
exception StopPhase1 of program
7

    
8
let dynamic_checks () =
9
  match !Options.output, !Options.spec with
10
  | "C", "C" -> true
11
  | _ -> false
12
     
13

    
14
(* check whether a source file has a compiled header, if not, generate the
15
   compiled header *)
16
let compile_source_to_header prog computed_types_env computed_clocks_env dirname basename extension =
17
  let destname = !Options.dest_dir ^ "/" ^ basename in
18
  let lusic_ext = extension ^ "c" in
19
  let header_name = destname ^ lusic_ext in
20
  begin
21
    if not (Sys.file_exists header_name) then
22
      begin
23
	Log.report ~level:1 (fun fmt -> fprintf fmt ".. generating compiled header file %s@," header_name);
24
	Lusic.write_lusic false (Lusic.extract_header dirname basename prog) destname lusic_ext;
25
	Lusic.print_lusic_to_h destname lusic_ext
26
      end
27
    else
28
      let lusic = Lusic.read_lusic destname lusic_ext in
29
      if not lusic.Lusic.from_lusi then
30
	begin
31
	  Log.report ~level:1 (fun fmt -> fprintf fmt ".. generating compiled header file %s@," header_name);
32
       	  Lusic.write_lusic false (Lusic.extract_header dirname basename prog) destname lusic_ext;
33
	  (*List.iter (fun top_decl -> Format.eprintf "lusic: %a@." Printers.pp_decl top_decl) lusic.Lusic.contents;*)
34
	  Lusic.print_lusic_to_h destname lusic_ext
35
	end
36
      else
37
	begin
38
	  Log.report ~level:1 (fun fmt -> fprintf fmt ".. loading compiled header file %s@," header_name);
39
	  Modules.check_dependency lusic destname;
40
	  let header = lusic.Lusic.contents in
41
	  let (declared_types_env, declared_clocks_env) = get_envs_from_top_decls header in
42
	  check_compatibility
43
	    (prog, computed_types_env, computed_clocks_env)
44
	    (header, declared_types_env, declared_clocks_env)
45
	end
46
  end
47

    
48

    
49
(* From prog to prog *)
50
let stage1 prog dirname basename =
51
  (* Updating parent node information for variables *)
52
  Compiler_common.update_vdecl_parents_prog prog;
53

    
54
  (* Removing automata *)
55
  let prog = expand_automata prog in
56
  Log.report ~level:4 (fun fmt -> fprintf fmt ".. after automata expansion:@,  @[<v 2>@,%a@]@ " Printers.pp_prog prog);
57

    
58
  (* Importing source *)
59
  let _ = Modules.load_program ISet.empty prog in
60

    
61
  (* Extracting dependencies *)
62
  let dependencies, type_env, clock_env = import_dependencies prog in
63

    
64
  (* Sorting nodes *)
65
  let prog = SortProg.sort prog in
66

    
67
  (* Perform inlining before any analysis *)
68
  let orig, prog =
69
    if !Options.global_inline && !Options.main_node <> "" then
70
      (if !Options.witnesses then prog else []),
71
      Inliner.global_inline basename prog type_env clock_env
72
    else (* if !Option.has_local_inline *)
73
      [],
74
      Inliner.local_inline prog (* type_env clock_env *)
75
  in
76

    
77
  (* Checking stateless/stateful status *)
78
  if Plugins.check_force_stateful () then
79
    force_stateful_decls prog
80
  else
81
    check_stateless_decls prog;
82

    
83
  (* Typing *)
84
  let computed_types_env = type_decls type_env prog in
85

    
86
  (* Clock calculus *)
87
  let computed_clocks_env = clock_decls clock_env prog in
88

    
89
  (* Registering and checking machine types *)
90
  if Machine_types.is_active then Machine_types.load prog;
91
  
92

    
93
  (* Generating a .lusi header file only *)
94
  if !Options.lusi then
95
    (* We stop here the processing and produce the current prog. It will be
96
       exported as a lusi *)
97
    raise (StopPhase1 prog);
98

    
99
  (* Optimization of prog: 
100
     - Unfold consts 
101
     - eliminate trivial expressions
102
  *)
103
  (*
104
    let prog = 
105
    if !Options.const_unfold || !Options.optimization >= 5 then
106
    begin
107
    Log.report ~level:1 (fun fmt -> fprintf fmt ".. eliminating constants and aliases@,");
108
    Optimize_prog.prog_unfold_consts prog
109
    end
110
    else
111
    prog
112
    in
113
  *)
114
  (* Delay calculus *)
115
  (* TO BE DONE LATER (Xavier)
116
     if(!Options.delay_calculus)
117
     then
118
     begin
119
     Log.report ~level:1 (fun fmt -> fprintf fmt ".. initialisation analysis@?");
120
     try
121
     Delay_calculus.delay_prog Basic_library.delay_env prog
122
     with (Delay.Error (loc,err)) as exc ->
123
     Location.print loc;
124
     eprintf "%a" Delay.pp_error err;
125
     Utils.track_exception ();
126
     raise exc
127
     end;
128
  *)
129

    
130
  (* Creating destination directory if needed *)
131
  create_dest_dir ();
132

    
133
  (* Compatibility with Lusi *)
134
  (* Checking the existence of a lusi (Lustre Interface file) *)
135
  let extension = ".lusi" in
136
  compile_source_to_header prog computed_types_env computed_clocks_env dirname basename extension;
137

    
138
  Typing.uneval_prog_generics prog;
139
  Clock_calculus.uneval_prog_generics prog;
140

    
141

    
142
  if !Options.global_inline && !Options.main_node <> "" && !Options.witnesses then
143
    begin
144
      let orig = Corelang.copy_prog orig in
145
      Log.report ~level:1 (fun fmt -> fprintf fmt ".. generating witness file@,");
146
      check_stateless_decls orig;
147
      let _ = Typing.type_prog type_env orig in
148
      let _ = Clock_calculus.clock_prog clock_env orig in
149
      Typing.uneval_prog_generics orig;
150
      Clock_calculus.uneval_prog_generics orig;
151
      Inliner.witness
152
	basename
153
	!Options.main_node
154
	orig prog type_env clock_env
155
    end;
156
  
157
  (* Computes and stores generic calls for each node,
158
     only useful for ANSI C90 compliant generic node compilation *)
159
  if !Options.ansi then Causality.NodeDep.compute_generic_calls prog;
160
  (*Hashtbl.iter (fun id td -> match td.Corelang.top_decl_desc with
161
    Corelang.Node nd -> Format.eprintf "%s calls %a" id
162
    Causality.NodeDep.pp_generic_calls nd | _ -> ()) Corelang.node_table;*)
163

    
164
  (* If some backend involving dynamic checks are active, then node annotations become runtime checks *)
165
  let prog =
166
    if dynamic_checks () then
167
      Spec.enforce_spec_prog prog
168
    else
169
      prog
170
  in
171

    
172

    
173
  (* (\* Registering and checking machine types *\) *)
174
  (* Machine_types.load prog; *)
175

    
176
  (* Normalization phase *)
177
  Log.report ~level:1 (fun fmt -> fprintf fmt ".. normalization@,");
178
  let prog = Normalization.normalize_prog ~backend:!Options.output prog in
179
  Log.report ~level:2 (fun fmt -> fprintf fmt "@[<v 2>@ %a@]@," Printers.pp_prog prog);
180

    
181
  let prog =
182
    if !Options.mpfr
183
    then
184
      begin
185
	Log.report ~level:1 (fun fmt -> fprintf fmt ".. targetting MPFR library@,");
186
	Mpfr.inject_prog prog
187
      end
188
    else
189
      begin
190
	Log.report ~level:1 (fun fmt -> fprintf fmt ".. keeping floating-point numbers@,");
191
	prog
192
      end in
193
  Log.report ~level:2 (fun fmt -> fprintf fmt "@[<v 2>@ %a@]@," Printers.pp_prog prog);
194

    
195
  (* Checking array accesses *)
196
  if !Options.check then
197
    begin
198
      Log.report ~level:1 (fun fmt -> fprintf fmt ".. checking array accesses@,");
199
      Access.check_prog prog;
200
    end;
201

    
202
  
203
  let prog = SortProg.sort_nodes_locals prog in
204
  
205
  prog, dependencies
206

    
207

    
208
    (* from source to machine code, with optimization *)
209
let stage2 prog =    
210
  (* Computation of node equation scheduling. It also breaks dependency cycles
211
     and warns about unused input or memory variables *)
212
  Log.report ~level:1 (fun fmt -> fprintf fmt ".. @[<v 2>scheduling@ ");
213
  let prog, node_schs =
214
    try 
215
      Scheduling.schedule_prog prog
216
    with Causality.Error _ -> (* Error is not kept. It is recomputed in a more
217
				 systemtic way in AlgebraicLoop module *)
218
      AlgebraicLoop.analyze prog
219
  in
220
  Log.report ~level:1 (fun fmt -> fprintf fmt "%a"              Scheduling.pp_warning_unused node_schs);
221
  Log.report ~level:3 (fun fmt -> fprintf fmt "@[<v 2>@ %a@]@," Scheduling.pp_schedule node_schs);
222
  Log.report ~level:3 (fun fmt -> fprintf fmt "@[<v 2>@ %a@]@," Scheduling.pp_fanin_table node_schs);
223
  Log.report ~level:5 (fun fmt -> fprintf fmt "@[<v 2>@ %a@]@," Scheduling.pp_dep_graph node_schs);
224
  Log.report ~level:3 (fun fmt -> fprintf fmt "@[<v 2>@ %a@]@," Printers.pp_prog prog);
225
  Log.report ~level:1 (fun fmt -> fprintf fmt "@]@ ");
226

    
227
  (* TODO Salsa optimize prog: 
228
     - emits warning for programs with pre inside expressions
229
     - make sure each node arguments and memory is bounded by a local annotation
230
     - introduce fresh local variables for each real pure subexpression
231
  *)
232
  (* DFS with modular code generation *)
233
  Log.report ~level:1 (fun fmt -> fprintf fmt ".. machines generation@,");
234
  let machine_code = Machine_code.translate_prog prog node_schs in
235

    
236
  Log.report ~level:3 (fun fmt -> fprintf fmt ".. generated machines (unoptimized):@ %a@ "Machine_code.pp_machines machine_code);
237

    
238
  (* Optimize machine code *)
239
  Optimize_machine.optimize prog node_schs machine_code
240

    
241

    
242
(* printing code *)
243
let stage3 prog machine_code dependencies basename =
244
  let basename    =  Filename.basename basename in
245
  match !Options.output with
246
    "C" -> 
247
      begin
248
	Log.report ~level:1 (fun fmt -> fprintf fmt ".. C code generation@,");
249
	C_backend.translate_to_c
250
	  (* alloc_header_file source_lib_file source_main_file makefile_file *)
251
	  basename prog machine_code dependencies
252
      end
253
  | "java" ->
254
     begin
255
       (Format.eprintf "internal error: sorry, but not yet supported !"; assert false)
256
     (*let source_file = basename ^ ".java" in
257
       Log.report ~level:1 (fun fmt -> fprintf fmt ".. opening file %s@,@?" source_file);
258
       let source_out = open_out source_file in
259
       let source_fmt = formatter_of_out_channel source_out in
260
       Log.report ~level:1 (fun fmt -> fprintf fmt ".. java code generation@,@?");
261
       Java_backend.translate_to_java source_fmt basename normalized_prog machine_code;*)
262
     end
263
  | "horn" ->
264
     begin
265
       let destname = !Options.dest_dir ^ "/" ^ basename in
266
       let source_file = destname ^ ".smt2" in (* Could be changed *)
267
       let source_out = open_out source_file in
268
       let fmt = formatter_of_out_channel source_out in
269
       Log.report ~level:1 (fun fmt -> fprintf fmt ".. hornification@,");
270
       Horn_backend.translate fmt basename prog (Machine_code.arrow_machine::machine_code);
271
       (* Tracability file if option is activated *)
272
       if !Options.traces then (
273
	 let traces_file = destname ^ ".traces.xml" in (* Could be changed *)
274
	 let traces_out = open_out traces_file in
275
	 let fmt = formatter_of_out_channel traces_out in
276
         Log.report ~level:1 (fun fmt -> fprintf fmt ".. tracing info@,");
277
	 Horn_backend_traces.traces_file fmt basename prog machine_code;
278
       )
279
     end
280
  | "lustre" ->
281
     begin
282
       let destname = !Options.dest_dir ^ "/" ^ basename in
283
       let source_file = destname ^ ".lustrec.lus" in (* Could be changed *)
284
       let source_out = open_out source_file in
285
       let fmt = formatter_of_out_channel source_out in
286
       Printers.pp_prog fmt prog;
287
       Format.fprintf fmt "@.@?";
288
       (*	Lustre_backend.translate fmt basename normalized_prog machine_code *)
289
       ()
290
     end
291
  | "emf" ->
292
     begin
293
       let destname = !Options.dest_dir ^ "/" ^ basename in
294
       let source_file = destname ^ ".emf" in (* Could be changed *)
295
       let source_out = open_out source_file in
296
       let fmt = formatter_of_out_channel source_out in
297
       EMF_backend.translate fmt basename prog machine_code;
298
       ()
299
     end
300

    
301
  | _ -> assert false