From 6d1693b9a18db56292dc417972f18bb70f1a644f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9lio=20Brun?= <lelio.brun@isae-supaero.fr> Date: Mon, 14 Jun 2021 19:06:13 +0200 Subject: [PATCH] work on spec generation almost done --- include/arrow.c | 8 + include/arrow.h | 11 +- include/arrow_spec.c | 25 + include/arrow_spec.h | 71 +- src/arrow.ml | 3 + src/arrow.mli | 1 + src/backends/Ada/ada_backend_adb.ml | 6 +- src/backends/Ada/misc_lustre_function.ml | 2 +- src/backends/C/c_backend_common.ml | 129 ++- src/backends/C/c_backend_header.ml | 17 +- src/backends/C/c_backend_main.ml | 2 +- src/backends/C/c_backend_spec.ml | 1096 +++++++++----------- src/backends/C/c_backend_src.ml | 170 +-- src/backends/EMF/EMF_backend.ml | 18 +- src/backends/Horn/horn_backend_printers.ml | 4 +- src/corelang.ml | 7 +- src/corelang.mli | 7 +- src/dune | 1 + src/lustre_live.ml | 104 ++ src/machine_code.ml | 333 +++--- src/machine_code_common.ml | 290 ++++-- src/machine_code_common.mli | 8 +- src/machine_code_types.ml | 9 +- src/optimize_machine.ml | 27 +- src/plugins/scopes/scopes.ml | 4 +- src/spec_common.ml | 121 +-- src/spec_types.ml | 59 +- src/utils/utils.ml | 10 + 28 files changed, 1502 insertions(+), 1041 deletions(-) create mode 100644 include/arrow_spec.c create mode 100644 src/lustre_live.ml diff --git a/include/arrow.c b/include/arrow.c index 93ae5979..7cfb2e86 100644 --- a/include/arrow.c +++ b/include/arrow.c @@ -12,3 +12,11 @@ struct _arrow_mem * _arrow_alloc () { void _arrow_dealloc (struct _arrow_mem * _alloc) { free (_alloc); } + +_Bool _arrow_step(struct _arrow_mem *self) { + if (self->_reg._first) { + self->_reg._first = 0; + return 1; + } + return 0; +} diff --git a/include/arrow.h b/include/arrow.h index d2956d8b..e0799784 100644 --- a/include/arrow.h +++ b/include/arrow.h @@ -1,8 +1,9 @@ - #ifndef _ARROW #define _ARROW -struct _arrow_mem {struct _arrow_reg {_Bool _first; } _reg; }; +struct _arrow_mem { + struct _arrow_reg {_Bool _first; } _reg; +}; extern struct _arrow_mem *_arrow_alloc (); @@ -23,12 +24,8 @@ extern void _arrow_dealloc (struct _arrow_mem *); #define _arrow_clear(self) {} -/* #define _arrow_step(x,y,output,self) ((self)->_reg._first?((self)->_reg._first=0,(*output = x)):(*output = y)) */ - #define _arrow_reset(self) {(self)->_reg._first = 1;} -/* Step macro for specialized arrows of the form: (true -> false) */ - -#define _once_step(output,self) { *output = (self)->_reg._first; if ((self)->_reg._first) { (self)->_reg._first=0; }; } +_Bool _arrow_step(struct _arrow_mem *self); #endif diff --git a/include/arrow_spec.c b/include/arrow_spec.c new file mode 100644 index 00000000..d47e314f --- /dev/null +++ b/include/arrow_spec.c @@ -0,0 +1,25 @@ +#include <stdlib.h> +#include <assert.h> +#include "arrow_spec.h" + +struct _arrow_mem * _arrow_alloc () { + struct _arrow_mem *_alloc; + _alloc = (struct _arrow_mem *) malloc(sizeof(struct _arrow_mem *)); + assert (_alloc); + return _alloc; +} + +void _arrow_dealloc (struct _arrow_mem * _alloc) { + free (_alloc); +} + +_Bool _arrow_step(struct _arrow_mem *self) + /*@ ghost (struct _arrow_mem_ghost \ghost *mem) */ +{ + if (self->_reg._first) { + self->_reg._first = 0; + //@ ghost _arrow_step_ghost(*mem); + return 1; + } + return 0; +} diff --git a/include/arrow_spec.h b/include/arrow_spec.h index 7ac02a4b..b1e1b544 100644 --- a/include/arrow_spec.h +++ b/include/arrow_spec.h @@ -1,29 +1,64 @@ #ifndef ARROW_SPEC_H_ #define ARROW_SPEC_H_ +struct _arrow_mem { + struct _arrow_reg {_Bool _first; } _reg; +}; + +extern struct _arrow_mem *_arrow_alloc (); + +extern void _arrow_dealloc (struct _arrow_mem *); + +#define _arrow_DECLARE(attr, inst)\ + attr struct _arrow_mem inst; + +#define _arrow_LINK(inst) do {\ + ;\ +} while (0) + +#define _arrow_ALLOC(attr, inst)\ + _arrow_DECLARE(attr, inst);\ + _arrow_LINK(inst) + +#define _arrow_init(self) {} + +#define _arrow_clear(self) {} + +#define _arrow_reset(self) {(self)->_reg._first = 1;} + /* ACSL arrow spec */ //@ ghost struct _arrow_mem_ghost {struct _arrow_reg _reg;}; -/*@ - predicate _arrow_valid(struct _arrow_mem *self) = - \valid(self); -*/ -/*@ - predicate _arrow_initialization(struct _arrow_mem_ghost mem_in) = - mem_in._reg._first == 1; + +#define _arrow_reset_ghost(mem) (mem)._reg._first = 1 +#define _arrow_step_ghost(mem) (mem)._reg._first = 0 + +/*@ predicate _arrow_initialization(struct _arrow_mem_ghost mem_in) = + mem_in._reg._first == 1; + */ + +/*@ predicate _arrow_transition(struct _arrow_mem_ghost mem_in, + struct _arrow_mem_ghost mem_out, + _Bool out) = + out == mem_in._reg._first + && (mem_in._reg._first ? (mem_out._reg._first == 0) + : (mem_out._reg._first == mem_in._reg._first)); */ -/*@ - predicate _arrow_transition(struct _arrow_mem_ghost mem_in, - integer x, integer y, - struct _arrow_mem_ghost mem_out, _Bool out) = - (mem_in._reg._first ? (mem_out._reg._first == 0 - && out == x) - : (mem_out._reg._first == mem_in._reg._first - && out == y)); + +/*@ predicate _arrow_ghost(struct _arrow_mem_ghost mem, + struct _arrow_mem *self) = + mem._reg._first == self->_reg._first; */ + /*@ - predicate _arrow_ghost(struct _arrow_mem_ghost mem, - struct _arrow_mem *self) = - mem._reg._first == self->_reg._first; + requires \separated(mem, self); + requires _arrow_ghost(*mem, self); + ensures _arrow_ghost(*mem, self); + ensures \result == \old(self->_reg._first); + ensures self->_reg._first == 0; + ensures !\old(mem->_reg._first) ==> *mem == \old(*mem); + assigns mem->_reg._first, self->_reg._first; */ +_Bool _arrow_step(struct _arrow_mem *self) + /*@ ghost (struct _arrow_mem_ghost \ghost *mem) */; #endif // ARROW_SPEC_H_ diff --git a/src/arrow.ml b/src/arrow.ml index 610b4792..23a71b1f 100644 --- a/src/arrow.ml +++ b/src/arrow.ml @@ -30,3 +30,6 @@ let arrow_top_decl () = top_decl_itf = false; top_decl_loc = Location.dummy_loc } + +let td_is_arrow td = + Corelang.node_name td = arrow_id diff --git a/src/arrow.mli b/src/arrow.mli index ace9a285..31916c58 100644 --- a/src/arrow.mli +++ b/src/arrow.mli @@ -1,3 +1,4 @@ val arrow_id: string val arrow_top_decl: unit -> Lustre_types.top_decl val arrow_desc: Lustre_types.node_desc +val td_is_arrow: Lustre_types.top_decl -> bool diff --git a/src/backends/Ada/ada_backend_adb.ml b/src/backends/Ada/ada_backend_adb.ml index 9ab15e30..18a0c7dd 100644 --- a/src/backends/Ada/ada_backend_adb.ml +++ b/src/backends/Ada/ada_backend_adb.ml @@ -85,8 +85,10 @@ struct match get_instr_desc instr with (* no reset *) | MNoReset _ -> () + (* TODO: handle clear_reset *) + | MClearReset -> () (* reset *) - | MReset i when List.mem_assoc i typed_submachines -> + | MSetReset i when List.mem_assoc i typed_submachines -> let (substitution, submachine) = get_instance i typed_submachines in let pp_package = pp_package_name_with_polymorphic substitution submachine in let args = if is_machine_statefull submachine then [[pp_state i]] else [] in @@ -149,7 +151,7 @@ struct **) let pp_reset_definition env typed_submachines fmt (m, m_spec_opt) = let build_assign = function var -> - mkinstr Spec_types.True (MStateAssign (var, mk_default_value var.var_type)) + mkinstr (MStateAssign (var, mk_default_value var.var_type)) in let env, memory = match m_spec_opt with | None -> env, m.mmemory diff --git a/src/backends/Ada/misc_lustre_function.ml b/src/backends/Ada/misc_lustre_function.ml index 35fb018c..45ebcd91 100644 --- a/src/backends/Ada/misc_lustre_function.ml +++ b/src/backends/Ada/misc_lustre_function.ml @@ -268,7 +268,7 @@ let rec push_if_in_expr = function let assign = if state then MStateAssign (ident, value) else MLocalAssign (ident, value) in { instr_desc = assign; lustre_eq = None; - instr_spec = Spec_types.True + instr_spec = [] } in let mkval_var id = { diff --git a/src/backends/C/c_backend_common.ml b/src/backends/C/c_backend_common.ml index 030e8bd9..bcffd9e9 100644 --- a/src/backends/C/c_backend_common.ml +++ b/src/backends/C/c_backend_common.ml @@ -37,6 +37,14 @@ let file_to_module_name basename = let baseNAME = protect_filename baseNAME in baseNAME +let pp_ptr fmt = + fprintf fmt "*%s" + +let reset_label = "Reset" + +let pp_label fmt = + fprintf fmt "%s:" + let var_is name v = v.var_id = name @@ -55,6 +63,7 @@ let mk_self = mk_local "self" let mk_mem = mk_local "mem" let mk_mem_in = mk_local "mem_in" let mk_mem_out = mk_local "mem_out" +let mk_mem_reset = mk_local "mem_reset" (* Generation of a non-clashing name for the instance variable of static allocation macro *) let mk_instance m = @@ -118,13 +127,18 @@ let pp_global_init_name fmt id = fprintf fmt "%s_INIT" id let pp_global_clear_name fmt id = fprintf fmt "%s_CLEAR" id let pp_machine_memtype_name ?(ghost=false) fmt id = fprintf fmt "struct %s_mem%s" id (if ghost then "_ghost" else "") +let pp_machine_decl ?(ghost=false) pp_var fmt (id, var) = + fprintf fmt "%a %a" (pp_machine_memtype_name ~ghost) id pp_var var +let pp_machine_decl' ?(ghost=false) fmt = + pp_machine_decl ~ghost pp_print_string fmt let pp_machine_regtype_name fmt id = fprintf fmt "struct %s_reg" id let pp_machine_alloc_name fmt id = fprintf fmt "%s_alloc" id let pp_machine_dealloc_name fmt id = fprintf fmt "%s_dealloc" id let pp_machine_static_declare_name fmt id = fprintf fmt "%s_DECLARE" id let pp_machine_static_link_name fmt id = fprintf fmt "%s_LINK" id let pp_machine_static_alloc_name fmt id = fprintf fmt "%s_ALLOC" id -let pp_machine_reset_name fmt id = fprintf fmt "%s_reset" id +let pp_machine_set_reset_name fmt id = fprintf fmt "%s_set_reset" id +let pp_machine_clear_reset_name fmt id = fprintf fmt "%s_clear_reset" id let pp_machine_init_name fmt id = fprintf fmt "%s_init" id let pp_machine_clear_name fmt id = fprintf fmt "%s_clear" id let pp_machine_step_name fmt id = fprintf fmt "%s_step" id @@ -583,6 +597,9 @@ let rec pp_value_suffix ?(indirect=true) m self var_type loop_vars pp_var fmt va then fprintf fmt "%a%a" pp_var v pp_suffix loop_vars else fprintf fmt "%s%s_reg.%a%a" self (if indirect then "->" else ".") pp_var v pp_suffix loop_vars + else if is_reset_flag v then + fprintf fmt "%s%s%a%a" + self (if indirect then "->" else ".") pp_var v pp_suffix loop_vars else fprintf fmt "%a%a" pp_var v pp_suffix loop_vars | _, Cst cst -> @@ -610,7 +627,7 @@ let rec pp_value_suffix ?(indirect=true) m self var_type loop_vars pp_var fmt va let print_machine_struct ?(ghost=false) fmt m = if not (fst (Machine_code_common.get_stateless_status m)) then (* Define struct *) - fprintf fmt "@[<v 2>%a {%a%a@]@,};" + fprintf fmt "@[<v 2>%a {@,_Bool _reset;%a%a@]@,};" (pp_machine_memtype_name ~ghost) m.mname.node_id (if ghost then (fun fmt -> function @@ -658,46 +675,74 @@ let print_dealloc_prototype fmt name = pp_machine_dealloc_name name (pp_machine_memtype_name ~ghost:false) name -let print_reset_prototype self fmt (name, static) = - fprintf fmt "void %a (%a%a *%s)" - pp_machine_reset_name name - (pp_print_list ~pp_sep:pp_print_comma ~pp_eol:pp_print_comma - pp_c_decl_input_var) static - (pp_machine_memtype_name ~ghost:false) name - self - -let print_init_prototype self fmt (name, static) = - fprintf fmt "void %a (%a%a *%s)" - pp_machine_init_name name - (pp_print_list ~pp_sep:pp_print_comma ~pp_eol:pp_print_comma - pp_c_decl_input_var) static - (pp_machine_memtype_name ~ghost:false) name - self - -let print_clear_prototype self fmt (name, static) = - fprintf fmt "void %a (%a%a *%s)" - pp_machine_clear_name name - (pp_print_list ~pp_sep:pp_print_comma ~pp_eol:pp_print_comma - pp_c_decl_input_var) static - (pp_machine_memtype_name ~ghost:false) name - self - -let print_stateless_prototype fmt (name, inputs, outputs) = - fprintf fmt "void %a (@[<v>%a%a@])" - pp_machine_step_name name - (pp_print_list ~pp_sep:pp_print_comma ~pp_eol:pp_print_comma - ~pp_epilogue:pp_print_cut pp_c_decl_input_var) inputs - (pp_print_list ~pp_sep:pp_print_comma pp_c_decl_output_var) outputs - -let print_step_prototype self fmt (name, inputs, outputs) = - fprintf fmt "void %a (@[<v>%a%a%a *%s@])" - pp_machine_step_name name - (pp_print_list ~pp_sep:pp_print_comma ~pp_eol:pp_print_comma - ~pp_epilogue:pp_print_cut pp_c_decl_input_var) inputs - (pp_print_list ~pp_sep:pp_print_comma ~pp_eol:pp_print_comma - ~pp_epilogue:pp_print_cut pp_c_decl_output_var) outputs - (pp_machine_memtype_name ~ghost:false) name - self +module type MODIFIERS_GHOST_PROTO = sig + val pp_ghost_parameters: formatter -> (string * (formatter -> string -> unit)) list -> unit +end + +module EmptyGhostProto: MODIFIERS_GHOST_PROTO = struct + let pp_ghost_parameters _ _ = () +end + +module Protos (Mod: MODIFIERS_GHOST_PROTO) = struct + + let pp_mem_ghost name fmt mem = + pp_machine_decl ~ghost:true + (fun fmt mem -> fprintf fmt "\ghost %a" pp_ptr mem) fmt + (name, mem) + + let print_clear_reset_prototype self mem fmt (name, static) = + fprintf fmt "@[<v>void %a (%a%a *%s)%a@]" + pp_machine_clear_reset_name name + (pp_comma_list ~pp_eol:pp_print_comma + pp_c_decl_input_var) static + (pp_machine_memtype_name ~ghost:false) name + self + Mod.pp_ghost_parameters [mem, pp_mem_ghost name] + + let print_set_reset_prototype self mem fmt (name, static) = + fprintf fmt "@[<v>void %a (%a%a *%s)%a@]" + pp_machine_set_reset_name name + (pp_comma_list ~pp_eol:pp_print_comma + pp_c_decl_input_var) static + (pp_machine_memtype_name ~ghost:false) name + self + Mod.pp_ghost_parameters [mem, pp_mem_ghost name] + + let print_step_prototype self mem fmt (name, inputs, outputs) = + fprintf fmt "@[<v>void %a (@[<v>%a%a%a *%s@])%a@]" + pp_machine_step_name name + (pp_comma_list ~pp_eol:pp_print_comma + ~pp_epilogue:pp_print_cut pp_c_decl_input_var) inputs + (pp_comma_list ~pp_eol:pp_print_comma + ~pp_epilogue:pp_print_cut pp_c_decl_output_var) outputs + (pp_machine_memtype_name ~ghost:false) name + self + Mod.pp_ghost_parameters [mem, pp_mem_ghost name] + + let print_init_prototype self fmt (name, static) = + fprintf fmt "void %a (%a%a *%s)" + pp_machine_init_name name + (pp_comma_list ~pp_eol:pp_print_comma + pp_c_decl_input_var) static + (pp_machine_memtype_name ~ghost:false) name + self + + let print_clear_prototype self fmt (name, static) = + fprintf fmt "void %a (%a%a *%s)" + pp_machine_clear_name name + (pp_comma_list ~pp_eol:pp_print_comma + pp_c_decl_input_var) static + (pp_machine_memtype_name ~ghost:false) name + self + + let print_stateless_prototype fmt (name, inputs, outputs) = + fprintf fmt "void %a (@[<v>%a%a@])" + pp_machine_step_name name + (pp_comma_list ~pp_eol:pp_print_comma + ~pp_epilogue:pp_print_cut pp_c_decl_input_var) inputs + (pp_comma_list pp_c_decl_output_var) outputs + +end let print_import_prototype fmt dep = fprintf fmt "#include \"%s.h\"" dep.name diff --git a/src/backends/C/c_backend_header.ml b/src/backends/C/c_backend_header.ml index 3e667072..74b3ff08 100644 --- a/src/backends/C/c_backend_header.ml +++ b/src/backends/C/c_backend_header.ml @@ -22,17 +22,21 @@ open C_backend_common module type MODIFIERS_HDR = sig + module GhostProto: MODIFIERS_GHOST_PROTO val print_machine_decl_prefix: Format.formatter -> machine_t -> unit val pp_import_standard_spec: formatter -> unit -> unit end module EmptyMod = struct + module GhostProto = EmptyGhostProto let print_machine_decl_prefix = fun _ _ -> () let pp_import_standard_spec _ _ = () end module Main = functor (Mod: MODIFIERS_HDR) -> struct + module Protos = Protos(Mod.GhostProto) + let print_import_standard fmt () = (* if Machine_types.has_machine_type () then *) fprintf fmt @@ -231,7 +235,7 @@ module Main = functor (Mod: MODIFIERS_HDR) -> struct assert false end else if inode.nodei_stateless then - fprintf fmt "extern %a;" print_stateless_prototype prototype + fprintf fmt "extern %a;" Protos.print_stateless_prototype prototype else let static_inputs = List.filter (fun v -> v.var_dec_const) inode.nodei_inputs in @@ -239,16 +243,19 @@ module Main = functor (Mod: MODIFIERS_HDR) -> struct List.exists (fun v -> v.var_id = name) (inode.nodei_inputs @ inode.nodei_outputs) in let self = mk_new_name used "self" in + let mem = mk_new_name used "mem" in let static_prototype = (inode.nodei_id, static_inputs) in fprintf fmt "extern %a;@,\ + extern %a;@,\ extern %a;@,\ extern %a;@,\ extern %a;" - (print_reset_prototype self) static_prototype - (print_init_prototype self) static_prototype - (print_clear_prototype self) static_prototype - (print_step_prototype self) prototype + (Protos.print_set_reset_prototype self mem) static_prototype + (Protos.print_clear_reset_prototype self mem) static_prototype + (Protos.print_init_prototype self) static_prototype + (Protos.print_clear_prototype self) static_prototype + (Protos.print_step_prototype self mem) prototype let print_const_top_decl fmt tdecl = let cdecl = const_of_top tdecl in diff --git a/src/backends/C/c_backend_main.ml b/src/backends/C/c_backend_main.ml index 187abec6..b66d794c 100644 --- a/src/backends/C/c_backend_main.ml +++ b/src/backends/C/c_backend_main.ml @@ -87,7 +87,7 @@ module Main = functor (Mod: MODIFIERS_MAINSRC) -> struct fprintf fmt "%a *main_mem = %a();" (pp_machine_memtype_name ~ghost:false) mname pp_machine_alloc_name mname) () - pp_machine_reset_name mname + pp_machine_set_reset_name mname main_mem let print_global_initialize fmt basename = diff --git a/src/backends/C/c_backend_spec.ml b/src/backends/C/c_backend_spec.ml index 10562936..c87b1f74 100644 --- a/src/backends/C/c_backend_spec.ml +++ b/src/backends/C/c_backend_spec.ml @@ -1,3 +1,4 @@ + (********************************************************************) (* *) (* The LustreC compiler toolset / The LustreC Development Team *) @@ -13,132 +14,20 @@ open Utils.Format open Lustre_types open Machine_code_types open C_backend_common -open Machine_code_common open Corelang +open Spec_types +open Spec_common +open Machine_code_common (**************************************************************************) (* Printing spec for c *) (**************************************************************************) -(* OLD STUFF ??? - - -let pp_acsl_type var fmt t = - let rec aux t pp_suffix = - match (Types.repr t).Types.tdesc with - | Types.Tclock t' -> aux t' pp_suffix - | Types.Tbool -> fprintf fmt "int %s%a" var pp_suffix () - | Types.Treal -> fprintf fmt "real %s%a" var pp_suffix () - | Types.Tint -> fprintf fmt "int %s%a" var pp_suffix () - | Types.Tarray (d, t') -> - let pp_suffix' fmt () = fprintf fmt "%a[%a]" pp_suffix () pp_c_dimension d in - aux t' pp_suffix' - (* | Types.Tstatic (_, t') -> fprintf fmt "const "; aux t' pp_suffix *) - (* | Types.Tconst ty -> fprintf fmt "%s %s" ty var *) - (* | Types.Tarrow (_, _) -> fprintf fmt "void (\*%s)()" var *) - | _ -> eprintf "internal error: pp_acsl_type %a@." Types.print_ty t; assert false - in aux t (fun fmt () -> ()) - -let pp_acsl_var_decl fmt id = - pp_acsl_type id.var_id fmt id.var_type - - -let rec pp_eexpr is_output fmt eexpr = - let pp_eexpr = pp_eexpr is_output in - match eexpr.eexpr_desc with - | EExpr_const c -> Printers.pp_econst fmt c - | EExpr_ident id -> - if is_output id then pp_print_string fmt ("*" ^ id) else pp_print_string fmt id - | EExpr_tuple el -> Utils.fprintf_list ~sep:"," pp_eexpr fmt el - | EExpr_arrow (e1, e2) -> fprintf fmt "%a -> %a" pp_eexpr e1 pp_eexpr e2 - | EExpr_fby (e1, e2) -> fprintf fmt "%a fby %a" pp_eexpr e1 pp_eexpr e2 - (* | EExpr_concat (e1, e2) -> fprintf fmt "%a::%a" pp_eexpr e1 pp_eexpr e2 *) - (* | EExpr_tail e -> fprintf fmt "tail %a" pp_eexpr e *) - | EExpr_pre e -> fprintf fmt "pre %a" pp_eexpr e - | EExpr_when (e, id) -> fprintf fmt "%a when %s" pp_eexpr e id - | EExpr_merge (id, e1, e2) -> - fprintf fmt "merge (%s, %a, %a)" id pp_eexpr e1 pp_eexpr e2 - | EExpr_appl (id, e, r) -> pp_eapp is_output fmt id e r - | EExpr_forall (vars, e) -> fprintf fmt "forall %a; %a" Printers.pp_node_args vars pp_eexpr e - | EExpr_exists (vars, e) -> fprintf fmt "exists %a; %a" Printers.pp_node_args vars pp_eexpr e - - - (* | EExpr_whennot _ *) - (* | EExpr_uclock _ *) - (* | EExpr_dclock _ *) - (* | EExpr_phclock _ -> assert false *) -and pp_eapp is_output fmt id e r = - let pp_eexpr = pp_eexpr is_output in - match r with - | None -> - (match id, e.eexpr_desc with - | "+", EExpr_tuple([e1;e2]) -> fprintf fmt "(%a + %a)" pp_eexpr e1 pp_eexpr e2 - | "uminus", _ -> fprintf fmt "(- %a)" pp_eexpr e - | "-", EExpr_tuple([e1;e2]) -> fprintf fmt "(%a - %a)" pp_eexpr e1 pp_eexpr e2 - | "*", EExpr_tuple([e1;e2]) -> fprintf fmt "(%a * %a)" pp_eexpr e1 pp_eexpr e2 - | "/", EExpr_tuple([e1;e2]) -> fprintf fmt "(%a / %a)" pp_eexpr e1 pp_eexpr e2 - | "mod", EExpr_tuple([e1;e2]) -> fprintf fmt "(%a mod %a)" pp_eexpr e1 pp_eexpr e2 - | "&&", EExpr_tuple([e1;e2]) -> fprintf fmt "(%a && %a)" pp_eexpr e1 pp_eexpr e2 - | "||", EExpr_tuple([e1;e2]) -> fprintf fmt "(%a || %a)" pp_eexpr e1 pp_eexpr e2 - | "xor", EExpr_tuple([e1;e2]) -> fprintf fmt "(%a ^^ %a)" pp_eexpr e1 pp_eexpr e2 - | "impl", EExpr_tuple([e1;e2]) -> fprintf fmt "(%a ==> %a)" pp_eexpr e1 pp_eexpr e2 - | "<", EExpr_tuple([e1;e2]) -> fprintf fmt "(%a < %a)" pp_eexpr e1 pp_eexpr e2 - | "<=", EExpr_tuple([e1;e2]) -> fprintf fmt "(%a <= %a)" pp_eexpr e1 pp_eexpr e2 - | ">", EExpr_tuple([e1;e2]) -> fprintf fmt "(%a > %a)" pp_eexpr e1 pp_eexpr e2 - | ">=", EExpr_tuple([e1;e2]) -> fprintf fmt "(%a >= %a)" pp_eexpr e1 pp_eexpr e2 - | "!=", EExpr_tuple([e1;e2]) -> fprintf fmt "(%a != %a)" pp_eexpr e1 pp_eexpr e2 - | "=", EExpr_tuple([e1;e2]) -> fprintf fmt "(%a == %a)" pp_eexpr e1 pp_eexpr e2 - | "not", _ -> fprintf fmt "(! %a)" pp_eexpr e - | "ite", EExpr_tuple([e1;e2;e3]) -> fprintf fmt "(if %a then %a else %a)" pp_eexpr e1 pp_eexpr e2 pp_eexpr e3 - | _ -> fprintf fmt "%s (%a)" id pp_eexpr e) - | Some x -> fprintf fmt "%s (%a) every %s" id pp_eexpr e x - -let pp_ensures is_output fmt e = - match e with - | EnsuresExpr e -> fprintf fmt "ensures %a;@ " (pp_eexpr is_output) e - | SpecObserverNode (name, args) -> fprintf fmt "observer %s (%a);@ " name (Utils.fprintf_list ~sep:", " (pp_eexpr is_output)) args - -let pp_acsl_spec outputs fmt spec = - let is_output = fun oid -> List.exists (fun v -> v.var_id = oid) outputs in - let pp_eexpr = pp_eexpr is_output in - fprintf fmt "@[<v 2>/*@@ "; - Utils.fprintf_list ~sep:"" (fun fmt r -> fprintf fmt "requires %a;@ " pp_eexpr r) fmt spec.requires; - Utils.fprintf_list ~sep:"" (pp_ensures is_output) fmt spec.ensures; - fprintf fmt "@ "; - (* fprintf fmt "assigns *self%t%a;@ " *) - (* (fun fmt -> if List.length outputs > 0 then fprintf fmt ", ") *) - (* (fprintf_list ~sep:"," (fun fmt v -> fprintf fmt "*%s" v.var_id)) outputs; *) - Utils.fprintf_list ~sep:"@ " (fun fmt (name, assumes, requires) -> - fprintf fmt "behavior %s:@[@ %a@ %a@]" - name - (Utils.fprintf_list ~sep:"@ " (fun fmt r -> fprintf fmt "assumes %a;" pp_eexpr r)) assumes - (Utils.fprintf_list ~sep:"@ " (pp_ensures is_output)) requires - ) fmt spec.behaviors; - fprintf fmt "@]@ */@."; - () - - - - -let print_machine_decl_prefix fmt m = - (* Print specification if any *) - (match m.mspec with - | None -> () - | Some spec -> - pp_acsl_spec m.mstep.step_outputs fmt spec - ) - - *) - - (* TODO ACSL + +(* TODO ACSL Return updates machines (eg with local annotations) and acsl preamble *) let preprocess_acsl machines = machines, [] -(* TODO: This preamble shall be a list of types, axiomatics, predicates, theorems *) -(* let pp_acsl_preamble fmt _preamble = - * fprintf fmt ""; - * () *) - let pp_acsl_basic_type_desc t_desc = if Types.is_bool_type t_desc then (* if !Options.cpp then "bool" else "_Bool" *) @@ -151,22 +40,14 @@ let pp_acsl_basic_type_desc t_desc = else assert false (* Not a basic C type. Do not handle arrays or pointers *) -module VarDecl = struct - type t = var_decl - let compare v1 v2 = compare v1.var_id v2.var_id -end -module VDSet = Set.Make(VarDecl) - -module Live = Map.Make(Int) - -let pp_spec pp fmt = - fprintf fmt "@[<v>/*%@@[<v>@,%a@]@,*/@]" pp +let pp_acsl pp fmt = + fprintf fmt "@[<v>/*%@ @[<v>%a@]@,*/@]" pp -let pp_spec_cut pp fmt = - fprintf fmt "%a@," (pp_spec pp) +let pp_acsl_cut pp fmt = + fprintf fmt "%a@," (pp_acsl pp) -let pp_spec_line pp fmt = - fprintf fmt "//%@ %a@," pp +let pp_acsl_line pp fmt = + fprintf fmt "//%@ @[<h>%a@]" pp let pp_requires pp_req fmt = fprintf fmt "requires %a;" pp_req @@ -174,11 +55,13 @@ let pp_requires pp_req fmt = let pp_ensures pp_ens fmt = fprintf fmt "ensures %a;" pp_ens +let pp_assumes pp_asm fmt = + fprintf fmt "assumes %a;" pp_asm + let pp_assigns pp = - pp_print_list + pp_comma_list ~pp_prologue:(fun fmt () -> pp_print_string fmt "assigns ") ~pp_epilogue:pp_print_semicolon' - ~pp_sep:pp_print_comma pp let pp_ghost pp_gho fmt = @@ -214,73 +97,46 @@ let pp_reg self fmt field = let pp_true fmt () = pp_print_string fmt "\\true" -(* let memories machines m = - * let open List in - * let grow paths i = - * match paths with - * | [] -> [[i]] - * | _ -> map (cons i) paths - * in - * let rec aux paths m = - * map (fun (i, (td, _)) -> - * let paths = grow paths i in - * try - * let m = find (fun m -> m.mname.node_id = node_name td) machines in - * aux paths m - * with Not_found -> paths) - * m.minstances |> flatten - * in - * aux [] m |> map rev *) +let pp_false fmt () = + pp_print_string fmt "\\false" + +let pp_at pp_v fmt (v, l) = + fprintf fmt "\\at(%a, %s)" pp_v v l let instances machines m = let open List in - let grow paths i mems = + let grow paths i td mems = match paths with - | [] -> [[i, mems]] - | _ -> map (cons (i, mems)) paths + | [] -> [[i, (td, mems)]] + | _ -> map (cons (i, (td, mems))) paths in let rec aux paths m = map (fun (i, (td, _)) -> try let m = find (fun m -> m.mname.node_id = node_name td) machines in - aux (grow paths i m.mmemory) m - with Not_found -> grow paths i []) + aux (grow paths i td m.mmemory) m + with Not_found -> grow paths i td []) m.minstances |> flatten in aux [] m |> map rev let memories insts = List.(map (fun path -> - let mems = snd (hd (rev path)) in + let _, (_, mems) = hd (rev path) in map (fun mem -> path, mem) mems) insts |> flatten) -let pp_instance = +let pp_instance ?(indirect=true) ptr = pp_print_list - ~pp_prologue:(fun fmt () -> pp_print_string fmt "self->") - ~pp_sep:(fun fmt () -> pp_print_string fmt "->") + ~pp_prologue:(fun fmt () -> fprintf fmt "%s->" ptr) + ~pp_sep:(fun fmt () -> pp_print_string fmt (if indirect then "->" else ".")) (fun fmt (i, _) -> pp_print_string fmt i) -let pp_memory fmt (path, mem) = - pp_access (pp_indirect pp_instance pp_print_string) pp_var_decl +let pp_memory ?(indirect=true) ptr fmt (path, mem) = + pp_access + ((if indirect then pp_indirect else pp_access) + (pp_instance ~indirect ptr) pp_print_string) + pp_var_decl fmt ((path, "_reg"), mem) - (* let mems = snd List.(hd (rev path)) in - * pp_print_list - * ~pp_sep:pp_print_comma - * (fun fmt mem -> pp_access pp_instance pp_var_decl fmt (path, mem)) - * fmt - * mems *) - (* let mems = ref [] in - * let pp fmt = - * pp_print_list - * ~pp_prologue:(fun fmt () -> pp_print_string fmt "self->") - * ~pp_sep:(fun fmt () -> pp_print_string fmt "->") - * (fun fmt (i, regs) -> mems := regs; pp_print_string fmt i) - * fmt - * in - * pp_print_list - * ~pp_sep:pp_print_comma - * (fun fmt mem -> pp_access pp pp_var_decl fmt (insts, mem)) - * fmt !mems *) let prefixes l = let rec pref acc = function @@ -292,27 +148,28 @@ let prefixes l = let powerset_instances paths = List.map prefixes paths |> List.flatten -let pp_separated self fmt (paths, ptrs) = - fprintf fmt "\\separated(@[<h>%s%a%a@])" +let pp_separated self mem fmt (paths, ptrs) = + fprintf fmt "\\separated(@[<v>%s, %s@;%a@;%a@])" self - (pp_print_list - ~pp_prologue:pp_print_comma - ~pp_sep:pp_print_comma - pp_instance) + mem + (pp_comma_list + ~pp_prologue:pp_print_comma' + (pp_instance self)) paths - (pp_print_list - ~pp_prologue:pp_print_comma - ~pp_sep:pp_print_comma + (pp_comma_list + ~pp_prologue:pp_print_comma' pp_var_decl) ptrs let pp_separated' = - pp_print_list + pp_comma_list ~pp_prologue:(fun fmt () -> pp_print_string fmt "\\separated(") ~pp_epilogue:pp_print_cpar - ~pp_sep:pp_print_comma pp_var_decl +let pp_par pp fmt = + fprintf fmt "(%a)" pp + let pp_forall pp_l pp_r fmt (l, r) = fprintf fmt "@[<v 2>\\forall %a;@,%a@]" pp_l l @@ -350,12 +207,30 @@ let pp_and_l pp_v fmt = pp_v fmt +let pp_or pp_l pp_r fmt (l, r) = + fprintf fmt "@[<v>%a @ || %a@]" + pp_l l + pp_r r + +let pp_or_l pp_v fmt = + pp_print_list + ~pp_open_box:pp_open_vbox0 + ~pp_sep:(fun fmt () -> fprintf fmt "@,|| ") + pp_v + fmt + +let pp_not pp fmt = + fprintf fmt "!%a" pp + let pp_valid pp = pp_and_l (* pp_print_list *) (* ~pp_sep:pp_print_cut *) (fun fmt x -> fprintf fmt "\\valid(%a)" pp x) +let pp_old pp fmt = + fprintf fmt "\\old(%a)" pp + let pp_ite pp_c pp_t pp_f fmt (c, t, f) = fprintf fmt "(%a @[<hov>? %a@ : %a)@]" pp_c c @@ -365,31 +240,18 @@ let pp_ite pp_c pp_t pp_f fmt (c, t, f) = let pp_paren pp fmt v = fprintf fmt "(%a)" pp v -let pp_machine_decl fmt (id, mem_type, var) = - fprintf fmt "struct %s_%s %s" id mem_type var - -let pp_mem_ghost pp_mem pp_self ?i fmt (name, mem, self) = - fprintf fmt "%s_ghost%a(@[<hov>%a,@ %a@])" - name - (pp_print_option pp_print_int) i - pp_mem mem - pp_self self - -let pp_mem_ghost' = pp_mem_ghost pp_print_string pp_print_string - -let pp_mem_init pp_mem fmt (name, mem) = +let pp_initialization pp_mem fmt (name, mem) = fprintf fmt "%s_initialization(%a)" name pp_mem mem -let pp_mem_init' = pp_mem_init pp_print_string +let pp_initialization' = pp_initialization pp_print_string -let pp_locals m fmt vs = - pp_print_list +let pp_locals m = + pp_comma_list ~pp_open_box:pp_open_hbox - ~pp_sep:pp_print_comma - (pp_c_decl_local_var ~pp_c_basic_type_desc:pp_acsl_basic_type_desc m) fmt vs + (pp_c_decl_local_var ~pp_c_basic_type_desc:pp_acsl_basic_type_desc m) let pp_ptr_decl fmt v = - fprintf fmt "*%s" v.var_id + pp_ptr fmt v.var_id let pp_basic_assign_spec pp_l pp_r fmt typ var_name value = if Types.is_real_type typ && !Options.mpfr @@ -399,8 +261,8 @@ let pp_basic_assign_spec pp_l pp_r fmt typ var_name value = else pp_equal pp_l pp_r fmt (var_name, value) -let pp_assign_spec - m self_l pp_var_l self_r pp_var_r fmt (var_type, var_name, value) = +let pp_assign_spec m self_l pp_var_l indirect_l self_r pp_var_r indirect_r fmt + (var_type, var_name, value) = let depth = expansion_depth value in let loop_vars = mk_loop_variables m var_type depth in let reordered_loop_vars = reorder_loop_variables loop_vars in @@ -408,8 +270,8 @@ let pp_assign_spec match vars with | [] -> pp_basic_assign_spec - (pp_value_suffix ~indirect:false m self_l var_type loop_vars pp_var_l) - (pp_value_suffix ~indirect:false m self_r var_type loop_vars pp_var_r) + (pp_value_suffix ~indirect:indirect_l m self_l var_type loop_vars pp_var_l) + (pp_value_suffix ~indirect:indirect_r m self_r var_type loop_vars pp_var_r) fmt typ var_name value | (_d, LVar _i) :: _q -> assert false @@ -441,118 +303,210 @@ let pp_c_var_read m fmt id = else fprintf fmt "%s" id.var_id -let rec assigned s instr = - let open VDSet in - match instr.instr_desc with - | MLocalAssign (x, _) -> - add x s - | MStep (xs, _, _) -> - union s (of_list xs) - | MBranch (_, brs) -> - List.(fold_left (fun s (_, instrs) -> fold_left assigned s instrs) s brs) - | _ -> s - -let rec occur_val s v = - let open VDSet in - match v.value_desc with - | Var x -> - add x s - | Fun (_, vs) - | Array vs -> - List.fold_left occur_val s vs - | Access (v1, v2) - | Power (v1, v2) -> - occur_val (occur_val s v1) v2 - | _ -> s - -let rec occur s instr = - let open VDSet in - match instr.instr_desc with - | MLocalAssign (_, v) - | MStateAssign (_, v) -> - occur_val s v - | MStep (_, _, vs) -> - List.fold_left occur_val s vs - | MBranch (v, brs) -> - List.(fold_left (fun s (_, instrs) -> fold_left occur s instrs) - (occur_val s v) brs) - | _ -> s - -let live = Hashtbl.create 32 - -let set_live_of m = - let open VDSet in - let locals = of_list m.mstep.step_locals in - let outputs = of_list m.mstep.step_outputs in - let vars = union locals outputs in - let no_occur_after i = - let occ, _ = List.fold_left (fun (s, j) instr -> - if j <= i then (s, j+1) else (occur s instr, j+1)) - (empty, 0) m.mstep.step_instrs in - diff locals occ - in - let l, _, _ = List.fold_left (fun (l, asg, i) instr -> - let asg = inter (assigned asg instr) vars in - Live.add (i + 1) (diff asg (no_occur_after i)) l, asg, i + 1) - (Live.empty, empty, 0) m.mstep.step_instrs in - Hashtbl.add live m.mname.node_id (Live.add 0 empty l) +let pp_nothing fmt () = + pp_print_string fmt "\\nothing" -let live_i m i = - Live.find i (Hashtbl.find live m.mname.node_id) +let pp_memory_pack_aux ?i pp_mem pp_self fmt (name, mem, self) = + fprintf fmt "%s_pack%a(@[<hov>%a,@ %a@])" + name + (pp_print_option pp_print_int) i + pp_mem mem + pp_self self + +let pp_memory_pack pp_mem pp_self fmt (mp, mem, self) = + pp_memory_pack_aux ?i:mp.mpindex pp_mem pp_self fmt + (mp.mpname.node_id, mem, self) + +let pp_memory_pack_aux' ?i fmt = + pp_memory_pack_aux ?i pp_print_string pp_print_string fmt +let pp_memory_pack' fmt = + pp_memory_pack pp_print_string pp_print_string fmt -let pp_mem_trans_aux ?i stateless pp_mem_in pp_mem_out pp_input pp_output fmt +let pp_transition_aux ?i m pp_mem_in pp_mem_out pp_input pp_output fmt (name, inputs, locals, outputs, mem_in, mem_out) = - fprintf fmt "%s_transition%a(@[<hov>%a%a%a%a%a@])" + let stateless = fst (get_stateless_status m) in + fprintf fmt "%s_transition%a(@[<hov>%t%a%a%t%a@])" name (pp_print_option pp_print_int) i - (fun fmt () -> if not stateless then fprintf fmt "%a,@ " pp_mem_in mem_in) () - (pp_print_list - (* ~pp_epilogue:pp_print_comma *) - ~pp_sep:pp_print_comma - pp_input) inputs - (pp_print_option - (fun fmt _ -> - pp_print_list - ~pp_prologue:pp_print_comma - ~pp_sep:pp_print_comma - pp_input fmt locals)) + (fun fmt -> if not stateless then fprintf fmt "%a,@ " pp_mem_in mem_in) + (pp_comma_list pp_input) inputs + (pp_print_option (fun fmt _ -> + pp_comma_list ~pp_prologue:pp_print_comma pp_input fmt locals)) i - (fun fmt () -> if not stateless then fprintf fmt ",@ %a" pp_mem_out mem_out) () - (pp_print_list - ~pp_prologue:pp_print_comma - ~pp_sep:pp_print_comma - pp_output) outputs - -let pp_mem_trans ?i pp_mem_in pp_mem_out pp_input pp_output fmt - (m, mem_in, mem_out) = - let locals, outputs = match i with - | Some 0 -> - [], [] - | Some i when i < List.length m.mstep.step_instrs -> - let li = live_i m i in - VDSet.(inter (of_list m.mstep.step_locals) li |> elements, - inter (of_list m.mstep.step_outputs) li |> elements) - | Some _ -> - [], m.mstep.step_outputs - | _ -> - m.mstep.step_locals, m.mstep.step_outputs - in - pp_mem_trans_aux ?i (fst (get_stateless_status m)) - pp_mem_in pp_mem_out pp_input pp_output fmt - (m.mname.node_id, - m.mstep.step_inputs, - locals, - outputs, - mem_in, - mem_out) - -let pp_mem_trans' ?i fmt = - pp_mem_trans ?i pp_print_string pp_print_string pp_var_decl pp_var_decl fmt -let pp_mem_trans'' ?i fmt = - pp_mem_trans ?i pp_print_string pp_print_string pp_var_decl pp_ptr_decl fmt + (fun fmt -> if not stateless then fprintf fmt ",@ %a" pp_mem_out mem_out) + (pp_comma_list ~pp_prologue:pp_print_comma pp_output) outputs + +let pp_transition m pp_mem_in pp_mem_out pp_input pp_output fmt + (t, mem_in, mem_out) = + pp_transition_aux ?i:t.tindex m pp_mem_in pp_mem_out pp_input pp_output fmt + (t.tname.node_id, t.tinputs, t.tlocals, t.toutputs, mem_in, mem_out) + +let pp_transition_aux' ?i m = + pp_transition_aux ?i m pp_print_string pp_print_string pp_var_decl pp_var_decl +let pp_transition_aux'' ?i m = + pp_transition_aux ?i m pp_print_string pp_print_string pp_var_decl pp_ptr_decl +let pp_transition' m = + pp_transition m pp_print_string pp_print_string pp_var_decl pp_var_decl +let pp_transition'' m = + pp_transition m pp_print_string pp_print_string pp_var_decl pp_ptr_decl + +let pp_reset_cleared pp_mem_in pp_mem_out fmt (name, mem_in, mem_out) = + fprintf fmt "%s_reset_cleared(@[<hov>%a,@ %a@])" + name + pp_mem_in mem_in + pp_mem_out mem_out + +let pp_reset_cleared' = pp_reset_cleared pp_print_string pp_print_string + +module PrintSpec = struct + + let pp_reg pp_mem fmt = function + | ResetFlag -> + fprintf fmt "%t_reset" pp_mem + | StateVar x -> + fprintf fmt "%t%a" pp_mem pp_var_decl x + + let pp_expr: + type a. machine_t -> (formatter -> unit) -> formatter -> (value_t, a) expression_t -> unit = + fun m pp_mem fmt -> function + | Val v -> pp_val m fmt v + | Tag t -> pp_print_string fmt t + | Var v -> pp_var_decl fmt v + | Memory r -> pp_reg pp_mem fmt r + + let pp_predicate m mem_in mem_in' mem_out mem_out' fmt p = + let pp_expr: type a. formatter -> (value_t, a) expression_t -> unit = + fun fmt e -> pp_expr m (fun fmt -> fprintf fmt "%s." mem_out) fmt e + in + match p with + | Transition (f, inst, i, inputs, locals, outputs) -> + let pp_mem_in, pp_mem_out = match inst with + | None -> + pp_print_string, pp_print_string + | Some inst -> + (fun fmt mem_in -> pp_access' fmt (mem_in, inst)), + (fun fmt mem_out -> pp_access' fmt (mem_out, inst)) + in + pp_transition_aux ?i m pp_mem_in pp_mem_out pp_expr pp_expr fmt + (f, inputs, locals, outputs, mem_in', mem_out') + | MemoryPack (f, inst, i) -> + let pp_mem, pp_self = match inst with + | None -> + pp_print_string, pp_print_string + | Some inst -> + (fun fmt mem -> pp_access' fmt (mem, inst)), + (fun fmt self -> pp_indirect' fmt (self, inst)) + in + pp_memory_pack_aux ?i pp_mem pp_self fmt (f, mem_out, mem_in) + | ResetCleared f -> + pp_reset_cleared' fmt (f, mem_in, mem_out) + (* fprintf fmt "ResetCleared_%a" pp_print_string f *) + | Initialization -> () + + let reset_flag = dummy_var_decl "_reset" Type_predef.type_bool + + let val_of_expr: type a. (value_t, a) expression_t -> value_t = function + | Val v -> v + | Tag t -> id_to_tag t + | Var v -> vdecl_to_val v + | Memory (StateVar v) -> vdecl_to_val v + | Memory ResetFlag -> vdecl_to_val reset_flag + + type mode = + | MemoryPackMode + | TransitionMode + | ResetIn + | ResetOut + | InstrMode of ident + + let find_arrow m = + try + List.find (fun (_, (td, _)) -> Arrow.td_is_arrow td) m.minstances + |> fst + with Not_found -> eprintf "Internal error: arrow not found"; raise Not_found + + let pp_spec mode m = + let rec pp_spec mode fmt f = + let mem_in, mem_in', indirect_r, mem_out, mem_out', indirect_l = + let self = mk_self m in + let mem = mk_mem m in + let mem_in = mk_mem_in m in + let mem_out = mk_mem_out m in + let mem_reset = mk_mem_reset m in + match mode with + | MemoryPackMode -> + self, self, true, mem, mem, false + | TransitionMode -> + mem_in, mem_in, false, mem_out, mem_out, false + | ResetIn -> + mem_in, mem_in, false, mem_reset, mem_reset, false + | ResetOut -> + mem_reset, mem_reset, false, mem_out, mem_out, false + | InstrMode self -> + let mem = "*" ^ mem in + fprintf str_formatter "%a" (pp_at pp_print_string) (mem, reset_label); + self, flush_str_formatter (), false, + mem, mem, false + in + let pp_expr: type a. formatter -> (value_t, a) expression_t -> unit = + fun fmt e -> pp_expr m (fun fmt -> fprintf fmt "%s." mem_out) fmt e + in + let pp_spec' = pp_spec mode in + match f with + | True -> + pp_true fmt () + | False -> + pp_false fmt () + | Equal (a, b) -> + pp_assign_spec m + mem_out (pp_c_var_read m) indirect_l + mem_in (pp_c_var_read m) indirect_r + fmt + (type_of_l_value a, val_of_expr a, val_of_expr b) + | And fs -> + pp_and_l pp_spec' fmt fs + | Or fs -> + pp_or_l pp_spec' fmt fs + | Imply (a, b) -> + pp_par (pp_implies pp_spec' pp_spec') fmt (a, b) + | Exists (xs, a) -> + pp_exists (pp_locals m) pp_spec' fmt (xs, a) + | Forall (xs, a) -> + pp_forall (pp_locals m) pp_spec' fmt (xs, a) + | Ternary (e, a, b) -> + pp_ite pp_expr pp_spec' pp_spec' fmt (e, a, b) + | Predicate p -> + pp_predicate m mem_in mem_in' mem_out mem_out' fmt p + | StateVarPack ResetFlag -> + let r = vdecl_to_val reset_flag in + pp_assign_spec m + mem_out (pp_c_var_read m) indirect_l + mem_in (pp_c_var_read m) indirect_r + fmt + (Type_predef.type_bool, r, r) + | StateVarPack (StateVar v) -> + let v' = vdecl_to_val v in + let inst = find_arrow m in + pp_par (pp_implies + (pp_not (pp_initialization pp_access')) + (pp_assign_spec m + mem_out (pp_c_var_read m) indirect_l + mem_in (pp_c_var_read m) indirect_r)) + fmt + ((Arrow.arrow_id, (mem_out, inst)), + (v.var_type, v', v')) + | ExistsMem (rc, tr) -> + pp_exists + (pp_machine_decl' ~ghost:true) + (pp_and (pp_spec ResetIn) (pp_spec ResetOut)) + fmt + ((m.mname.node_id, mk_mem_reset m), + (rc, tr)) + (* fprintf fmt "@[<hv 2>∃ MEM,@ %a@]" pp_spec f *) + in + pp_spec mode -let pp_nothing fmt () = - pp_print_string fmt "\\nothing" +end let pp_predicate pp_l pp_r fmt (l, r) = fprintf fmt "@[<v 2>predicate %a =@,%a;@]" @@ -563,227 +517,175 @@ let print_machine_valid_predicate fmt m = if not (fst (get_stateless_status m)) then let name = m.mname.node_id in let self = mk_self m in - pp_spec + pp_acsl (pp_predicate - (pp_mem_valid pp_machine_decl) + (pp_mem_valid (pp_machine_decl pp_ptr)) (pp_and (pp_and_l (fun fmt (_, (td, _) as inst) -> pp_mem_valid (pp_inst self) fmt (node_name td, inst))) (pp_valid pp_print_string))) fmt - ((name, (name, "mem", "*" ^ self)), + ((name, (name, self)), (m.minstances, [self])) -let print_machine_ghost_simulation_aux ?i m pp fmt v = - let name = m.mname.node_id in + +let pp_memory_pack_def m fmt mp = + let name = mp.mpname.node_id in let self = mk_self m in let mem = mk_mem m in - pp_spec + pp_acsl (pp_predicate - (pp_mem_ghost pp_machine_decl pp_machine_decl ?i) - pp) + (pp_memory_pack (pp_machine_decl' ~ghost:true) (pp_machine_decl pp_ptr)) + (PrintSpec.pp_spec MemoryPackMode m)) fmt - ((name, (name, "mem_ghost", mem), (name, "mem", "*" ^ self)), - v) - -let print_ghost_simulation dependencies m fmt (i, instr) = - let name = m.mname.node_id in - let self = mk_self m in - let mem = mk_mem m in - let prev_ghost fmt () = pp_mem_ghost' ~i fmt (name, mem, self) in - let pred pp v = pp_and prev_ghost pp fmt ((), v) in - let rec aux fmt instr = - match instr.instr_desc with - | MStateAssign (m, _) -> - pp_equal - (pp_access pp_print_string (pp_access pp_print_string pp_var_decl)) - (pp_indirect pp_print_string (pp_access pp_print_string pp_var_decl)) - fmt - ((mem, ("_reg", m)), (self, ("_reg", m))) - | MStep ([i0], i, vl) - when Basic_library.is_value_internal_fun - (mk_val (Fun (i, vl)) i0.var_type) -> - pp_true fmt () - | MStep (_, i, _) when !Options.mpfr && Mpfr.is_homomorphic_fun i -> - pp_true fmt () - | MStep ([_], i, _) when has_c_prototype i dependencies -> - pp_true fmt () - | MStep (_, i, _) - | MReset i -> - begin try - let n, _ = List.assoc i m.minstances in - pp_mem_ghost pp_access' pp_indirect' fmt - (node_name n, (mem, i), (self, i)) - with Not_found -> pp_true fmt () - end - | MBranch (_, brs) -> - (* TODO: handle branches *) - pp_and_l aux fmt List.(flatten (map snd brs)) - | _ -> pp_true fmt () - in - pred aux instr - -let print_machine_ghost_simulation dependencies m fmt i instr = - print_machine_ghost_simulation_aux m - (print_ghost_simulation dependencies m) - ~i:(i+1) - fmt (i, instr) + ((mp, (name, mem), (name, self)), + mp.mpformula) let print_machine_ghost_struct fmt m = - pp_spec (pp_ghost (print_machine_struct ~ghost:true)) fmt m + pp_acsl (pp_ghost (print_machine_struct ~ghost:true)) fmt m -let print_machine_ghost_simulations dependencies fmt m = +let pp_memory_pack_defs fmt m = if not (fst (get_stateless_status m)) then - let name = m.mname.node_id in - let self = mk_self m in - let mem = mk_mem m in - fprintf fmt "%a@,%a@,%a%a" + fprintf fmt "%a@,%a" print_machine_ghost_struct m - (print_machine_ghost_simulation_aux m pp_true ~i:0) () - (pp_print_list_i - ~pp_epilogue:pp_print_cut - ~pp_open_box:pp_open_vbox0 - (print_machine_ghost_simulation dependencies m)) - m.mstep.step_instrs - (print_machine_ghost_simulation_aux m - (pp_mem_ghost' ~i:(List.length m.mstep.step_instrs))) (name, mem, self) - -let print_machine_trans_simulation_aux ?i m pp fmt v = - let name = m.mname.node_id in + (pp_print_list + ~pp_epilogue:pp_print_cut + ~pp_open_box:pp_open_vbox0 + (pp_memory_pack_def m)) m.mspec.mmemory_packs + +let pp_transition_def m fmt t = + let name = t.tname.node_id in let mem_in = mk_mem_in m in let mem_out = mk_mem_out m in - pp_spec + pp_acsl (pp_predicate - (pp_mem_trans pp_machine_decl pp_machine_decl - (pp_c_decl_local_var ~pp_c_basic_type_desc:pp_acsl_basic_type_desc m) + (pp_transition m + (pp_machine_decl' ~ghost:true) (pp_machine_decl' ~ghost:true) (pp_c_decl_local_var ~pp_c_basic_type_desc:pp_acsl_basic_type_desc m) - ?i) - pp) + (pp_c_decl_local_var ~pp_c_basic_type_desc:pp_acsl_basic_type_desc m)) + (PrintSpec.pp_spec TransitionMode m)) fmt - ((m, (name, "mem_ghost", mem_in), (name, "mem_ghost", mem_out)), - v) - -let print_trans_simulation dependencies m fmt (i, instr) = - let mem_in = mk_mem_in m in - let mem_out = mk_mem_out m in - let d = VDSet.(diff (union (live_i m i) (assigned empty instr)) - (live_i m (i+1))) in - (* XXX *) - (* printf "%d : %a\n%d : %a\nocc: %a\n\n" - * i - * (pp_print_parenthesized pp_var_decl) (VDSet.elements (live_i m i)) - * (i+1) - * (pp_print_parenthesized pp_var_decl) (VDSet.elements (live_i m (i+1))) - * (pp_print_parenthesized pp_var_decl) VDSet.(elements (assigned empty instr)); *) - let prev_trans fmt () = pp_mem_trans' ~i fmt (m, mem_in, mem_out) in - let pred pp v = - let vars = VDSet.(union (of_list m.mstep.step_locals) - (of_list m.mstep.step_outputs)) in - let locals = VDSet.(inter vars d |> elements) in - if locals = [] - then pp_and prev_trans pp fmt ((), v) - else pp_exists (pp_locals m) (pp_and prev_trans pp) fmt (locals, ((), v)) - in - let rec aux fmt instr = match instr.instr_desc with - | MLocalAssign (x, v) - | MStateAssign (x, v) -> - pp_assign_spec m mem_out (pp_c_var_read m) mem_in (pp_c_var_read m) fmt - (x.var_type, mk_val (Var x) x.var_type, v) - | MStep ([i0], i, vl) - when Basic_library.is_value_internal_fun - (mk_val (Fun (i, vl)) i0.var_type) -> - pp_true fmt () - | MStep (_, i, _) when !Options.mpfr && Mpfr.is_homomorphic_fun i -> - pp_true fmt () - | MStep ([_], i, _) when has_c_prototype i dependencies -> - pp_true fmt () - | MStep (xs, i, ys) -> - begin try - let n, _ = List.assoc i m.minstances in - pp_mem_trans_aux - (fst (get_stateless_status_top_decl n)) - pp_access' pp_access' - (pp_c_val m mem_in (pp_c_var_read m)) - pp_var_decl - fmt - (node_name n, ys, [], xs, (mem_in, i), (mem_out, i)) - with Not_found -> pp_true fmt () - end - | MReset i -> - begin try - let n, _ = List.assoc i m.minstances in - pp_mem_init' fmt (node_name n, mem_out) - with Not_found -> pp_true fmt () - end - | MBranch (v, brs) -> - if let t = fst (List.hd brs) in t = tag_true || t = tag_false - then (* boolean case *) - pp_ite (pp_c_val m mem_in (pp_c_var_read m)) - (fun fmt () -> - match List.assoc tag_true brs with - | _ :: _ as l -> pp_paren (pp_and_l aux) fmt l - | [] - | exception Not_found -> pp_true fmt ()) - (fun fmt () -> - match List.assoc tag_false brs with - | _ :: _ as l -> pp_paren (pp_and_l aux) fmt l - | [] - | exception Not_found -> pp_true fmt ()) - fmt (v, (), ()) - else (* enum type case *) - pp_and_l (fun fmt (l, instrs) -> - let pp_val = pp_c_val m mem_in (pp_c_var_read m) in - pp_paren (pp_implies - (pp_equal pp_val pp_c_tag) - (pp_and_l aux)) - fmt - ((v, l), instrs)) - fmt brs - | _ -> pp_true fmt () - in - pred aux instr - -let print_machine_trans_simulation dependencies m fmt i instr = - print_machine_trans_simulation_aux m - (print_trans_simulation dependencies m) - ~i:(i+1) - fmt (i, instr) - -let print_machine_trans_annotations dependencies fmt m = - set_live_of m; - let i = List.length m.mstep.step_instrs in - let mem_in = mk_mem_in m in - let mem_out = mk_mem_out m in - let last_trans fmt () = - let locals = VDSet.(inter - (of_list m.mstep.step_locals) - (live_i m i) - |> elements) in - if locals = [] - then pp_mem_trans' ~i fmt (m, mem_in, mem_out) - else pp_exists (pp_locals m) (pp_mem_trans' ~i) fmt - (locals, (m, mem_in, mem_out)) - in - fprintf fmt "%a@,%a%a" - (print_machine_trans_simulation_aux m pp_true ~i:0) () - (pp_print_list_i + ((t, (name, mem_in), (name, mem_out)), + t.tformula) + +(* let print_trans_simulation dependencies m fmt (i, instr) = + * let mem_in = mk_mem_in m in + * let mem_out = mk_mem_out m in + * let d = VDSet.(diff (union (live_i m i) (assigned empty instr)) + * (live_i m (i+1))) in + * (\* XXX *\) + * (\* printf "%d : %a\n%d : %a\nocc: %a\n\n" + * * i + * * (pp_print_parenthesized pp_var_decl) (VDSet.elements (live_i m i)) + * * (i+1) + * * (pp_print_parenthesized pp_var_decl) (VDSet.elements (live_i m (i+1))) + * * (pp_print_parenthesized pp_var_decl) VDSet.(elements (assigned empty instr)); *\) + * let prev_trans fmt () = pp_mem_trans' ~i fmt (m, mem_in, mem_out) in + * let pred pp v = + * let vars = VDSet.(union (of_list m.mstep.step_locals) + * (of_list m.mstep.step_outputs)) in + * let locals = VDSet.(inter vars d |> elements) in + * if locals = [] + * then pp_and prev_trans pp fmt ((), v) + * else pp_exists (pp_locals m) (pp_and prev_trans pp) fmt (locals, ((), v)) + * in + * let rec aux fmt instr = match instr.instr_desc with + * | MLocalAssign (x, v) + * | MStateAssign (x, v) -> + * pp_assign_spec m mem_out (pp_c_var_read m) mem_in (pp_c_var_read m) fmt + * (x.var_type, mk_val (Var x) x.var_type, v) + * | MStep ([i0], i, vl) + * when Basic_library.is_value_internal_fun + * (mk_val (Fun (i, vl)) i0.var_type) -> + * pp_true fmt () + * | MStep (_, i, _) when !Options.mpfr && Mpfr.is_homomorphic_fun i -> + * pp_true fmt () + * | MStep ([_], i, _) when has_c_prototype i dependencies -> + * pp_true fmt () + * | MStep (xs, i, ys) -> + * begin try + * let n, _ = List.assoc i m.minstances in + * pp_mem_trans_aux + * (fst (get_stateless_status_top_decl n)) + * pp_access' pp_access' + * (pp_c_val m mem_in (pp_c_var_read m)) + * pp_var_decl + * fmt + * (node_name n, ys, [], xs, (mem_in, i), (mem_out, i)) + * with Not_found -> pp_true fmt () + * end + * | MReset i -> + * begin try + * let n, _ = List.assoc i m.minstances in + * pp_mem_init' fmt (node_name n, mem_out) + * with Not_found -> pp_true fmt () + * end + * | MBranch (v, brs) -> + * if let t = fst (List.hd brs) in t = tag_true || t = tag_false + * then (\* boolean case *\) + * pp_ite (pp_c_val m mem_in (pp_c_var_read m)) + * (fun fmt () -> + * match List.assoc tag_true brs with + * | _ :: _ as l -> pp_paren (pp_and_l aux) fmt l + * | [] + * | exception Not_found -> pp_true fmt ()) + * (fun fmt () -> + * match List.assoc tag_false brs with + * | _ :: _ as l -> pp_paren (pp_and_l aux) fmt l + * | [] + * | exception Not_found -> pp_true fmt ()) + * fmt (v, (), ()) + * else (\* enum type case *\) + * pp_and_l (fun fmt (l, instrs) -> + * let pp_val = pp_c_val m mem_in (pp_c_var_read m) in + * pp_paren (pp_implies + * (pp_equal pp_val pp_c_tag) + * (pp_and_l aux)) + * fmt + * ((v, l), instrs)) + * fmt brs + * | _ -> pp_true fmt () + * in + * pred aux instr *) + +(* let print_machine_trans_simulation dependencies m fmt i instr = + * print_machine_trans_simulation_aux m + * (print_trans_simulation dependencies m) + * ~i:(i+1) + * fmt (i, instr) *) + +let pp_transition_defs fmt m = + (* set_live_of m; *) + (* let i = List.length m.mstep.step_instrs in *) + (* let mem_in = mk_mem_in m in + * let mem_out = mk_mem_out m in *) + (* let last_trans fmt () = + * let locals = VDSet.(inter + * (of_list m.mstep.step_locals) + * (live_i m i) + * |> elements) in + * if locals = [] + * then pp_mem_trans' ~i fmt (m, mem_in, mem_out) + * else pp_exists (pp_locals m) (pp_mem_trans' ~i) fmt + * (locals, (m, mem_in, mem_out)) + * in *) + fprintf fmt "%a" + (pp_print_list ~pp_epilogue:pp_print_cut ~pp_open_box:pp_open_vbox0 - (print_machine_trans_simulation dependencies m)) - m.mstep.step_instrs - (print_machine_trans_simulation_aux m last_trans) () + (pp_transition_def m)) m.mspec.mtransitions let print_machine_init_predicate fmt m = if not (fst (get_stateless_status m)) then let name = m.mname.node_id in let mem_in = mk_mem_in m in - pp_spec + pp_acsl (pp_predicate - (pp_mem_init pp_machine_decl) + (pp_initialization (pp_machine_decl' ~ghost:true)) (pp_and_l (fun fmt (i, (td, _)) -> - pp_mem_init pp_access' fmt (node_name td, (mem_in, i))))) + pp_initialization pp_access' fmt (node_name td, (mem_in, i))))) fmt - ((name, (name, "mem_ghost", mem_in)), m.minstances) + ((name, (name, mem_in)), m.minstances) let pp_at pp_p fmt (p, l) = fprintf fmt "\\at(%a, %s)" pp_p p l @@ -793,15 +695,34 @@ let label_pre = "Pre" let pp_at_pre pp_p fmt p = pp_at pp_p fmt (p, label_pre) -let pp_register = +let pp_register ?(indirect=true) ptr = pp_print_list - ~pp_prologue:(fun fmt () -> pp_print_string fmt "self->") - ~pp_epilogue:(fun fmt () -> pp_print_string fmt "->_reg._first") - ~pp_sep:(fun fmt () -> pp_print_string fmt "->") + ~pp_prologue:(fun fmt () -> fprintf fmt "%s->" ptr) + ~pp_epilogue:(fun fmt () -> fprintf fmt "%s_reg._first" + (if indirect then "->" else ".")) + ~pp_sep:(fun fmt () -> pp_print_string fmt (if indirect then "->" else ".")) (fun fmt (i, _) -> pp_print_string fmt i) +let pp_reset_flag ?(indirect=true) ptr fmt mems = + pp_print_list + ~pp_prologue:(fun fmt () -> fprintf fmt "%s->" ptr) + ~pp_epilogue:(fun fmt () -> fprintf fmt "%s_reset" + (if indirect then "->" else ".")) + ~pp_sep:(fun fmt () -> pp_print_string fmt (if indirect then "->" else ".")) + (fun fmt (i, _) -> pp_print_string fmt i) + fmt mems + +module GhostProto: MODIFIERS_GHOST_PROTO = struct + let pp_ghost_parameters fmt vs = + fprintf fmt "@;%a" + (pp_acsl (pp_ghost (pp_print_parenthesized (fun fmt (x, pp) -> pp fmt x)))) + vs +end + module HdrMod = struct + module GhostProto = GhostProto + let print_machine_decl_prefix = fun _ _ -> () let pp_import_standard_spec fmt () = @@ -813,7 +734,9 @@ end module SrcMod = struct - let pp_predicates dependencies fmt machines = + module GhostProto = GhostProto + + let pp_predicates (* dependencies *) fmt machines = fprintf fmt "%a%a%a%a" (pp_print_list @@ -825,7 +748,7 @@ module SrcMod = struct ~pp_open_box:pp_open_vbox0 ~pp_sep:pp_print_cutcut ~pp_prologue:(pp_print_endcut "/* ACSL ghost simulations */") - (print_machine_ghost_simulations dependencies) + pp_memory_pack_defs ~pp_epilogue:pp_print_cutcut) machines (pp_print_list ~pp_open_box:pp_open_vbox0 @@ -837,97 +760,102 @@ module SrcMod = struct ~pp_open_box:pp_open_vbox0 ~pp_sep:pp_print_cutcut ~pp_prologue:(pp_print_endcut "/* ACSL transition annotations */") - (print_machine_trans_annotations dependencies) + pp_transition_defs ~pp_epilogue:pp_print_cutcut) machines - let pp_reset_spec fmt machines self m = + let pp_clear_reset_spec fmt machines self mem m = let name = m.mname.node_id in - let mem = mk_mem m in - let insts = instances machines m in - pp_spec_cut (fun fmt () -> + let arws, narws = List.partition (fun (_, (td, _)) -> Arrow.td_is_arrow td) + m.minstances in + let mk_insts = List.map (fun x -> [x]) in + pp_acsl_cut (fun fmt () -> fprintf fmt - "%a@,%a@,%a@,%a" + "%a@,%a@,%a@,%a@,%a@,%a@,%a@,%a@,%a@,\ + @[<v 2>behavior reset:@;\ + %a@,%a@]@,\ + @[<v 2>behavior no_reset:@;\ + %a@,%a@]" (pp_requires pp_mem_valid') (name, self) - (pp_requires (pp_separated self)) (powerset_instances insts, []) - (pp_assigns pp_register) insts - (pp_ensures - (pp_forall - pp_machine_decl - (pp_implies - pp_mem_ghost' - pp_mem_init'))) - ((name, "mem_ghost", mem), - ((name, mem, self), (name, mem)))) + (pp_requires (pp_separated self mem)) (mk_insts m.minstances, []) + (pp_ensures (pp_memory_pack_aux + ~i:(List.length m.mspec.mmemory_packs - 2) + pp_ptr pp_print_string)) + (name, mem, self) + (pp_assigns pp_indirect') [self, "_reset"] + (pp_assigns (pp_register self)) (mk_insts arws) + (pp_assigns (pp_reset_flag self)) (mk_insts narws) + (pp_assigns pp_indirect') [mem, "_reset"] + (pp_assigns (pp_register ~indirect:false mem)) (mk_insts arws) + (pp_assigns (pp_reset_flag ~indirect:false mem)) (mk_insts narws) + (pp_assumes (pp_equal pp_indirect' pp_print_int)) ((mem, "_reset"), 1) + (pp_ensures (pp_initialization pp_ptr)) (name, mem) + (pp_assumes (pp_equal pp_indirect' pp_print_int)) ((mem, "_reset"), 0) + (pp_ensures (pp_equal pp_ptr (pp_old pp_ptr))) (mem, mem) + ) fmt () - let pp_step_spec fmt machines self m = + let pp_set_reset_spec fmt self mem m = + let name = m.mname.node_id in + pp_acsl_cut (fun fmt () -> + fprintf fmt + "%a@,%a@,%a" + (pp_ensures (pp_memory_pack_aux pp_ptr pp_print_string)) (name, mem, self) + (pp_ensures (pp_equal pp_indirect' pp_print_string)) ((mem, "_reset"), "1") + (pp_assigns (fun fmt ptr -> pp_indirect' fmt (ptr, "_reset"))) [self; mem]) + fmt () + + let pp_step_spec fmt machines self mem m = let name = m.mname.node_id in - let mem_in = mk_mem_in m in - let mem_out = mk_mem_out m in let insts = instances machines m in let insts' = powerset_instances insts in - pp_spec_cut (fun fmt () -> + let insts'' = List.(filter (fun l -> l <> []) + (map (filter (fun (_, (td, _)) -> + not (Arrow.td_is_arrow td))) insts)) in + let inputs = m.mstep.step_inputs in + let outputs = m.mstep.step_outputs in + pp_acsl_cut (fun fmt () -> if fst (get_stateless_status m) then fprintf fmt "%a@,%a@,%a@,%a" - (pp_requires (pp_valid pp_var_decl)) m.mstep.step_outputs - (pp_requires pp_separated') m.mstep.step_outputs - (pp_assigns pp_ptr_decl) m.mstep.step_outputs - (pp_ensures pp_mem_trans'') (m, mem_in, mem_out) + (pp_requires (pp_valid pp_var_decl)) outputs + (pp_requires pp_separated') outputs + (pp_assigns pp_ptr_decl) outputs + (pp_ensures (pp_transition_aux'' m)) + (name, inputs, [], outputs, "", "") else fprintf fmt - "%a@,%a@,%a@,%a@,%a@,%a@,%a@,%a" - (pp_requires (pp_valid pp_var_decl)) m.mstep.step_outputs + "%a@,%a@,%a@,%a@,%a@,%a@,%a@,%a@,%a@,%a@,%a@,%a@,%a@,%a" + (pp_requires (pp_valid pp_var_decl)) outputs (pp_requires pp_mem_valid') (name, self) - (pp_requires (pp_separated self)) (insts', m.mstep.step_outputs) - (pp_assigns pp_ptr_decl) m.mstep.step_outputs + (pp_requires (pp_separated self mem)) (insts', outputs) + (pp_requires (pp_memory_pack_aux pp_ptr pp_print_string)) + (name, mem, self) + (pp_assigns pp_ptr_decl) outputs (pp_assigns (pp_reg self)) m.mmemory - (pp_assigns pp_memory) (memories insts') - (pp_assigns pp_register) insts - (pp_ensures - (pp_forall - pp_machine_decl - (pp_forall - pp_machine_decl - (pp_implies - (pp_at_pre pp_mem_ghost') - (pp_implies - pp_mem_ghost' - pp_mem_trans''))))) - ((name, "mem_ghost", mem_in), - ((name, "mem_ghost", mem_out), - ((name, mem_in, self), - ((name, mem_out, self), - (m, mem_in, mem_out))))) + (pp_assigns (pp_memory self)) (memories insts') + (pp_assigns (pp_register self)) insts + (pp_assigns (pp_reset_flag self)) insts'' + (pp_assigns (pp_reg mem)) m.mmemory + (pp_assigns (pp_memory ~indirect:false mem)) (memories insts') + (pp_assigns (pp_register ~indirect:false mem)) insts + (pp_assigns (pp_reset_flag ~indirect:false mem)) insts'' + (pp_ensures (pp_transition_aux m (pp_old pp_ptr) + pp_ptr pp_var_decl pp_ptr_decl)) + (name, inputs, [], outputs, mem, mem) ) fmt () - let pp_step_instr_spec m self fmt (i, _instr) = - let name = m.mname.node_id in - let mem_in = mk_mem_in m in - let mem_out = mk_mem_out m in - if fst (get_stateless_status m) then - fprintf fmt "@,%a" - (pp_spec (pp_assert (pp_mem_trans'' ~i))) (m, mem_in, mem_out) - else - fprintf fmt "@,%a" - (pp_spec - (pp_assert - (pp_forall - pp_machine_decl - (pp_forall - pp_machine_decl - (pp_implies - (pp_at_pre pp_mem_ghost') - (pp_implies - (pp_mem_ghost' ~i) - (pp_mem_trans'' ~i))))))) - ((name, "mem_ghost", mem_in), - ((name, "mem_ghost", mem_out), - ((name, mem_in, self), - ((name, mem_out, self), - (m, mem_in, mem_out))))) - + let pp_step_instr_spec m self fmt instr = + fprintf fmt "@,%a" + (pp_print_list ~pp_open_box:pp_open_vbox0 + (pp_acsl (pp_assert (PrintSpec.pp_spec (InstrMode self) m)))) + instr.instr_spec + + let pp_ghost_set_reset_spec fmt = + fprintf fmt "@;%a@;" + (pp_acsl_line + (pp_ghost + (fun fmt mem -> fprintf fmt "%a = 1;" pp_indirect' (mem, "_reset")))) end (**************************************************************************) diff --git a/src/backends/C/c_backend_src.ml b/src/backends/C/c_backend_src.ml index 1df132a0..002ae1d7 100644 --- a/src/backends/C/c_backend_src.ml +++ b/src/backends/C/c_backend_src.ml @@ -17,21 +17,29 @@ open Machine_code_common open C_backend_common module type MODIFIERS_SRC = sig - val pp_predicates: dep_t list -> formatter -> machine_t list -> unit - val pp_reset_spec: formatter -> machine_t list -> ident -> machine_t -> unit - val pp_step_spec: formatter -> machine_t list -> ident -> machine_t -> unit - val pp_step_instr_spec: machine_t -> ident -> formatter -> (int * instr_t) -> unit + module GhostProto: MODIFIERS_GHOST_PROTO + val pp_predicates: formatter -> machine_t list -> unit + val pp_set_reset_spec: formatter -> ident -> ident -> machine_t -> unit + val pp_clear_reset_spec: formatter -> machine_t list -> ident -> ident -> machine_t -> unit + val pp_step_spec: formatter -> machine_t list -> ident -> ident -> machine_t -> unit + val pp_step_instr_spec: machine_t -> ident -> formatter -> instr_t -> unit + val pp_ghost_set_reset_spec: formatter -> ident -> unit end module EmptyMod = struct - let pp_predicates _ _ _ = () - let pp_reset_spec _ _ _ _ = () - let pp_step_spec _ _ _ _ = () + module GhostProto = EmptyGhostProto + let pp_predicates _ _ = () + let pp_set_reset_spec _ _ _ _ = () + let pp_clear_reset_spec _ _ _ _ _ = () + let pp_step_spec _ _ _ _ _ = () let pp_step_instr_spec _ _ _ _ = () + let pp_ghost_set_reset_spec _ _ = () end module Main = functor (Mod: MODIFIERS_SRC) -> struct + module Protos = Protos(Mod.GhostProto) + (********************************************************************************************) (* Instruction Printing functions *) (********************************************************************************************) @@ -119,50 +127,70 @@ module Main = functor (Mod: MODIFIERS_SRC) -> struct (*eprintf "end pp_assign@.";*) end - let pp_machine_ pp_machine_name fn_name m self fmt inst = - let (node, static) = try List.assoc inst m.minstances with Not_found -> - eprintf "internal error: %s %s %s %s:@." fn_name m.mname.node_id self inst; - raise Not_found + let pp_machine_ pp_machine_name fn_name m fmt ?inst self = + let name, static = + match inst with + | Some inst -> + let node, static = try List.assoc inst m.minstances with Not_found -> + eprintf "internal error: %s %s %s %s:@." + fn_name m.mname.node_id self inst; + raise Not_found + in + node_name node, static + | None -> + m.mname.node_id, [] in - fprintf fmt "%a(%a%s->%s);" - pp_machine_name (node_name node) - (pp_print_list ~pp_sep:pp_print_comma ~pp_eol:pp_print_comma - Dimension.pp_dimension) static - self inst + fprintf fmt "%a(%a%s%a);" + pp_machine_name name + (pp_comma_list ~pp_eol:pp_print_comma Dimension.pp_dimension) static + self + (pp_print_option (fun fmt -> fprintf fmt "->%s")) inst + + let pp_machine_set_reset m self fmt inst = + pp_machine_ pp_machine_set_reset_name "pp_machine_set_reset" m fmt ~inst self - let pp_machine_reset = - pp_machine_ pp_machine_reset_name "pp_machine_reset" + let pp_machine_clear_reset m self fmt = + pp_machine_ pp_machine_clear_reset_name "pp_machine_clear_reset" m fmt self - let pp_machine_init = - pp_machine_ pp_machine_init_name "pp_machine_init" + let pp_machine_init m self fmt inst = + pp_machine_ pp_machine_init_name "pp_machine_init" m fmt ~inst self - let pp_machine_clear = - pp_machine_ pp_machine_clear_name "pp_machine_clear" + let pp_machine_clear m self fmt inst = + pp_machine_ pp_machine_clear_name "pp_machine_clear" m fmt ~inst self - let pp_call m self pp_read pp_write fmt i - (inputs: Machine_code_types.value_t list) (outputs: var_decl list) = + let pp_call m self pp_read pp_write fmt i inputs outputs = try (* stateful node instance *) let n, _ = List.assoc i m.minstances in - fprintf fmt "%a (%a%a%s->%s);" + fprintf fmt "%a(%a%a%s->%s);" pp_machine_step_name (node_name n) - (pp_print_list ~pp_sep:pp_print_comma ~pp_eol:pp_print_comma + (pp_comma_list ~pp_eol:pp_print_comma (pp_c_val m self pp_read)) inputs - (pp_print_list ~pp_sep:pp_print_comma ~pp_eol:pp_print_comma + (pp_comma_list ~pp_eol:pp_print_comma pp_write) outputs self i with Not_found -> (* stateless node instance *) let n, _ = List.assoc i m.mcalls in - fprintf fmt "%a (%a%a);" + fprintf fmt "%a(%a%a);" pp_machine_step_name (node_name n) - (pp_print_list ~pp_sep:pp_print_comma ~pp_eol:pp_print_comma + (pp_comma_list ~pp_eol:pp_print_comma (pp_c_val m self pp_read)) inputs - (pp_print_list ~pp_sep:pp_print_comma pp_write) outputs + (pp_comma_list pp_write) outputs let pp_basic_instance_call m self = pp_call m self (pp_c_var_read m) (pp_c_var_write m) - let pp_instance_call m self fmt i (inputs: Machine_code_types.value_t list) (outputs: var_decl list) = + let pp_arrow_call m self fmt i outputs = + match outputs with + | [x] -> + fprintf fmt "%a = %a(%s->%s);" + (pp_c_var_read m) x + pp_machine_step_name Arrow.arrow_id + self + i + | _ -> assert false + + let pp_instance_call m self fmt i inputs outputs = let pp_offset pp_var indices fmt var = fprintf fmt "%a%a" pp_var var @@ -196,8 +224,11 @@ module Main = functor (Mod: MODIFIERS_SRC) -> struct and pp_machine_instr dependencies (m: machine_t) self fmt instr = match get_instr_desc instr with | MNoReset _ -> () - | MReset i -> - pp_machine_reset m self fmt i + | MSetReset inst -> + pp_machine_set_reset m self fmt inst + | MClearReset -> + fprintf fmt "%t@,%a" + (pp_machine_clear_reset m self) pp_label reset_label | MLocalAssign (i,v) -> pp_assign m self (pp_c_var_read m) fmt @@ -217,7 +248,11 @@ module Main = functor (Mod: MODIFIERS_SRC) -> struct i (pp_print_parenthesized (pp_c_val m self (pp_c_var_read m))) vl | MStep (il, i, vl) -> - pp_basic_instance_call m self fmt i vl il + let td, _ = List.assoc i m.minstances in + if Arrow.td_is_arrow td then + pp_arrow_call m self fmt i il + else + pp_basic_instance_call m self fmt i vl il | MBranch (_, []) -> eprintf "internal error: C_backend_src.pp_machine_instr %a@." (pp_instr m) instr; @@ -249,15 +284,10 @@ module Main = functor (Mod: MODIFIERS_SRC) -> struct let pp_machine_nospec_instr dependencies m self fmt _i instr = pp_machine_instr dependencies m self fmt instr - let pp_machine_step_instr dependencies m self fmt i instr = - fprintf fmt "%a%a%a" - (if i = 0 then - (fun fmt () -> fprintf fmt "%a@," - (Mod.pp_step_instr_spec m self) (i, instr)) - else - pp_print_nothing) () + let pp_machine_step_instr dependencies m self fmt _i instr = + fprintf fmt "%a%a" (pp_machine_instr dependencies m self) instr - (Mod.pp_step_instr_spec m self) (i+1, instr) + (Mod.pp_step_instr_spec m self) instr (********************************************************************************************) (* C file Printing functions *) @@ -438,8 +468,8 @@ module Main = functor (Mod: MODIFIERS_SRC) -> struct then (* C99 code *) pp_print_function - ~pp_spec:(fun fmt () -> Mod.pp_step_spec fmt machines self m) - ~pp_prototype:print_stateless_prototype + ~pp_spec:(fun fmt () -> Mod.pp_step_spec fmt machines self self m) + ~pp_prototype:Protos.print_stateless_prototype ~prototype:(m.mname.node_id, m.mstep.step_inputs, m.mstep.step_outputs) ~pp_local:(pp_c_decl_local_var m) ~base_locals:m.mstep.step_locals @@ -459,7 +489,7 @@ module Main = functor (Mod: MODIFIERS_SRC) -> struct let (id, _, _) = call_of_expr e in mk_call_var_decl e.expr_loc id) m.mname.node_gencalls in pp_print_function - ~pp_prototype:print_stateless_prototype + ~pp_prototype:Protos.print_stateless_prototype ~prototype:(m.mname.node_id, m.mstep.step_inputs @ gen_locals @ gen_calls, m.mstep.step_outputs) @@ -474,10 +504,10 @@ module Main = functor (Mod: MODIFIERS_SRC) -> struct ~instrs:m.mstep.step_instrs fmt - let print_reset_code machines dependencies self fmt m = + let print_clear_reset_code machines dependencies self mem fmt m = pp_print_function - ~pp_spec:(fun fmt () -> Mod.pp_reset_spec fmt machines self m) - ~pp_prototype:(print_reset_prototype self) + ~pp_spec:(fun fmt () -> Mod.pp_clear_reset_spec fmt machines self mem m) + ~pp_prototype:(Protos.print_clear_reset_prototype self mem) ~prototype:(m.mname.node_id, m.mstatic) ~pp_local:(pp_c_decl_local_var m) ~base_locals:(const_locals m) @@ -485,11 +515,23 @@ module Main = functor (Mod: MODIFIERS_SRC) -> struct ~instrs:m.minit fmt + let print_set_reset_code self mem fmt m = + pp_print_function + ~pp_spec:(fun fmt () -> Mod.pp_set_reset_spec fmt self mem m) + ~pp_prototype:(Protos.print_set_reset_prototype self mem) + ~prototype:(m.mname.node_id, m.mstatic) + ~pp_extra:(fun fmt () -> fprintf fmt "self->_reset = 1;%a" + Mod.pp_ghost_set_reset_spec mem) + fmt + let print_init_code self fmt m = let minit = List.map (fun i -> - match get_instr_desc i with MReset i -> i | _ -> assert false) m.minit in + match get_instr_desc i with + | MSetReset i -> i + | _ -> assert false) + m.minit in pp_print_function - ~pp_prototype:(print_init_prototype self) + ~pp_prototype:(Protos.print_init_prototype self) ~prototype:(m.mname.node_id, m.mstatic) ~pp_array_mem:(pp_c_decl_array_mem self) ~array_mems:(array_mems m) @@ -505,9 +547,11 @@ module Main = functor (Mod: MODIFIERS_SRC) -> struct let print_clear_code self fmt m = let minit = List.map (fun i -> - match get_instr_desc i with MReset i -> i | _ -> assert false) m.minit in + match get_instr_desc i with + | MSetReset i -> i + | _ -> assert false) m.minit in pp_print_function - ~pp_prototype:(print_clear_prototype self) + ~pp_prototype:(Protos.print_clear_prototype self) ~prototype:(m.mname.node_id, m.mstatic) ~pp_array_mem:(pp_c_decl_array_mem self) ~array_mems:(array_mems m) @@ -521,13 +565,13 @@ module Main = functor (Mod: MODIFIERS_SRC) -> struct fmt minit) fmt - let print_step_code machines dependencies self fmt m = + let print_step_code machines dependencies self mem fmt m = if not (!Options.ansi && is_generic_node (node_of_machine m)) then (* C99 code *) pp_print_function - ~pp_spec:(fun fmt () -> Mod.pp_step_spec fmt machines self m) - ~pp_prototype:(print_step_prototype self) + ~pp_spec:(fun fmt () -> Mod.pp_step_spec fmt machines self mem m) + ~pp_prototype:(Protos.print_step_prototype self mem) ~prototype:(m.mname.node_id, m.mstep.step_inputs, m.mstep.step_outputs) ~pp_local:(pp_c_decl_local_var m) ~base_locals:m.mstep.step_locals @@ -549,8 +593,8 @@ module Main = functor (Mod: MODIFIERS_SRC) -> struct let id, _, _ = call_of_expr e in mk_call_var_decl e.expr_loc id) m.mname.node_gencalls in pp_print_function - ~pp_spec:(fun fmt () -> Mod.pp_step_spec fmt machines self m) - ~pp_prototype:(print_step_prototype self) + ~pp_spec:(fun fmt () -> Mod.pp_step_spec fmt machines self mem m) + ~pp_prototype:(Protos.print_step_prototype self mem) ~prototype:(m.mname.node_id, m.mstep.step_inputs @ gen_locals @ gen_calls, m.mstep.step_outputs) @@ -706,12 +750,14 @@ module Main = functor (Mod: MODIFIERS_SRC) -> struct print_stateless_code machines dependencies fmt m else let self = mk_self m in - fprintf fmt "@[<v>%a%a@,@,%a%a@]" + let mem = mk_mem m in + fprintf fmt "@[<v>%a%a@,@,%a@,@,%a%a@]" print_alloc_function m - (* Reset function *) - (print_reset_code machines dependencies self) m + (* Reset functions *) + (print_clear_reset_code machines dependencies self mem) m + (print_set_reset_code self mem) m (* Step function *) - (print_step_code machines dependencies self) m + (print_step_code machines dependencies self mem) m (print_mpfr_code self) m let print_import_standard source_fmt () = @@ -826,7 +872,7 @@ module Main = functor (Mod: MODIFIERS_SRC) -> struct ~pp_epilogue:pp_print_cutcut) machines (* Print the spec predicates *) - (Mod.pp_predicates dependencies) machines + Mod.pp_predicates machines (* Print nodes one by one (in the previous order) *) (pp_print_list diff --git a/src/backends/EMF/EMF_backend.ml b/src/backends/EMF/EMF_backend.ml index c144f5b4..ff89bc40 100644 --- a/src/backends/EMF/EMF_backend.ml +++ b/src/backends/EMF/EMF_backend.ml @@ -165,7 +165,9 @@ let branch_cpt = ref 0 let get_instr_id fmt i = match Corelang.get_instr_desc i with | MLocalAssign(lhs,_) | MStateAssign (lhs, _) -> pp_var_name fmt lhs - | MReset i | MNoReset i -> fprintf fmt "%s" (reset_name i) + | MSetReset i | MNoReset i -> fprintf fmt "%s" (reset_name i) + (* TODO: handle clear_reset *) + | MClearReset -> () | MBranch _ -> incr branch_cpt; fprintf fmt "branch_%i" !branch_cpt | MStep (outs, id, _) -> print_protect fmt @@ -242,10 +244,12 @@ and branch_instr_vars m i = all_def_vars, def_vars, VSet.union read_guard read_vars | MBranch _ -> assert false (* branch instruction should admit at least one case *) - | MReset ni - | MNoReset ni -> - let write = ISet.singleton (reset_name ni) in - write, write, VSet.empty + | MSetReset ni + | MNoReset ni -> + let write = ISet.singleton (reset_name ni) in + write, write, VSet.empty + (* TODO: handle clear_reset *) + | MClearReset -> ISet.empty, ISet.empty, VSet.empty | MSpec _ | MComment _ -> assert false (* not available for EMF output *) (* A kind of super join_guards: all MBranch are postponed and sorted by @@ -298,7 +302,7 @@ let rec pp_emf_instr m fmt i = (pp_emf_cst_or_var m) expr ) - | MReset id + | MSetReset id -> ( fprintf fmt "\"kind\": \"reset\",@ \"lhs\": \"%s\",@ \"rhs\": \"true\"" (reset_name id) @@ -308,6 +312,8 @@ let rec pp_emf_instr m fmt i = fprintf fmt "\"kind\": \"reset\",@ \"lhs\": \"%s\",@ \"rhs\": \"false\"" (reset_name id) ) + (* TODO: handle clear_reset *) + | MClearReset -> () | MBranch (g, hl) -> ( let all_outputs, outputs, inputs = branch_instr_vars m i in diff --git a/src/backends/Horn/horn_backend_printers.ml b/src/backends/Horn/horn_backend_printers.ml index 9576a3b9..4fe13f20 100644 --- a/src/backends/Horn/horn_backend_printers.ml +++ b/src/backends/Horn/horn_backend_printers.ml @@ -295,10 +295,12 @@ let pp_instance_call machines reset_instances m fmt i inputs outputs = let rec pp_machine_instr machines reset_instances (m: machine_t) fmt instr : ident list = match get_instr_desc instr with | MSpec _ | MComment _ -> reset_instances + (* TODO: handle clear_reset *) + | MClearReset -> reset_instances | MNoReset i -> (* we assign middle_mem with mem_m. And declare i as reset *) pp_no_reset machines m fmt i; i::reset_instances - | MReset i -> (* we assign middle_mem with reset: reset(mem_m) *) + | MSetReset i -> (* we assign middle_mem with reset: reset(mem_m) *) pp_instance_reset machines m fmt i; i::reset_instances | MLocalAssign (i,v) -> diff --git a/src/corelang.ml b/src/corelang.ml index 32e57bda..a819930d 100644 --- a/src/corelang.ml +++ b/src/corelang.ml @@ -257,7 +257,7 @@ let update_expr_annot node_id e annot = e -let mkinstr ?lustre_eq instr_spec instr_desc = { +let mkinstr ?lustre_eq ?(instr_spec=[]) instr_desc = { instr_desc; (* lustre_expr = lustre_expr; *) instr_spec; @@ -662,9 +662,10 @@ let get_nodes prog = List.fold_left ( fun nodes decl -> match decl.top_decl_desc with - | Node _ -> decl::nodes - | Const _ | ImportedNode _ | Include _ | Open _ | TypeDef _ -> nodes + | Node _ -> decl::nodes + | Const _ | ImportedNode _ | Include _ | Open _ | TypeDef _ -> nodes ) [] prog + |> List.rev let get_imported_nodes prog = List.fold_left ( diff --git a/src/corelang.mli b/src/corelang.mli index 0f099f0d..e4d1053f 100644 --- a/src/corelang.mli +++ b/src/corelang.mli @@ -12,6 +12,11 @@ open Lustre_types +module VDeclModule: sig + type t + val compare: t -> t -> int +end with type t = Lustre_types.var_decl + module VSet: sig include Set.S val pp: Format.formatter -> t -> unit @@ -45,7 +50,7 @@ val mk_new_node_name: node_desc -> ident -> ident val mktop: top_decl_desc -> top_decl (* constructor for machine types *) -val mkinstr: (* ?lustre_expr:expr -> *)?lustre_eq: eq -> Machine_code_types.value_t Spec_types.formula_t -> Machine_code_types.instr_t_desc -> Machine_code_types.instr_t +val mkinstr: (* ?lustre_expr:expr -> *)?lustre_eq: eq -> ?instr_spec: Machine_code_types.value_t Spec_types.formula_t list -> Machine_code_types.instr_t_desc -> Machine_code_types.instr_t val get_instr_desc: Machine_code_types.instr_t -> Machine_code_types.instr_t_desc val update_instr_desc: Machine_code_types.instr_t -> Machine_code_types.instr_t_desc -> Machine_code_types.instr_t diff --git a/src/dune b/src/dune index b189c653..ed1caff8 100644 --- a/src/dune +++ b/src/dune @@ -23,6 +23,7 @@ machine_code_types spec_types spec_common + lustre_live scheduling_type log printers diff --git a/src/lustre_live.ml b/src/lustre_live.ml new file mode 100644 index 00000000..69c1ce6d --- /dev/null +++ b/src/lustre_live.ml @@ -0,0 +1,104 @@ +(********************************************************************) +(* *) +(* The LustreC compiler toolset / The LustreC Development Team *) +(* Copyright 2012 - -- ONERA - CNRS - INPT *) +(* *) +(* LustreC is free software, distributed WITHOUT ANY WARRANTY *) +(* under the terms of the GNU Lesser General Public License *) +(* version 2.1. *) +(* *) +(********************************************************************) + +open Lustre_types +open Dimension +open Utils +open ISet +module Live = Map.Make(Int) + +let pp_live fmt l = + Live.bindings + +let assigned s eq = + union s (of_list eq.eq_lhs) + +let rec occur_dim_expr s d = + match d.dim_desc with + | Dident x -> + add x s + | Dappl (_, ds) -> + List.fold_left occur_dim_expr s ds + | Dite (e, t, f) -> + occur_dim_expr (occur_dim_expr (occur_dim_expr s e) t) f + | Dlink d -> + occur_dim_expr s d + | _ -> s + +let rec occur_expr s e = + match e.expr_desc with + | Expr_ident x -> + add x s + | Expr_tuple es + | Expr_array es -> + List.fold_left occur_expr s es + | Expr_ite (e, t, f) -> + occur_expr (occur_expr (occur_expr s e) t) f + | Expr_arrow (e1, e2) + | Expr_fby (e1, e2) -> + occur_expr (occur_expr s e1) e2 + | Expr_access (e, d) + | Expr_power (e, d) -> + occur_expr (occur_dim_expr s d) e + | Expr_pre e -> + occur_expr s e + | Expr_when (e, x, _) -> + occur_expr (add x s) e + | Expr_merge (x, les) -> + List.fold_left (fun s (_, e) -> occur_expr s e) (add x s) les + | Expr_appl (_, e, r) -> + occur_expr (match r with Some r -> occur_expr s r | None -> s) e + | _ -> s + +let occur s eq = + occur_expr s eq.eq_rhs + +let live: (ident, ISet.t Live.t) Hashtbl.t = Hashtbl.create 32 + +let of_var_decls = + List.fold_left (fun s v -> add v.var_id s) empty + +let set_live_of nid outputs locals sorted_eqs = + let outputs = of_var_decls outputs in + let locals = of_var_decls locals in + let vars = union locals outputs in + let no_occur_after i = + let occ, _ = List.fold_left (fun (s, j) eq -> + if j <= i then (s, j + 1) else (occur s eq, j + 1)) + (empty, 0) sorted_eqs in + diff locals occ + in + let l, _, _ = List.fold_left (fun (l, asg, i) eq -> + let asg = inter (assigned asg eq) vars in + let noc = no_occur_after i in + let liv = diff asg noc in + Format.printf "asg %i: %a@." (i+1) pp_iset asg; + Format.printf "noc %i: %a@." (i+1) pp_iset noc; + Format.printf "liv %i: %a@." (i+1) pp_iset liv; + Live.add (i + 1) liv l, asg, i + 1) + (Live.add 0 empty Live.empty, empty, 0) sorted_eqs in + Format.(printf "@;%a@." (pp_print_list ~pp_open_box:pp_open_vbox0 + (fun fmt (i, l) -> fprintf fmt "%i : %a" i pp_iset l)) + (Live.bindings l)); + Hashtbl.add live nid l + +let live_i nid i = + Live.find i (Hashtbl.find live nid) + +let inter_live_i_with nid i = + let li = live_i nid i in + List.filter (fun v -> mem v.var_id li) + +let existential_vars nid i eq = + let li' = live_i nid (i-1) in + let li = live_i nid i in + let d = diff (union li' (assigned empty eq)) li in + List.filter (fun v -> mem v.var_id d) diff --git a/src/machine_code.ml b/src/machine_code.ml index abc36a7e..b840e6b7 100644 --- a/src/machine_code.ml +++ b/src/machine_code.ml @@ -42,11 +42,10 @@ type machine_env = { } -let build_env locals non_locals = - let all = VSet.union locals non_locals in - { - is_local = (fun id -> VSet.exists (fun v -> v.var_id = id) locals); - get_var = (fun id -> try VSet.get id all with Not_found -> +let build_env inputs locals outputs = + let all = List.sort_uniq VDeclModule.compare (locals @ inputs @ outputs) in + { is_local = (fun id -> List.exists (fun v -> v.var_id = id) locals); + get_var = (fun id -> try List.find (fun v -> v.var_id = id) all with Not_found -> (* Format.eprintf "Impossible to find variable %s in set %a@.@?" * id * VSet.pp all; *) @@ -64,7 +63,7 @@ let translate_ident env id = (* id is a var that shall be visible here , ie. in vars *) try let var_id = env.get_var id in - mk_val (Var var_id) var_id.var_type + vdecl_to_val var_id with Not_found -> (* id is a constant *) @@ -72,13 +71,12 @@ let translate_ident env id = let vdecl = (Corelang.var_decl_of_const (const_of_top (Hashtbl.find Corelang.consts_table id))) in - mk_val (Var vdecl) vdecl.var_type + vdecl_to_val vdecl with Not_found -> (* id is a tag, getting its type in the list of declared enums *) try - let typ = (typedef_of_top (Hashtbl.find Corelang.tag_table id)).tydef_id in - mk_val (Cst (Const_tag id)) (Type_predef.type_const typ) + id_to_tag id with Not_found -> Format.eprintf "internal error: Machine_code.translate_ident %s@.@?" id; assert false @@ -147,28 +145,40 @@ let translate_guard env expr = let rec translate_act env (y, expr) = let translate_act = translate_act env in let translate_guard = translate_guard env in - let translate_ident = translate_ident env in + (* let translate_ident = translate_ident env in *) let translate_expr = translate_expr env in let lustre_eq = Corelang.mkeq Location.dummy_loc ([y.var_id], expr) in match expr.expr_desc with | Expr_ite (c, t, e) -> - mk_conditional ~lustre_eq - (translate_guard c) - [translate_act (y, t)] - [translate_act (y, e)] + let c = translate_guard c in + let t, spec_t = translate_act (y, t) in + let e, spec_e = translate_act (y, e) in + mk_conditional ~lustre_eq c [t] [e], + mk_conditional_tr c spec_t spec_e | Expr_merge (x, hl) -> - mk_branch ~lustre_eq - (translate_ident x) - (List.map (fun (t, h) -> t, [translate_act (y, h)]) hl) + let var_x = env.get_var x in + let hl, spec_hl = List.(split (map (fun (t, h) -> + let h, spec_h = translate_act (y, h) in + (t, [h]), (t, spec_h)) + hl)) in + mk_branch ~lustre_eq var_x hl, + mk_branch_tr var_x spec_hl | _ -> - mk_assign ~lustre_eq y (translate_expr expr) + let e = translate_expr expr in + mk_assign ~lustre_eq y e, + mk_assign_tr y e + +let get_memory env mems eq = match eq.eq_lhs, eq.eq_rhs.expr_desc with + | ([x], Expr_pre _ | [x], Expr_fby _) when env.is_local x -> + let var_x = env.get_var x in + VSet.add var_x mems + | _ -> mems + +let get_memories env = + List.fold_left (get_memory env) VSet.empty (* Datastructure updated while visiting equations *) type machine_ctx = { - (* machine name *) - id: ident; - (* Memories *) - m: VSet.t; (* Reset instructions *) si: instr_t list; (* Instances *) @@ -177,25 +187,18 @@ type machine_ctx = { s: instr_t list; (* Memory pack spec *) mp: mc_formula_t list; - (* Clocked spec *) - c: mc_formula_t IMap.t; (* Transition spec *) - t: mc_formula_t list; + t: (var_decl list * var_decl list * var_decl list * mc_formula_t) list; } -let ctx_init id = { - id; - m = VSet.empty; +let ctx_init = { si = []; j = IMap.empty; s = []; mp = []; - c = IMap.empty; t = [] } -let ctx_dummy = ctx_init "" - (****************************************************************) (* Main function to translate equations into this machine context we are building *) @@ -203,57 +206,74 @@ let ctx_dummy = ctx_init "" let mk_control v l inst = mkinstr - True - (* (Imply (mk_clocked_on id vs, inst.instr_spec)) *) - (MBranch (v, [l, [inst]])) + (MBranch (vdecl_to_val v, [l, [inst]])) -let control_on_clock env ctx ck spec inst = - let rec aux (ck_ids, vs, ctx, spec, inst as acc) ck = +let control_on_clock env ck inst = + let rec aux (fspec, inst as acc) ck = match (Clocks.repr ck).cdesc with | Con (ck, cr, l) -> let id = Clocks.const_of_carrier cr in - let v = translate_ident env id in - let ck_ids' = String.concat "_" ck_ids in - let id' = id ^ "_" ^ ck_ids' in - let ck_spec = mk_condition v l in - aux (id :: ck_ids, - v :: vs, - { ctx with - c = IMap.add id ck_spec - (IMap.add id' (And [ck_spec; mk_clocked_on ck_ids' vs]) ctx.c) - }, - Imply (mk_clocked_on id' (v :: vs), spec), - mk_control v l inst) ck + let v = env.get_var id in + aux ((fun spec -> Imply (Equal (Var v, Tag l), fspec spec)), + mk_control v l inst) + ck | _ -> acc in - let _, _, ctx, spec, inst = aux ([], [], ctx, spec, inst) ck in - ctx, spec, inst + let fspec, inst = aux ((fun spec -> spec), inst) ck in + fspec, inst let reset_instance env i r c = match r with | Some r -> - let _, _, inst = control_on_clock env ctx_dummy c True + let _, inst = control_on_clock env c (mk_conditional (translate_guard env r) - [mkinstr True (MReset i)] - [mkinstr True (MNoReset i)]) in + [mkinstr (MSetReset i)] + [mkinstr (MNoReset i)]) in [ inst ] | None -> [] - -let translate_eq env ctx i eq = +let translate_eq env ctx id inputs locals outputs i eq = let translate_expr = translate_expr env in let translate_act = translate_act env in - let control_on_clock ck spec inst = - let ctx, _spec, inst = control_on_clock env ctx ck spec inst in + let locals_pi = Lustre_live.inter_live_i_with id (i-1) locals in + let outputs_pi = Lustre_live.inter_live_i_with id (i-1) outputs in + let locals_i = Lustre_live.inter_live_i_with id i locals in + let outputs_i = Lustre_live.inter_live_i_with id i outputs in + let pred_mp ctx a = + And [mk_memory_pack ~i:(i-1) id; a] :: ctx.mp in + let pred_t ctx a = + (inputs, locals_i, outputs_i, + Exists + (Lustre_live.existential_vars id i eq (locals @ outputs), + And [ + mk_transition ~i:(i-1) id + (vdecls_to_vals inputs) + (vdecls_to_vals locals_pi) + (vdecls_to_vals outputs_pi); + a + ])) + :: ctx.t in + let control_on_clock ck inst spec_mp spec_t = + let fspec, inst = control_on_clock env ck inst in { ctx with s = { inst with - instr_spec = mk_transition ~i ctx.id [] } :: ctx.s } + instr_spec = [ + mk_memory_pack ~i id; + mk_transition ~i id + (vdecls_to_vals inputs) + (vdecls_to_vals locals_i) + (vdecls_to_vals outputs_i) + ] } + :: ctx.s; + mp = pred_mp ctx spec_mp; + t = pred_t ctx (fspec spec_t); + } in let reset_instance = reset_instance env in - let mkinstr' = mkinstr ~lustre_eq:eq True in - let ctl ?(ck=eq.eq_rhs.expr_clock) spec instr = - control_on_clock ck spec (mkinstr' instr) in + let mkinstr' = mkinstr ~lustre_eq:eq in + let ctl ?(ck=eq.eq_rhs.expr_clock) instr spec_mp spec_t = + control_on_clock ck (mkinstr' instr) spec_mp spec_t in (* Format.eprintf "translate_eq %a with clock %a@." Printers.pp_node_eq eq Clocks.print_ck eq.eq_rhs.expr_clock; *) @@ -261,33 +281,38 @@ let translate_eq env ctx i eq = | [x], Expr_arrow (e1, e2) -> let var_x = env.get_var x in let td = Arrow.arrow_top_decl () in - let o = new_instance td eq.eq_rhs.expr_tag in + let inst = new_instance td eq.eq_rhs.expr_tag in let c1 = translate_expr e1 in let c2 = translate_expr e2 in + assert (c1.value_desc = Cst (Const_tag "true")); + assert (c2.value_desc = Cst (Const_tag "false")); let ctx = ctl - (mk_transition (node_name td) []) - (MStep ([var_x], o, [c1;c2])) in + (MStep ([var_x], inst, [c1; c2])) + (mk_memory_pack ~inst (node_name td)) + (mk_transition ~inst (node_name td) [] [] [vdecl_to_val var_x]) + in { ctx with - si = mkinstr True (MReset o) :: ctx.si; - j = IMap.add o (td, []) ctx.j; + si = mkinstr (MSetReset inst) :: ctx.si; + j = IMap.add inst (td, []) ctx.j; } - | [x], Expr_pre e1 when env.is_local x -> + | [x], Expr_pre e when env.is_local x -> let var_x = env.get_var x in - let ctx = ctl - True - (MStateAssign (var_x, translate_expr e1)) in - { ctx with - m = VSet.add var_x ctx.m; - } + let e = translate_expr e in + ctl + (MStateAssign (var_x, e)) + (mk_state_variable_pack var_x) + (mk_state_assign_tr var_x e) | [x], Expr_fby (e1, e2) when env.is_local x -> let var_x = env.get_var x in + let e2 = translate_expr e2 in let ctx = ctl - True - (MStateAssign (var_x, translate_expr e2)) in + (MStateAssign (var_x, e2)) + (mk_state_variable_pack var_x) + (mk_state_assign_tr var_x e2) + in { ctx with - m = VSet.add var_x ctx.m; si = mkinstr' (MStateAssign (var_x, translate_expr e1)) :: ctx.si; } @@ -298,31 +323,34 @@ let translate_eq env ctx i eq = let vl = List.map translate_expr el in let node_f = node_from_name f in let call_f = node_f, NodeDep.filter_static_inputs (node_inputs node_f) el in - let o = new_instance node_f eq.eq_rhs.expr_tag in + let inst = new_instance node_f eq.eq_rhs.expr_tag in let env_cks = List.fold_right (fun arg cks -> arg.expr_clock :: cks) el [eq.eq_rhs.expr_clock] in let call_ck = Clock_calculus.compute_root_clock (Clock_predef.ck_tuple env_cks) in let ctx = ctl ~ck:call_ck - True - (MStep (var_p, o, vl)) in + (MStep (var_p, inst, vl)) + (mk_memory_pack ~inst (node_name node_f)) + (mk_transition ~inst (node_name node_f) vl [] (vdecls_to_vals var_p)) + in (*Clocks.new_var true in Clock_calculus.unify_imported_clock (Some call_ck) eq.eq_rhs.expr_clock eq.eq_rhs.expr_loc; Format.eprintf "call %a: %a: %a@," Printers.pp_expr eq.eq_rhs Clocks.print_ck (Clock_predef.ck_tuple env_cks) Clocks.print_ck call_ck;*) { ctx with si = if Stateless.check_node node_f - then ctx.si else mkinstr True (MReset o) :: ctx.si; - j = IMap.add o call_f ctx.j; + then ctx.si else mkinstr (MSetReset inst) :: ctx.si; + j = IMap.add inst call_f ctx.j; s = (if Stateless.check_node node_f then [] - else reset_instance o r call_ck) - @ ctx.s + else reset_instance inst r call_ck) + @ ctx.s; } | [x], _ -> let var_x = env.get_var x in - control_on_clock eq.eq_rhs.expr_clock True (translate_act (var_x, eq.eq_rhs)) + let instr, spec = translate_act (var_x, eq.eq_rhs) in + control_on_clock eq.eq_rhs.expr_clock instr True spec | _ -> Format.eprintf "internal error: Machine_code.translate_eq %a@?" @@ -330,7 +358,7 @@ let translate_eq env ctx i eq = assert false let constant_equations locals = - VSet.fold (fun vdecl eqs -> + List.fold_left (fun eqs vdecl -> if vdecl.var_dec_const then { eq_lhs = [vdecl.var_id]; @@ -338,11 +366,11 @@ let constant_equations locals = eq_loc = vdecl.var_loc } :: eqs else eqs) - locals [] + [] locals -let translate_eqs env ctx eqs = +let translate_eqs env ctx id inputs locals outputs eqs = List.fold_right (fun eq (ctx, i) -> - let ctx = translate_eq env ctx i eq in + let ctx = translate_eq env ctx id inputs locals outputs i eq in ctx, i - 1) eqs (ctx, List.length eqs) |> fst @@ -385,22 +413,60 @@ let process_asserts nd = in vars, eql, assertl -let translate_core nid sorted_eqs locals other_vars = +let translate_core env nid sorted_eqs inputs locals outputs = let constant_eqs = constant_equations locals in - let env = build_env locals other_vars in - (* Compute constants' instructions *) - let ctx0 = translate_eqs env (ctx_init nid) constant_eqs in - assert (VSet.is_empty ctx0.m); + let ctx0 = translate_eqs env ctx_init nid inputs locals outputs constant_eqs in assert (ctx0.si = []); assert (IMap.is_empty ctx0.j); (* Compute ctx for all eqs *) - let ctx = translate_eqs env (ctx_init nid) sorted_eqs in + let ctx = translate_eqs env ctx_init nid inputs locals outputs sorted_eqs in ctx, ctx0.s +let zero = mk_val (Cst (Const_int 0)) Type_predef.type_int + +let memory_pack_0 nd = + { + mpname = nd; + mpindex = Some 0; + mpformula = And [StateVarPack ResetFlag; Equal (Memory ResetFlag, Val zero)] + } + +let memory_pack_toplevel nd i = + { + mpname = nd; + mpindex = None; + mpformula = Ternary (Memory ResetFlag, + StateVarPack ResetFlag, + mk_memory_pack ~i nd.node_id) + } + +let transition_0 nd = + { + tname = nd; + tindex = Some 0; + tinputs = nd.node_inputs; + tlocals = []; + toutputs = []; + tformula = True; + } + +let transition_toplevel nd i = + { + tname = nd; + tindex = None; + tinputs = nd.node_inputs; + tlocals = []; + toutputs = nd.node_outputs; + tformula = ExistsMem (Predicate (ResetCleared nd.node_id), + mk_transition nd.node_id ~i + (vdecls_to_vals (nd.node_inputs)) + [] + (vdecls_to_vals nd.node_outputs)); + } let translate_decl nd sch = (* Format.eprintf "Translating node %s@." nd.node_id; *) @@ -413,10 +479,10 @@ let translate_decl nd sch = let new_locals, assert_instrs, nd_node_asserts = process_asserts nd in (* Build the env: variables visible in the current scope *) - let locals_list = nd.node_locals @ new_locals in - let locals = VSet.of_list locals_list in - let inout_vars = (VSet.of_list (nd.node_inputs @ nd.node_outputs)) in - let env = build_env locals inout_vars in + let locals = nd.node_locals @ new_locals in + (* let locals = VSet.of_list locals_list in *) + (* let inout_vars = nd.node_inputs @ nd.node_outputs in *) + let env = build_env nd.node_inputs locals nd.node_outputs in (* Format.eprintf "Node content is %a@." Printers.pp_node nd; *) @@ -430,20 +496,54 @@ let translate_decl nd sch = * VSet.pp inout_vars * ; *) - let ctx, ctx0_s = translate_core - nd.node_id (assert_instrs@sorted_eqs) locals inout_vars in + let equations = assert_instrs @ sorted_eqs in + let mems = get_memories env equations in + (* Removing computed memories from locals. We also removed unused variables. *) + let locals = List.filter + (fun v -> not (VSet.mem v mems) && not (List.mem v.var_id unused)) locals in + (* Compute live sets for spec *) + Lustre_live.set_live_of nd.node_id nd.node_outputs locals equations; + + (* Translate equations *) + let ctx, ctx0_s = translate_core env nd.node_id equations + nd.node_inputs locals nd.node_outputs in (* Format.eprintf "ok4@.@?"; *) - (* Removing computed memories from locals. We also removed unused variables. *) - let updated_locals = - let l = VSet.elements (VSet.diff locals ctx.m) in - List.fold_left (fun res v -> if List.mem v.var_id unused then res else v::res) [] l - in + (* Build the machine *) let mmap = IMap.bindings ctx.j in + let mmemory_packs = + memory_pack_0 nd + :: List.mapi (fun i f -> + { + mpname = nd; + mpindex = Some (i + 1); + mpformula = red f + }) ctx.mp + @ [memory_pack_toplevel nd (List.length ctx.mp)] + in + let mtransitions = + transition_0 nd + :: List.mapi (fun i (tinputs, tlocals, toutputs, f) -> + { + tname = nd; + tindex = Some (i + 1); + tinputs; + tlocals; + toutputs; + tformula = red f; + }) ctx.t + @ [transition_toplevel nd (List.length ctx.t)] + in + let clear_reset = mkinstr ~instr_spec:[ + mk_memory_pack ~i:0 nd.node_id; + mk_transition ~i:0 nd.node_id + (vdecls_to_vals nd.node_inputs) + [] + []] MClearReset in { mname = nd; - mmemory = VSet.elements ctx.m; + mmemory = VSet.elements mems; mcalls = mmap; minstances = List.filter (fun (_, (n,_)) -> not (Stateless.check_node n)) mmap; minit = ctx.si; @@ -452,20 +552,19 @@ let translate_decl nd sch = mstep = { step_inputs = nd.node_inputs; step_outputs = nd.node_outputs; - step_locals = updated_locals; + step_locals = locals; step_checks = List.map (fun d -> d.Dimension.dim_loc, translate_expr env (expr_of_dimension d)) nd.node_checks; - step_instrs = ( - (* special treatment depending on the active backend. For horn backend, - common branches are not merged while they are in C or Java - backends. *) - if !Backends.join_guards then - join_guards_list ctx.s - else - ctx.s - ); + step_instrs = clear_reset :: + (* special treatment depending on the active backend. For horn backend, + common branches are not merged while they are in C or Java + backends. *) + (if !Backends.join_guards then + join_guards_list ctx.s + else + ctx.s); step_asserts = List.map (translate_expr env) nd_node_asserts; }; @@ -474,7 +573,7 @@ let translate_decl nd sch = cocospec node, or the current one is a cocospec node. Contract do not contain any statement or import. *) - mspec = { mnode_spec = nd.node_spec; mtransitions = [] }; + mspec = { mnode_spec = nd.node_spec; mtransitions; mmemory_packs }; mannot = nd.node_annot; msch = Some sch; } diff --git a/src/machine_code_common.ml b/src/machine_code_common.ml index 35512053..47fa5d8c 100644 --- a/src/machine_code_common.ml +++ b/src/machine_code_common.ml @@ -1,7 +1,6 @@ open Lustre_types open Machine_code_types open Spec_types -open Spec_common open Corelang open Utils.Format @@ -10,63 +9,142 @@ let print_statelocaltag = true let is_memory m id = (List.exists (fun o -> o.var_id = id.var_id) m.mmemory) +let is_reset_flag id = + id.var_id = "_reset" + +let pp_vdecl fmt v = + pp_print_string fmt v.var_id + let rec pp_val m fmt v = let pp_val = pp_val m in match v.value_desc with | Cst c -> Printers.pp_const fmt c | Var v -> - if is_memory m v then - if print_statelocaltag then - fprintf fmt "{%s}" v.var_id - else - pp_print_string fmt v.var_id - else - if print_statelocaltag then - fprintf fmt "%s" v.var_id - else - pp_print_string fmt v.var_id - | Array vl -> fprintf fmt "[%a]" (Utils.fprintf_list ~sep:", " pp_val) vl + if is_memory m v then + if print_statelocaltag then + fprintf fmt "{%s}" v.var_id + else + pp_print_string fmt v.var_id + else + if print_statelocaltag then + fprintf fmt "%s" v.var_id + else + pp_vdecl fmt v + | Array vl -> pp_print_bracketed pp_val fmt vl | Access (t, i) -> fprintf fmt "%a[%a]" pp_val t pp_val i | Power (v, n) -> fprintf fmt "(%a^%a)" pp_val v pp_val n - | Fun (n, vl) -> fprintf fmt "%s (%a)" n (Utils.fprintf_list ~sep:", " pp_val) vl - -module PrintSpec = PrintSpec(struct - type t = value_t - type ctx = machine_t - let pp_val = pp_val - end) - -let rec pp_instr m fmt i = - let pp_val = pp_val m and - pp_branch = pp_branch m in - let _ = - match i.instr_desc with + | Fun (n, vl) -> fprintf fmt "%s%a" n (pp_print_parenthesized pp_val) vl + +module PrintSpec = struct + + let pp_reg fmt = function + | ResetFlag -> pp_print_string fmt "{RESET}" + | StateVar v -> fprintf fmt "{OUT:%a}" pp_vdecl v + + let pp_expr: type a. machine_t -> formatter -> (value_t, a) expression_t -> unit = + fun m fmt -> function + | Val v -> pp_val m fmt v + | Tag t -> pp_print_string fmt t + | Var v -> pp_vdecl fmt v + | Memory r -> pp_reg fmt r + + let pp_predicate m fmt p = + let pp_expr: type a. formatter -> (value_t, a) expression_t -> unit = + fun fmt e -> pp_expr m fmt e + in + match p with + | Transition (f, inst, i, inputs, locals, outputs) -> + fprintf fmt "Transition_%a<%a>%a%a" + pp_print_string f + (pp_print_option ~none:(fun fmt () -> pp_print_string fmt "SELF") + pp_print_string) inst + (pp_print_option pp_print_int) i + (pp_print_parenthesized pp_expr) (inputs @ locals @ outputs) + | MemoryPack (f, inst, i) -> + fprintf fmt "MemoryPack_%a<%a>%a" + pp_print_string f + (pp_print_option ~none:(fun fmt () -> pp_print_string fmt "SELF") + pp_print_string) inst + (pp_print_option pp_print_int) i + | ResetCleared f -> + fprintf fmt "ResetCleared_%a" pp_print_string f + | Initialization -> () + + let pp_spec m = + let pp_expr: type a. formatter -> (value_t, a) expression_t -> unit = + fun fmt e -> pp_expr m fmt e + in + let rec pp_spec fmt f = + match f with + | True -> pp_print_string fmt "true" + | False -> pp_print_string fmt "false" + | Equal (a, b) -> + fprintf fmt "%a == %a" pp_expr a pp_expr b + | And fs -> + pp_print_list ~pp_sep:(fun fmt () -> fprintf fmt "@ ∧ ") + (fun fmt spec -> fprintf fmt "@[%a@]" pp_spec spec) fmt fs + | Or fs -> + pp_print_list ~pp_sep:(fun fmt () -> fprintf fmt "@ ∨ ") + (fun fmt spec -> fprintf fmt "@[%a@]" pp_spec spec) fmt fs + | Imply (a, b) -> + fprintf fmt "%a@ -> %a" pp_spec a pp_spec b + | Exists (xs, a) -> + fprintf fmt "@[<hv 2>∃ @[<h>%a,@]@ %a@]" + (pp_comma_list Printers.pp_var) xs pp_spec a + | Forall (xs, a) -> + fprintf fmt "@[<hv 2>∀ @[<h>%a,@]@ %a@]" + (pp_comma_list Printers.pp_var) xs pp_spec a + | Ternary (e, a, b) -> + fprintf fmt "If %a Then (@[<hov>%a@]) Else (@[<hov>%a@])" + pp_expr e pp_spec a pp_spec b + | Predicate p -> + pp_predicate m fmt p + | StateVarPack r -> + fprintf fmt "StateVarPack<%a>" pp_reg r + | ExistsMem (rc, tr) -> + fprintf fmt "@[<hv 2>∃ MEM,@ %a@]" pp_spec (And [rc; tr]) + in + pp_spec + +end + +let pp_spec m = + pp_print_list + ~pp_open_box:pp_open_vbox0 + ~pp_prologue:pp_print_cut + (fun fmt -> fprintf fmt "@[<h>--%@ %a@]" (PrintSpec.pp_spec m)) + +let rec pp_instr m fmt i = + let pp_val = pp_val m in + let pp_branch = pp_branch m in + begin match i.instr_desc with | MLocalAssign (i,v) -> fprintf fmt "%s := %a" i.var_id pp_val v | MStateAssign (i,v) -> fprintf fmt "{%s} := %a" i.var_id pp_val v - | MReset i -> fprintf fmt "reset %s" i + | MSetReset i -> fprintf fmt "set_reset %s" i + | MClearReset -> fprintf fmt "clear_reset %s" m.mname.node_id | MNoReset i -> fprintf fmt "noreset %s" i | MStep (il, i, vl) -> - fprintf fmt "%a = %s (%a)" - (Utils.fprintf_list ~sep:", " (fun fmt v -> pp_print_string fmt v.var_id)) il - i - (Utils.fprintf_list ~sep:", " pp_val) vl + fprintf fmt "%a := %s%a" + (pp_comma_list pp_vdecl) il + i + (pp_print_parenthesized pp_val) vl | MBranch (g,hl) -> - fprintf fmt "@[<v 2>case(%a) {@,%a@,}@]" - pp_val g - (Utils.fprintf_list ~sep:"@," pp_branch) hl + fprintf fmt "@[<v 2>case(%a) {@,%a@]@,}" + pp_val g + (pp_print_list ~pp_open_box:pp_open_vbox0 pp_branch) hl | MComment s -> pp_print_string fmt s | MSpec s -> pp_print_string fmt ("@" ^ s) - - in + + end; (* Annotation *) (* let _ = *) (* match i.lustre_expr with None -> () | Some e -> fprintf fmt " -- original expr: %a" Printers.pp_expr e *) (* in *) begin match i.lustre_eq with | None -> () - | Some eq -> fprintf fmt " -- original eq: %a" Printers.pp_node_eq eq + | Some eq -> fprintf fmt " @[<h>-- original eq: %a@]" Printers.pp_node_eq eq end; - fprintf fmt "@ --%@ %a" (PrintSpec.pp_spec m) i.instr_spec + pp_spec m fmt i.instr_spec and pp_branch m fmt (t, h) = @@ -95,21 +173,56 @@ let get_node_def id m = let machine_vars m = m.mstep.step_inputs @ m.mstep.step_locals @ m.mstep.step_outputs @ m.mmemory let pp_step m fmt s = - let pp_list = pp_print_list ~pp_sep:pp_print_comma in - fprintf fmt "@[<v>inputs : %a@ outputs: %a@ locals : %a@ checks : %a@ instrs : @[%a@]@ asserts : @[%a@]@]@ " - (pp_list Printers.pp_var) s.step_inputs - (pp_list Printers.pp_var) s.step_outputs - (pp_list Printers.pp_var) s.step_locals - (pp_list (fun fmt (_, c) -> pp_val m fmt c)) + fprintf fmt + "@[<v>\ + inputs : %a@ \ + outputs: %a@ \ + locals : %a@ \ + checks : %a@ \ + instrs : @[%a@]@ \ + asserts : @[%a@]@]@ " + (pp_comma_list Printers.pp_var) s.step_inputs + (pp_comma_list Printers.pp_var) s.step_outputs + (pp_comma_list Printers.pp_var) s.step_locals + (pp_comma_list (fun fmt (_, c) -> pp_val m fmt c)) s.step_checks (pp_instrs m) s.step_instrs - (pp_list (pp_val m)) s.step_asserts - + (pp_comma_list (pp_val m)) s.step_asserts let pp_static_call fmt (node, args) = - fprintf fmt "%s<%a>" - (node_name node) - (Utils.fprintf_list ~sep:", " Dimension.pp_dimension) args + fprintf fmt "%s<%a>" + (node_name node) + (pp_comma_list Dimension.pp_dimension) args + +let pp_instance fmt (o1, o2) = + fprintf fmt "(%s, %a)" + o1 + pp_static_call o2 + +let pp_memory_pack m fmt mp = + fprintf fmt + "@[<v 2>MemoryPack_%a<SELF>%a =@ %a@]" + pp_print_string mp.mpname.node_id + (pp_print_option pp_print_int) mp.mpindex + (PrintSpec.pp_spec m) mp.mpformula + +let pp_memory_packs m fmt = + fprintf fmt + "@[<v 2>memory_packs:@ %a@]" + (pp_print_list (pp_memory_pack m)) + +let pp_transition m fmt t = + fprintf fmt + "@[<v 2>Transition_%a<SELF>%a%a =@ %a@]" + pp_print_string t.tname.node_id + (pp_print_option pp_print_int) t.tindex + (pp_print_parenthesized pp_vdecl) (t.tinputs @ t.tlocals @ t.toutputs) + (PrintSpec.pp_spec m) t.tformula + +let pp_transitions m fmt = + fprintf fmt + "@[<v 2>transitions:@ %a@]" + (pp_print_list (pp_transition m)) let pp_machine fmt m = fprintf fmt @@ -120,24 +233,25 @@ let pp_machine fmt m = const : %a@ \ step :@ \ @[<v 2>%a@]@ \ - spec : @[%t@]@ \ + spec : @[<v>%t@ %a@ @ %a@]@ \ annot : @[%a@]@]@ " m.mname.node_id - (Utils.fprintf_list ~sep:", " Printers.pp_var) m.mmemory - (Utils.fprintf_list ~sep:", " (fun fmt (o1, o2) -> fprintf fmt "(%s, %a)" o1 pp_static_call o2)) m.minstances - (Utils.fprintf_list ~sep:"@ " (pp_instr m)) m.minit - (Utils.fprintf_list ~sep:"@ " (pp_instr m)) m.mconst + (pp_comma_list Printers.pp_var) m.mmemory + (pp_comma_list pp_instance) m.minstances + (pp_instrs m) m.minit + (pp_instrs m) m.mconst (pp_step m) m.mstep (fun fmt -> match m.mspec.mnode_spec with | None -> () | Some (NodeSpec id) -> fprintf fmt "cocospec: %s" id | Some (Contract spec) -> Printers.pp_spec fmt spec) - (Utils.fprintf_list ~sep:"@ " Printers.pp_expr_annot) m.mannot + (pp_memory_packs m) m.mspec.mmemory_packs + (pp_transitions m) m.mspec.mtransitions + (pp_print_list Printers.pp_expr_annot) m.mannot -let pp_machines fmt ml = - fprintf fmt "@[<v 0>%a@]" (Utils.fprintf_list ~sep:"@," pp_machine) ml +let pp_machines = + pp_print_list ~pp_open_box:pp_open_vbox0 pp_machine - let rec is_const_value v = match v.value_desc with | Cst _ -> true @@ -169,12 +283,26 @@ let is_output m id = let get_instr_spec i = i.instr_spec +let mk_val v t = + { value_desc = v; + value_type = t; + value_annot = None } + +let vdecl_to_val vd = + mk_val (Var vd) vd.var_type + +let vdecls_to_vals = + List.map vdecl_to_val + +let id_to_tag id = + let typ = (typedef_of_top (Hashtbl.find Corelang.tag_table id)).tydef_id in + mk_val (Cst (Const_tag id)) (Type_predef.type_const typ) + let mk_conditional ?lustre_eq c t e = mkinstr ?lustre_eq (* (Ternary (Val c, * And (List.map get_instr_spec t), * And (List.map get_instr_spec e))) *) - True (MBranch(c, [ (tag_true, t); (tag_false, e) ])) @@ -184,20 +312,13 @@ let mk_branch ?lustre_eq c br = (* (And (List.map (fun (l, instrs) -> * Imply (Equal (Val c, Tag l), And (List.map get_instr_spec instrs))) * br)) *) - True - (MBranch (c, br)) + (MBranch (vdecl_to_val c, br)) let mk_assign ?lustre_eq x v = mkinstr ?lustre_eq (* (Equal (Var x, Val v)) *) - True (MLocalAssign (x, v)) -let mk_val v t = - { value_desc = v; - value_type = t; - value_annot = None } - let arrow_machine = let state = "_first" in let var_state = dummy_var_decl state Type_predef.type_bool(* (Types.new_ty Types.Tbool) *) in @@ -212,7 +333,7 @@ let arrow_machine = mmemory = [var_state]; mcalls = []; minstances = []; - minit = [mkinstr True (MStateAssign(var_state, cst true))]; + minit = [mkinstr (MStateAssign(var_state, cst true))]; mstatic = []; mconst = []; mstep = { @@ -221,14 +342,14 @@ let arrow_machine = step_locals = []; step_checks = []; step_instrs = [mk_conditional (mk_val (Var var_state) Type_predef.type_bool) - (List.map (mkinstr True) - [MStateAssign(var_state, cst false); - MLocalAssign(var_output, mk_val (Var var_input1) t_arg)]) - (List.map (mkinstr True) - [MLocalAssign(var_output, mk_val (Var var_input2) t_arg)]) ]; + (List.map mkinstr + [MStateAssign(var_state, cst false); + MLocalAssign(var_output, mk_val (Var var_input1) t_arg)]) + (List.map mkinstr + [MLocalAssign(var_output, mk_val (Var var_input2) t_arg)]) ]; step_asserts = []; }; - mspec = { mnode_spec = None; mtransitions = [] }; + mspec = { mnode_spec = None; mtransitions = []; mmemory_packs = [] }; mannot = []; msch = None } @@ -269,7 +390,7 @@ let empty_machine = step_instrs = []; step_asserts = []; }; - mspec = { mnode_spec = None; mtransitions = [] }; + mspec = { mnode_spec = None; mtransitions = []; mmemory_packs = [] }; mannot = []; msch = None } @@ -374,7 +495,7 @@ let rec dimension_of_value value = | _ -> assert false - let rec join_branches hl1 hl2 = +let rec join_branches hl1 hl2 = match hl1, hl2 with | [] , _ -> hl2 | _ , [] -> hl1 @@ -384,15 +505,16 @@ let rec dimension_of_value value = else (t1, List.fold_right join_guards h1 h2) :: join_branches q1 q2 and join_guards inst1 insts2 = - match get_instr_desc inst1, List.map get_instr_desc insts2 with - | _ , [] -> - [inst1] - | MBranch (x1, hl1), MBranch (x2, hl2) :: _ when x1 = x2 -> - mkinstr True - (* TODO on pourrait uniquement concatener les lustres de inst1 et hd(inst2) *) - (MBranch (x1, join_branches (sort_handlers hl1) (sort_handlers hl2))) - :: (List.tl insts2) - | _ -> inst1 :: insts2 + match get_instr_desc inst1, insts2 with + | MBranch (x1, hl1), + ({ instr_desc = MBranch (x2, hl2); _ } as inst2) :: insts2 + when x1 = x2 -> + mkinstr + ~instr_spec:(get_instr_spec inst1 @ get_instr_spec inst2) + (* TODO on pourrait uniquement concatener les lustres de inst1 et hd(inst2) *) + (MBranch (x1, join_branches (sort_handlers hl1) (sort_handlers hl2))) + :: insts2 + | _ -> inst1 :: insts2 let join_guards_list insts = List.fold_right join_guards insts [] diff --git a/src/machine_code_common.mli b/src/machine_code_common.mli index 341d81c4..0655bc63 100644 --- a/src/machine_code_common.mli +++ b/src/machine_code_common.mli @@ -1,5 +1,6 @@ val pp_val: Machine_code_types.machine_t -> Format.formatter -> Machine_code_types.value_t -> unit val is_memory: Machine_code_types.machine_t -> Lustre_types.var_decl -> bool +val is_reset_flag: Lustre_types.var_decl -> bool val is_output: Machine_code_types.machine_t -> Lustre_types.var_decl -> bool val is_const_value: Machine_code_types.value_t -> bool val get_const_assign: Machine_code_types.machine_t -> Lustre_types.var_decl -> Machine_code_types.value_t @@ -7,8 +8,11 @@ val get_stateless_status: Machine_code_types.machine_t -> bool * bool val get_stateless_status_top_decl: Lustre_types.top_decl -> bool * bool val is_stateless: Machine_code_types.machine_t -> bool val mk_val: Machine_code_types.value_t_desc -> Types.type_expr -> Machine_code_types.value_t +val vdecl_to_val: Lustre_types.var_decl -> Machine_code_types.value_t +val vdecls_to_vals: Lustre_types.var_decl list -> Machine_code_types.value_t list +val id_to_tag: Lustre_types.ident -> Machine_code_types.value_t val mk_conditional: ?lustre_eq:Lustre_types.eq -> Machine_code_types.value_t -> Machine_code_types.instr_t list -> Machine_code_types.instr_t list -> Machine_code_types.instr_t -val mk_branch: ?lustre_eq:Lustre_types.eq -> Machine_code_types.value_t -> (Lustre_types.label * Machine_code_types.instr_t list) list -> Machine_code_types.instr_t +val mk_branch: ?lustre_eq:Lustre_types.eq -> Lustre_types.var_decl -> (Lustre_types.label * Machine_code_types.instr_t list) list -> Machine_code_types.instr_t val mk_assign: ?lustre_eq:Lustre_types.eq -> Lustre_types.var_decl -> Machine_code_types.value_t -> Machine_code_types.instr_t val empty_machine: Machine_code_types.machine_t val arrow_machine: Machine_code_types.machine_t @@ -26,3 +30,5 @@ val get_machine: Machine_code_types.machine_t list -> string -> Machine_code_typ val get_node_def: string -> Machine_code_types.machine_t -> Lustre_types.node_desc val join_guards_list: Machine_code_types.instr_t list -> Machine_code_types.instr_t list val machine_vars: Machine_code_types.machine_t -> Lustre_types.var_decl list + +module PrintSpec: sig val pp_spec: Machine_code_types.machine_t -> Format.formatter -> Machine_code_types.value_t Spec_types.formula_t -> unit end diff --git a/src/machine_code_types.ml b/src/machine_code_types.ml index 9403b67b..7cdfc1fe 100644 --- a/src/machine_code_types.ml +++ b/src/machine_code_types.ml @@ -23,12 +23,13 @@ type instr_t = instr_desc: instr_t_desc; (* main data: the content *) (* lustre_expr: expr option; (* possible representation as a lustre expression *) *) lustre_eq: eq option; (* possible representation as a lustre flow equation *) - instr_spec: mc_formula_t + instr_spec: mc_formula_t list } and instr_t_desc = | MLocalAssign of var_decl * value_t | MStateAssign of var_decl * value_t - | MReset of ident + | MClearReset + | MSetReset of ident | MNoReset of ident | MStep of var_decl list * ident * value_t list | MBranch of value_t * (label * instr_t list) list @@ -47,10 +48,12 @@ type step_t = { type static_call = top_decl * (Dimension.dim_expr list) type mc_transition_t = value_t transition_t +type mc_memory_pack_t = value_t memory_pack_t type machine_spec = { mnode_spec: node_spec_t option; - mtransitions: mc_transition_t list + mtransitions: mc_transition_t list; + mmemory_packs: mc_memory_pack_t list } type machine_t = { diff --git a/src/optimize_machine.ml b/src/optimize_machine.ml index ab06ccdf..b79835ab 100644 --- a/src/optimize_machine.ml +++ b/src/optimize_machine.ml @@ -28,11 +28,13 @@ let pp_elim m fmt elim = let rec eliminate m elim instr = let e_expr = eliminate_expr m elim in match get_instr_desc instr with - | MSpec _ | MComment _ -> instr | MLocalAssign (i,v) -> update_instr_desc instr (MLocalAssign (i, e_expr v)) | MStateAssign (i,v) -> update_instr_desc instr (MStateAssign (i, e_expr v)) - | MReset _ -> instr - | MNoReset _ -> instr + | MSetReset _ + | MNoReset _ + | MClearReset + | MSpec _ + | MComment _ -> instr | MStep (il, i, vl) -> update_instr_desc instr (MStep(il, i, List.map e_expr vl)) | MBranch (g,hl) -> update_instr_desc instr ( @@ -115,14 +117,16 @@ let rec simplify_instr_offset m instr = match get_instr_desc instr with | MLocalAssign (v, expr) -> update_instr_desc instr (MLocalAssign (v, simplify_expr_offset m expr)) | MStateAssign (v, expr) -> update_instr_desc instr (MStateAssign (v, simplify_expr_offset m expr)) - | MReset _ -> instr - | MNoReset _ -> instr + | MSetReset _ + | MNoReset _ + | MClearReset + | MSpec _ + | MComment _ -> instr | MStep (outputs, id, inputs) -> update_instr_desc instr (MStep (outputs, id, List.map (simplify_expr_offset m) inputs)) | MBranch (cond, brl) -> update_instr_desc instr ( MBranch(simplify_expr_offset m cond, List.map (fun (l, il) -> l, simplify_instrs_offset m il) brl) ) - | MSpec _ | MComment _ -> instr and simplify_instrs_offset m instrs = List.map (simplify_instr_offset m) instrs @@ -284,7 +288,6 @@ let instr_of_const top_const = let lustre_eq = mkeq loc ([const.const_id], mkexpr loc (Expr_const const.const_value)) in mkinstr ~lustre_eq - True (MLocalAssign (vdecl, mk_val (Cst const.const_value) vdecl.var_type)) (* We do not perform this optimization on contract nodes since there @@ -499,11 +502,13 @@ let rec value_replace_var fvar value = let rec instr_replace_var fvar instr cont = match get_instr_desc instr with - | MSpec _ | MComment _ -> instr_cons instr cont | MLocalAssign (i, v) -> instr_cons (update_instr_desc instr (MLocalAssign (fvar i, value_replace_var fvar v))) cont | MStateAssign (i, v) -> instr_cons (update_instr_desc instr (MStateAssign (i, value_replace_var fvar v))) cont - | MReset _ -> instr_cons instr cont - | MNoReset _ -> instr_cons instr cont + | MSetReset _ + | MNoReset _ + | MClearReset + | MSpec _ + | MComment _ -> instr_cons instr cont | MStep (il, i, vl) -> instr_cons (update_instr_desc instr (MStep (List.map fvar il, i, List.map (value_replace_var fvar) vl))) cont | MBranch (g, hl) -> instr_cons (update_instr_desc instr (MBranch (value_replace_var fvar g, List.map (fun (h, il) -> (h, instrs_replace_var fvar il [])) hl))) cont @@ -763,7 +768,7 @@ let optimize params prog node_schs machine_code = in - prog, List.rev machine_code + prog, machine_code (* Local Variables: *) diff --git a/src/plugins/scopes/scopes.ml b/src/plugins/scopes/scopes.ml index 0772b160..45e4e358 100644 --- a/src/plugins/scopes/scopes.ml +++ b/src/plugins/scopes/scopes.ml @@ -220,7 +220,7 @@ let pp_scopes fmt scopes = let update_machine main_node machine scopes = let stateassign (vdecl_mem, vdecl_orig) = - mkinstr True + mkinstr (MStateAssign (vdecl_mem, mk_val (Var vdecl_orig) vdecl_orig.var_type)) in let selection = @@ -248,7 +248,7 @@ let update_machine main_node machine scopes = mstep = { machine.mstep with step_instrs = machine.mstep.step_instrs - @ (mkinstr True (MComment "Registering all flows"))::(List.map stateassign new_mems) + @ (mkinstr (MComment "Registering all flows"))::(List.map stateassign new_mems) } } diff --git a/src/spec_common.ml b/src/spec_common.ml index 3eb96c70..44cd7f9b 100644 --- a/src/spec_common.ml +++ b/src/spec_common.ml @@ -10,8 +10,15 @@ let is_false = function | False -> true | _ -> false -let rec red = function - | Equal (a, b) when a = b -> +let expr_eq: type a b. (a, left_v) expression_t -> (a, b) expression_t -> bool = + fun a b -> + match a, b with + | Var x, Var y -> x = y + | Memory r1, Memory r2 -> r1 = r2 + | _ -> false + +let rec red: type a. a formula_t -> a formula_t = function + | Equal (a, b) when expr_eq a b -> True | And l -> @@ -45,11 +52,17 @@ let rec red = function | Exists (x, p) -> let p' = red p in - if is_true p' then True else Exists (x, p') + if is_true p' then True else begin match x with + | [] -> p' + | x -> Exists (x, p') + end | Forall (x, p) -> let p' = red p in - if is_true p' then True else Forall (x, p') + if is_true p' then True else begin match x with + | [] -> p' + | x -> Forall (x, p') + end | Ternary (x, a, b) -> let a' = red a in @@ -59,74 +72,38 @@ let rec red = function | f -> f (* smart constructors *) -let mk_condition x l = - if l = tag_true then Ternary (Val x, True, False) - else if l = tag_false then Ternary (Val x, False, True) - else Equal (Val x, Tag l) +(* let mk_condition x l = + * if l = tag_true then Ternary (Val x, True, False) + * else if l = tag_false then Ternary (Val x, False, True) + * else Equal (Val x, Tag l) *) let vals vs = List.map (fun v -> Val v) vs -let mk_pred_call pred vars = - Predicate (pred, vals vars) - -let mk_clocked_on id = - mk_pred_call (Clocked_on id) - -let mk_transition ?i id = - mk_pred_call (Transition (id, i)) - -module type SPECVALUE = sig - type t - type ctx - val pp_val: ctx -> Format.formatter -> t -> unit -end - -module PrintSpec(SV: SPECVALUE) = struct - - open Utils.Format - - let pp_state fmt = function - | In -> pp_print_string fmt "IN" - | Out -> pp_print_string fmt "OUT" - - let pp_expr ctx fmt = function - | Val v -> SV.pp_val ctx fmt v - | Tag t -> pp_print_string fmt t - | Var v -> pp_print_string fmt v.var_id - | Instance (s, i) -> fprintf fmt "%a:%a" pp_state s pp_print_string i - | Memory (s, i) -> fprintf fmt "%a:%a" pp_state s pp_print_string i - - let pp_predicate fmt = function - | Clocked_on x -> fprintf fmt "On<%a>" pp_print_string x - | Transition (f, i) -> - fprintf fmt "Transition<%a>%a" - pp_print_string f - (pp_print_option pp_print_int) i - | Initialization -> () - - let pp_spec ctx = - let pp_expr = pp_expr ctx in - let rec pp_spec fmt f = - match f with - | True -> pp_print_string fmt "true" - | False -> pp_print_string fmt "false" - | Equal (a, b) -> - fprintf fmt "%a == %a" pp_expr a pp_expr b - | And fs -> - pp_print_list ~pp_sep:(fun fmt () -> pp_print_string fmt "/\\") pp_spec fmt fs - | Or fs -> - pp_print_list ~pp_sep:(fun fmt () -> pp_print_string fmt "\\/") pp_spec fmt fs - | Imply (a, b) -> - fprintf fmt "%a -> %a" pp_spec a pp_spec b - | Exists (xs, a) -> - fprintf fmt "∃%a, %a" (pp_print_list Printers.pp_var) xs pp_spec a - | Forall (xs, a) -> - fprintf fmt "∀%a, %a" (pp_print_list Printers.pp_var) xs pp_spec a - | Ternary (e, a, b) -> - fprintf fmt "If %a Then %a Else %a" pp_expr e pp_spec a pp_spec b - | Predicate (p, es) -> - fprintf fmt "%a%a" pp_predicate p (pp_print_parenthesized pp_expr) es - in - pp_spec - -end +let mk_pred_call pred = + Predicate pred + +(* let mk_clocked_on id = + * mk_pred_call (Clocked_on id) *) + +let mk_transition ?i ?inst id inputs locals outputs = + mk_pred_call + (Transition (id, inst, i, vals inputs, vals locals, vals outputs)) + +let mk_memory_pack ?i ?inst id = + mk_pred_call (MemoryPack (id, inst, i)) + +let mk_state_variable_pack x = + StateVarPack (StateVar x) + +let mk_state_assign_tr x v = + Equal (Memory (StateVar x), Val v) + +let mk_conditional_tr v t f = + Ternary (Val v, t, f) + +let mk_branch_tr x hl = + And (List.map (fun (t, spec) -> Imply (Equal (Var x, Tag t), spec)) hl) + +let mk_assign_tr x v = + Equal (Var x, Val v) + diff --git a/src/spec_types.ml b/src/spec_types.ml index a96d0a44..32391548 100644 --- a/src/spec_types.ml +++ b/src/spec_types.ml @@ -1,33 +1,49 @@ open Lustre_types -type state_t = - | In - | Out - -type 'a expression_t = - | Val of 'a - | Tag of ident - | Var of var_decl - | Instance of state_t * ident - | Memory of state_t * ident - -type predicate_t = - (* | Memory_pack *) - | Clocked_on of ident - | Transition of ident * int option +type register_t = + | ResetFlag + | StateVar of var_decl + +type left_v +type right_v + +type ('a, _) expression_t = + | Val: 'a -> ('a, right_v) expression_t + | Tag: ident -> ('a, right_v) expression_t + | Var: var_decl -> ('a, left_v) expression_t + | Memory: register_t -> ('a, left_v) expression_t + +(** TODO: why moving this elsewhere makes the exhaustiveness check fail? *) +let type_of_l_value: type a. (a, left_v) expression_t -> Types.type_expr = + function + | Var v -> v.var_type + | Memory ResetFlag -> Type_predef.type_bool + | Memory (StateVar v) -> v.var_type + +type ('a, 'b) expressions_t = ('a, 'b) expression_t list + +type 'a predicate_t = + | Transition: ident * ident option * int option + * ('a, 'b) expressions_t + * ('a, 'b) expressions_t + * ('a, 'b) expressions_t -> 'a predicate_t + | MemoryPack of ident * ident option * int option | Initialization + | ResetCleared of ident type 'a formula_t = | True | False - | Equal of 'a expression_t * 'a expression_t + | Equal: ('a, left_v) expression_t * ('a, 'b) expression_t -> 'a formula_t | And of 'a formula_t list | Or of 'a formula_t list | Imply of 'a formula_t * 'a formula_t | Exists of var_decl list * 'a formula_t | Forall of var_decl list * 'a formula_t - | Ternary of 'a expression_t * 'a formula_t * 'a formula_t - | Predicate of predicate_t * 'a expression_t list + | Ternary: ('a, 'b) expression_t * 'a formula_t * 'a formula_t -> 'a formula_t + | Predicate: 'a predicate_t -> 'a formula_t + | StateVarPack of register_t + | ExistsMem of 'a formula_t * 'a formula_t (* type 'a simulation_t = { * sname: node_desc; @@ -35,9 +51,16 @@ type 'a formula_t = * sformula: 'a formula_t; * } *) +type 'a memory_pack_t = { + mpname: node_desc; + mpindex: int option; + mpformula: 'a formula_t; +} + type 'a transition_t = { tname: node_desc; tindex: int option; + tinputs: var_decl list; tlocals: var_decl list; toutputs: var_decl list; tformula: 'a formula_t; diff --git a/src/utils/utils.ml b/src/utils/utils.ml index a298bd36..df6e0bb8 100644 --- a/src/utils/utils.ml +++ b/src/utils/utils.ml @@ -284,6 +284,8 @@ module Format = struct let pp_print_opar fmt () = pp_print_string fmt "(" let pp_print_cpar fmt () = pp_print_string fmt ")" + let pp_print_obracket fmt () = pp_print_string fmt "[" + let pp_print_cbracket fmt () = pp_print_string fmt "]" let pp_print_obrace fmt () = pp_print_string fmt "{" let pp_print_cbrace fmt () = pp_print_string fmt "}" let pp_print_opar' fmt () = pp_print_string fmt "( " @@ -315,6 +317,8 @@ module Format = struct pp_cl () (fun fmt l -> if l <> [] then pp_epilogue fmt ()) l + let pp_comma_list = pp_print_list ~pp_sep:pp_print_comma + let pp_print_list_i ?pp_prologue ?pp_epilogue ?pp_op ?pp_cl ?pp_open_box ?pp_eol ?pp_sep pp_v = @@ -343,6 +347,12 @@ module Format = struct ~pp_cl:pp_print_cpar ~pp_sep + let pp_print_bracketed ?(pp_sep=pp_print_comma) = + pp_print_list + ~pp_op:pp_print_obracket + ~pp_cl:pp_print_cbracket + ~pp_sep + let pp_print_braced ?(pp_sep=pp_print_comma) = pp_print_list ~pp_op:pp_print_obrace -- GitLab