1 |
1 |
|
2 |
2 |
(* We try to avoid opening modules here *)
|
3 |
|
module ST = Salsa.SalsaTypes
|
|
3 |
module ST = Salsa.Types
|
4 |
4 |
module SDT = SalsaDatatypes
|
5 |
5 |
module LT = LustreSpec
|
6 |
6 |
module MC = Machine_code
|
... | ... | |
118 |
118 |
| LT.Access _
|
119 |
119 |
| LT.Power _ -> assert false
|
120 |
120 |
and opt_num_expr ranges formalEnv e =
|
121 |
|
(* if debug then Format.eprintf "Optimizing expression %a with Salsa@ " MC.pp_val e; *)
|
|
121 |
(* if !debug then Format.eprintf "Optimizing expression %a with Salsa@ " MC.pp_val e; *)
|
122 |
122 |
let fresh_id = "toto" in (* TODO more meaningful name *)
|
123 |
123 |
(* Convert expression *)
|
124 |
124 |
(* List.iter (fun (l,c) -> Format.eprintf "%s -> %a@ " l Printers.pp_const c) constEnv; *)
|
125 |
|
let e_salsa : Salsa.SalsaTypes.expression = value_t2salsa_expr constEnv e in
|
|
125 |
let e_salsa : Salsa.Types.expression = value_t2salsa_expr constEnv e in
|
126 |
126 |
(* Format.eprintf "apres deplaige constantes ok%a @." MC.pp_val (salsa_expr2value_t vars_env [](\* constEnv *\) e_salsa) ; *)
|
127 |
127 |
|
128 |
128 |
(* Convert formalEnv *)
|
129 |
|
(* if debug then Format.eprintf "Formal env is [%a]@ " FormalEnv.pp formalEnv; *)
|
|
129 |
(* if !debug then Format.eprintf "Formal env is [%a]@ " FormalEnv.pp formalEnv; *)
|
130 |
130 |
let formalEnv_salsa =
|
131 |
131 |
FormalEnv.fold (fun id expr accu ->
|
132 |
132 |
(id, value_t2salsa_expr constEnv expr)::accu
|
133 |
133 |
) formalEnv [] in
|
134 |
|
(* if debug then Format.eprintf "Formal env converted to salsa@ "; *)
|
|
134 |
(* if !debug then Format.eprintf "Formal env converted to salsa@ "; *)
|
135 |
135 |
(* Substitute all occurences of variables by their definition in env *)
|
136 |
|
let (e_salsa: Salsa.SalsaTypes.expression), _ =
|
|
136 |
let (e_salsa: Salsa.Types.expression), _ =
|
137 |
137 |
Salsa.Rewrite.substVars
|
138 |
138 |
e_salsa
|
139 |
139 |
formalEnv_salsa
|
140 |
140 |
0 (* TODO: Nasrine, what is this integer value for ? *)
|
141 |
141 |
in
|
142 |
|
(* if debug then Format.eprintf "Substituted def in expr@ "; *)
|
|
142 |
(* if !debug then Format.eprintf "Substituted def in expr@ "; *)
|
143 |
143 |
let abstractEnv = Hashtbl.fold
|
144 |
144 |
(fun id value accu -> (id,value)::accu)
|
145 |
145 |
ranges
|
... | ... | |
150 |
150 |
valEnv2ExprEnv remplce les paires id, abstractVal par id, Cst itv - on
|
151 |
151 |
garde evalPartExpr remplace les variables e qui sont dans env par la cst
|
152 |
152 |
- on garde *)
|
153 |
|
(* if debug then Format.eprintf "avant avant eval part@ "; *)
|
|
153 |
(* if !debug then Format.eprintf "avant avant eval part@ "; *)
|
154 |
154 |
(* Format.eprintf "avant evalpart: %a@." MC.pp_val (salsa_expr2value_t vars_env constEnv e_salsa); *)
|
155 |
155 |
let e_salsa =
|
156 |
|
Salsa.Float.evalPartExpr
|
|
156 |
Salsa.Analyzer.evalPartExpr
|
157 |
157 |
e_salsa
|
158 |
|
(Salsa.Float.valEnv2ExprEnv abstractEnv)
|
159 |
|
([] (* no blacklisted variables *))
|
|
158 |
(Salsa.Analyzer.valEnv2ExprEnv abstractEnv)
|
|
159 |
([] (* no blacklisted variables *))
|
|
160 |
([] (* no arrays *))
|
160 |
161 |
in
|
161 |
162 |
(* Format.eprintf "apres evalpart: %a@." MC.pp_val (salsa_expr2value_t vars_env constEnv e_salsa); *)
|
162 |
163 |
(* Checking if we have all necessary information *)
|
163 |
164 |
|
164 |
|
let free_vars = get_salsa_free_vars vars_env constEnv abstractEnv e_salsa in
|
165 |
|
|
|
165 |
let free_vars = get_salsa_free_vars vars_env constEnv abstractEnv e_salsa in
|
166 |
166 |
if Vars.cardinal free_vars > 0 then (
|
167 |
|
Format.eprintf "Warning: unbounded free vars (%a) in expression %a. We do not optimize it.@ "
|
|
167 |
Log.report ~level:2 (fun fmt -> Format.fprintf fmt "Warning: unbounded free vars (%a) in expression %a. We do not optimize it.@ "
|
168 |
168 |
Vars.pp (Vars.fold (fun v accu -> let v' = {v with LT.var_id = nodename ^ "." ^ v.LT.var_id } in Vars.add v' accu) free_vars Vars.empty)
|
169 |
|
MC.pp_val (salsa_expr2value_t vars_env constEnv e_salsa);
|
170 |
|
if debug then Format.eprintf "Some free vars, not optimizing@.";
|
|
169 |
MC.pp_val (salsa_expr2value_t vars_env constEnv e_salsa));
|
|
170 |
if !debug then Format.eprintf "Some free vars, not optimizing@.";
|
171 |
171 |
let new_e = try salsa_expr2value_t vars_env constEnv e_salsa with Not_found -> assert false in
|
172 |
172 |
new_e, None
|
173 |
173 |
)
|
174 |
174 |
else (
|
|
175 |
|
175 |
176 |
try
|
176 |
|
if debug then
|
|
177 |
if !debug then
|
177 |
178 |
Format.eprintf "Analyzing expression %a with env: @[<v>%a@ @]@ "
|
178 |
179 |
MC.pp_val (salsa_expr2value_t vars_env constEnv e_salsa)
|
179 |
180 |
(Utils.fprintf_list ~sep:",@ "(fun fmt (l,r) -> Format.fprintf fmt "%s -> %a" l FloatIntSalsa.pp r)) abstractEnv
|
180 |
181 |
;
|
181 |
|
|
|
182 |
|
182 |
183 |
let new_e_salsa, e_val =
|
183 |
184 |
Salsa.MainEPEG.transformExpression fresh_id e_salsa abstractEnv
|
184 |
185 |
in
|
185 |
186 |
let new_e = try salsa_expr2value_t vars_env constEnv new_e_salsa with Not_found -> assert false in
|
186 |
|
if debug then Format.eprintf "@ @[<v>old: %a@ new: %a@ range: %a@]" MC.pp_val e MC.pp_val new_e RangesInt.pp_val e_val;
|
|
187 |
if !debug then Format.eprintf "@ @[<v>old: %a@ new: %a@ range: %a@]" MC.pp_val e MC.pp_val new_e RangesInt.pp_val e_val;
|
187 |
188 |
new_e, Some e_val
|
188 |
189 |
with Not_found -> assert false
|
189 |
190 |
| Salsa.Epeg_types.EPEGError _ -> (
|
... | ... | |
195 |
196 |
|
196 |
197 |
|
197 |
198 |
in
|
198 |
|
if debug then
|
|
199 |
if !debug then
|
199 |
200 |
Format.eprintf "@[<v 2>Optimizing expression %a in environment %a and ranges %a@ "
|
200 |
201 |
MC.pp_val e
|
201 |
202 |
FormalEnv.pp formalEnv
|
... | ... | |
216 |
217 |
(FormalEnv.get_sort_fun formalEnv)
|
217 |
218 |
(Vars.elements vars_to_print)
|
218 |
219 |
in
|
219 |
|
Format.eprintf "Printing vars in the following order: [%a]@ " (Utils.fprintf_list ~sep:", " Printers.pp_var) ordered_vars ;
|
|
220 |
if !debug then Format.eprintf "Printing vars in the following order: [%a]@ " (Utils.fprintf_list ~sep:", " Printers.pp_var) ordered_vars ;
|
220 |
221 |
List.fold_right (
|
221 |
222 |
fun v (accu_instr, accu_ranges) ->
|
222 |
|
if debug then Format.eprintf "Printing assign for variable %s@ " v.LT.var_id;
|
|
223 |
if !debug then Format.eprintf "Printing assign for variable %s@ " v.LT.var_id;
|
223 |
224 |
try
|
224 |
225 |
(* Obtaining unfold expression of v in formalEnv *)
|
225 |
226 |
let v_def = FormalEnv.get_def formalEnv v in
|
... | ... | |
243 |
244 |
(* Main recursive function: modify the instructions list while preserving the
|
244 |
245 |
order of assigns for state variables. Returns a quintuple: (new_instrs,
|
245 |
246 |
ranges, formalEnv, printed_vars, and remaining vars to be printed) *)
|
246 |
|
let rec rewrite_instrs nodename constEnv vars_env m instrs ranges formalEnv printed_vars vars_to_print =
|
|
247 |
let rec rewrite_instrs nodename constEnv vars_env m instrs ranges formalEnv printed_vars vars_to_print =
|
|
248 |
Format.eprintf "Rewrite intrs :%a@." Machine_code.pp_instrs instrs;
|
247 |
249 |
let assign_vars = assign_vars nodename constEnv vars_env in
|
248 |
|
(* if debug then ( *)
|
|
250 |
(* if !debug then ( *)
|
249 |
251 |
(* Format.eprintf "------------@ "; *)
|
250 |
252 |
(* Format.eprintf "Current printed_vars: [%a]@ " Vars.pp printed_vars; *)
|
251 |
253 |
(* Format.eprintf "Formal env is [%a]@ " FormalEnv.pp formalEnv; *)
|
... | ... | |
254 |
256 |
| [] ->
|
255 |
257 |
(* End of instruction list: we produce the definition of each variable that
|
256 |
258 |
appears in vars_to_print. Each of them should be defined in formalEnv *)
|
257 |
|
if debug then Format.eprintf "Producing definitions %a@ " Vars.pp vars_to_print;
|
|
259 |
if !debug then Format.eprintf "Producing definitions %a@ " Vars.pp vars_to_print;
|
258 |
260 |
let instrs, ranges' = assign_vars printed_vars ranges formalEnv vars_to_print in
|
259 |
261 |
instrs,
|
260 |
262 |
ranges',
|
... | ... | |
266 |
268 |
(* We reformulate hd_instr, producing or not a fresh instruction, updating
|
267 |
269 |
formalEnv, possibly ranges and vars_to_print *)
|
268 |
270 |
begin
|
|
271 |
Format.eprintf "Hdlist@.";
|
269 |
272 |
let hd_instrs, ranges, formalEnv, printed_vars, vars_to_print =
|
270 |
273 |
match Corelang.get_instr_desc hd_instr with
|
271 |
274 |
| LT.MLocalAssign(vd,vt) when Types.is_real_type vd.LT.var_type && not (Vars.mem vd vars_to_print) ->
|
|
275 |
Format.eprintf "local assign@.";
|
272 |
276 |
(* LocalAssign are injected into formalEnv *)
|
273 |
|
(* if debug then Format.eprintf "Registering local assign %a@ " MC.pp_instr hd_instr; *)
|
274 |
|
if debug then Format.eprintf "%a@ " MC.pp_instr hd_instr;
|
|
277 |
(* if !debug then Format.eprintf "Registering local assign %a@ " MC.pp_instr hd_instr; *)
|
|
278 |
if !debug then Format.eprintf "%a@ " MC.pp_instr hd_instr;
|
275 |
279 |
let formalEnv' = FormalEnv.def formalEnv vd vt in (* formelEnv updated with vd = vt *)
|
276 |
280 |
[], (* no instr generated *)
|
277 |
281 |
ranges, (* no new range computed *)
|
... | ... | |
280 |
284 |
vars_to_print (* no more or less variables to print *)
|
281 |
285 |
|
282 |
286 |
| LT.MLocalAssign(vd,vt) when Types.is_real_type vd.LT.var_type && Vars.mem vd vars_to_print ->
|
|
287 |
Format.eprintf "local assign 2@.";
|
283 |
288 |
|
284 |
|
(* if debug then Format.eprintf "Registering and producing state assign %a@ " MC.pp_instr hd_instr; *)
|
285 |
|
(* if debug then Format.eprintf "Registering and producing state assign %a@ " MC.pp_instr hd_instr; *)
|
286 |
|
if debug then (
|
|
289 |
(* if !debug then Format.eprintf "Registering and producing state assign %a@ " MC.pp_instr hd_instr; *)
|
|
290 |
(* if !debug then Format.eprintf "Registering and producing state assign %a@ " MC.pp_instr hd_instr; *)
|
|
291 |
if !debug then (
|
287 |
292 |
Format.eprintf "%a@]@ " MC.pp_instr hd_instr;
|
288 |
293 |
Format.eprintf "Selected var %a: producing expression@ " Printers.pp_var vd;
|
289 |
294 |
);
|
290 |
|
let formalEnv' = FormalEnv.def formalEnv vd vt in (* formelEnv updated with vd = vt *)
|
|
295 |
let formalEnv' = FormalEnv.def formalEnv vd vt in (* formelEnv updated with vd = vt *)
|
291 |
296 |
let instrs', ranges' = (* printing vd = optimized vt *)
|
292 |
297 |
assign_vars printed_vars ranges formalEnv' (Vars.singleton vd)
|
293 |
298 |
in
|
... | ... | |
298 |
303 |
Vars.remove vd vars_to_print (* removed vd from variables to print *)
|
299 |
304 |
|
300 |
305 |
| LT.MStateAssign(vd,vt) when Types.is_real_type vd.LT.var_type && Vars.mem vd vars_to_print ->
|
|
306 |
Format.eprintf "state assign@.";
|
301 |
307 |
|
302 |
308 |
(* StateAssign are produced since they are required by the function. We still
|
303 |
309 |
keep their definition in the formalEnv in case it can optimize later
|
304 |
310 |
outputs. vd is removed from remaining vars_to_print *)
|
305 |
|
(* if debug then Format.eprintf "Registering and producing state assign %a@ " MC.pp_instr hd_instr; *)
|
306 |
|
if debug then (
|
|
311 |
(* if !debug then Format.eprintf "Registering and producing state assign %a@ " MC.pp_instr hd_instr; *)
|
|
312 |
if !debug then (
|
307 |
313 |
Format.eprintf "%a@]@ " MC.pp_instr hd_instr;
|
308 |
314 |
Format.eprintf "State assign %a: producing expression@ " Printers.pp_var vd;
|
309 |
315 |
);
|
... | ... | |
317 |
323 |
Vars.add vd printed_vars, (* adding vd to new printed vars *)
|
318 |
324 |
Vars.remove vd vars_to_print (* removed vd from variables to print *)
|
319 |
325 |
|
320 |
|
| (LT.MLocalAssign(vd,vt) | LT.MStateAssign(vd,vt)) ->
|
|
326 |
| (LT.MLocalAssign(vd,vt) | LT.MStateAssign(vd,vt)) ->
|
|
327 |
Format.eprintf "other assign@.";
|
|
328 |
|
321 |
329 |
(* We have to produce the instruction. But we may have to produce as
|
322 |
330 |
well its dependencies *)
|
323 |
331 |
let required_vars = get_expr_real_vars vt in
|
... | ... | |
327 |
335 |
variables *)
|
328 |
336 |
let prefix_instr, ranges =
|
329 |
337 |
assign_vars printed_vars ranges formalEnv required_vars in
|
|
338 |
|
330 |
339 |
let vt', _ = optimize_expr nodename constEnv (Vars.union required_vars printed_vars) vars_env ranges formalEnv vt in
|
331 |
340 |
let new_instr =
|
332 |
341 |
match Corelang.get_instr_desc hd_instr with
|
... | ... | |
342 |
351 |
Vars.diff vars_to_print written_vars (* removed vd + dependencies from
|
343 |
352 |
variables to print *)
|
344 |
353 |
|
345 |
|
| LT.MStep(vdl,id,vtl) ->
|
346 |
|
if debug then Format.eprintf "Call to a node %a@ " MC.pp_instr hd_instr;
|
|
354 |
| LT.MStep(vdl,id,vtl) ->
|
|
355 |
Format.eprintf "step@.";
|
|
356 |
|
|
357 |
if !debug then Format.eprintf "Call to a node %a@ " MC.pp_instr hd_instr;
|
347 |
358 |
(* Call of an external function. Input expressions have to be
|
348 |
359 |
optimized, their free variables produced. A fresh range has to be
|
349 |
360 |
computed for each output variable in vdl. Output of the function
|
... | ... | |
359 |
370 |
else
|
360 |
371 |
fun_types node
|
361 |
372 |
in
|
362 |
|
if debug then Format.eprintf "@[<v 2>... optimizing arguments@ ";
|
|
373 |
if !debug then Format.eprintf "@[<v 2>... optimizing arguments@ ";
|
363 |
374 |
let vtl', vtl_ranges = List.fold_right2 (
|
364 |
375 |
fun e typ_e (exprl, range_l)->
|
365 |
376 |
if Types.is_real_type typ_e then
|
... | ... | |
369 |
380 |
e::exprl, None::range_l
|
370 |
381 |
) vtl tin ([], [])
|
371 |
382 |
in
|
372 |
|
if debug then Format.eprintf "... done@ @]@ ";
|
|
383 |
if !debug then Format.eprintf "... done@ @]@ ";
|
373 |
384 |
let required_vars =
|
374 |
385 |
List.fold_left2
|
375 |
386 |
(fun accu e typ_e ->
|
... | ... | |
381 |
392 |
Vars.empty
|
382 |
393 |
vtl' tin
|
383 |
394 |
in
|
384 |
|
if debug then Format.eprintf "Required vars: [%a]@ Printed vars: [%a]@ Remaining required vars: [%a]@ "
|
|
395 |
if !debug then Format.eprintf "Required vars: [%a]@ Printed vars: [%a]@ Remaining required vars: [%a]@ "
|
385 |
396 |
Vars.pp required_vars
|
386 |
397 |
Vars.pp printed_vars
|
387 |
398 |
Vars.pp (Vars.diff required_vars printed_vars)
|
... | ... | |
398 |
409 |
Vars.union written_vars printed_vars, (* adding vdl to new printed vars *)
|
399 |
410 |
Vars.diff vars_to_print written_vars
|
400 |
411 |
|
401 |
|
| LT.MBranch(vt, branches) ->
|
|
412 |
| LT.MBranch(vt, branches) ->
|
|
413 |
|
402 |
414 |
(* Required variables to compute vt are introduced.
|
403 |
415 |
Then each branch is refactored specifically
|
404 |
416 |
*)
|
405 |
|
if debug then Format.eprintf "Branching %a@ " MC.pp_instr hd_instr;
|
|
417 |
if !debug then Format.eprintf "Branching %a@ " MC.pp_instr hd_instr;
|
406 |
418 |
let required_vars = get_expr_real_vars vt in
|
407 |
419 |
let required_vars = Vars.diff required_vars printed_vars in (* remove
|
408 |
420 |
already
|
... | ... | |
416 |
428 |
let vt', _ = optimize_expr nodename constEnv printed_vars vars_env ranges formalEnv vt in
|
417 |
429 |
|
418 |
430 |
let read_vars_tl = get_read_vars tl_instrs in
|
419 |
|
if debug then Format.eprintf "@[<v 2>Dealing with branches@ ";
|
|
431 |
if !debug then Format.eprintf "@[<v 2>Dealing with branches@ ";
|
420 |
432 |
let branches', written_vars, merged_ranges = List.fold_right (
|
421 |
433 |
fun (b_l, b_instrs) (new_branches, written_vars, merged_ranges) ->
|
422 |
434 |
let b_write_vars = get_written_vars b_instrs in
|
... | ... | |
439 |
451 |
RangesInt.merge merged_ranges b_ranges
|
440 |
452 |
|
441 |
453 |
) branches ([], required_vars, ranges) in
|
442 |
|
if debug then Format.eprintf "dealing with branches done@ @]@ ";
|
|
454 |
if !debug then Format.eprintf "dealing with branches done@ @]@ ";
|
443 |
455 |
prefix_instr@[Corelang.update_instr_desc hd_instr (LT.MBranch(vt', branches'))],
|
444 |
456 |
merged_ranges, (* Only step functions call within branches
|
445 |
457 |
may have produced new ranges. We merge this data by
|
... | ... | |
453 |
465 |
|
454 |
466 |
|
455 |
467 |
| LT.MReset(_) | LT.MNoReset _ | LT.MComment _ ->
|
456 |
|
if debug then Format.eprintf "Untouched %a (non real)@ " MC.pp_instr hd_instr;
|
|
468 |
if !debug then Format.eprintf "Untouched %a (non real)@ " MC.pp_instr hd_instr;
|
457 |
469 |
|
458 |
470 |
(* Untouched instruction *)
|
459 |
471 |
[ hd_instr ], (* unmodified instr *)
|
... | ... | |
463 |
475 |
vars_to_print (* no more or less variables to print *)
|
464 |
476 |
|
465 |
477 |
in
|
|
478 |
Format.eprintf "cic@.";
|
466 |
479 |
let tl_instrs, ranges, formalEnv, printed_vars, vars_to_print =
|
467 |
480 |
rewrite_instrs
|
468 |
481 |
nodename
|
... | ... | |
475 |
488 |
printed_vars
|
476 |
489 |
vars_to_print
|
477 |
490 |
in
|
|
491 |
Format.eprintf "la@.";
|
478 |
492 |
hd_instrs @ tl_instrs,
|
479 |
493 |
ranges,
|
480 |
494 |
formalEnv,
|
... | ... | |
508 |
522 |
let get_cst e = match e.LT.expr_desc with
|
509 |
523 |
| LT.Expr_const (LT.Const_real (c,e,s)) ->
|
510 |
524 |
(* calculer la valeur c * 10^e *)
|
511 |
|
Num.float_of_num (Num.div_num c (Num.power_num (Num.num_of_int 10) (Num.num_of_int e)))
|
|
525 |
Num.div_num c (Num.power_num (Num.num_of_int 10) (Num.num_of_int e))
|
512 |
526 |
| _ ->
|
513 |
527 |
Format.eprintf
|
514 |
528 |
"Invalid scala range: %a. It should be a pair of constant floats.@."
|
... | ... | |
516 |
530 |
assert false
|
517 |
531 |
in
|
518 |
532 |
let minv, maxv = get_cst minv, get_cst maxv in
|
519 |
|
if debug then Format.eprintf "variable %s in [%f, %f]@ " v minv maxv;
|
520 |
|
RangesInt.enlarge ranges v (Salsa.SalsaTypes.I(minv, maxv),Salsa.SalsaTypes.J(0.,0.))
|
|
533 |
if !debug then Format.eprintf "variable %s in [%s, %s]@ " v (Num.string_of_num minv) (Num.string_of_num maxv);
|
|
534 |
RangesInt.enlarge ranges v (Salsa.Float.Domain.nnew minv maxv)
|
521 |
535 |
)
|
522 |
536 |
| _ ->
|
523 |
537 |
Format.eprintf
|
... | ... | |
536 |
550 |
)
|
537 |
551 |
in
|
538 |
552 |
(* TODO: should be at least step output + may be memories *)
|
539 |
|
let vars_env = compute_vars_env m in
|
540 |
553 |
|
541 |
|
if debug then Format.eprintf "@[<v 2>Registering node equations@ ";
|
|
554 |
let vars_env = compute_vars_env m in
|
|
555 |
if !debug then Format.eprintf "@[<v 2>Registering node equations@ ";
|
542 |
556 |
let new_instrs, _, _, printed_vars, _ =
|
543 |
557 |
rewrite_instrs
|
544 |
558 |
m.MC.mname.LT.node_id
|
... | ... | |
567 |
581 |
{ s with MC.step_instrs = new_instrs; MC.step_locals = locals } (* we have also to modify local variables to declare new vars *)
|
568 |
582 |
|
569 |
583 |
|
570 |
|
let machine_t2machine_t_optimized_by_salsa constEnv mt =
|
|
584 |
let machine_t2machine_t_optimized_by_salsa constEnv mt =
|
571 |
585 |
try
|
572 |
|
if debug then Format.eprintf "@[<v 8>[salsa] Optimizing machine %s@ " mt.MC.mname.LT.node_id;
|
|
586 |
if !debug then Format.eprintf "@[<v 8>[salsa] Optimizing machine %s@ " mt.MC.mname.LT.node_id;
|
573 |
587 |
let new_step = salsaStep constEnv mt mt.MC.mstep in
|
574 |
|
if debug then Format.eprintf "@]@ ";
|
|
588 |
if !debug then Format.eprintf "@]@ ";
|
575 |
589 |
{ mt with MC.mstep = new_step }
|
576 |
590 |
|
577 |
591 |
|
Updated Salsa plugin to latest version of Salsa.
Some issues wrt machine type features.
Work in progress