diff --git a/Makefile.in b/Makefile.in index 749e3bb066bfd0e4d2a18971ff50c1f1266c9d7a..48e6f31eef411fbc5fd075fa0757f40441c51e2e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -7,12 +7,13 @@ datadir = ${prefix}/share includedir = ${prefix}/include LUSI_LIBS=include/math.lusi include/conv.lusi +LUSI_MPFR_LIB=include/mpfr_lustre.lusi LOCAL_BINDIR=bin LOCAL_DOCDIR=doc/manual lustrec: @echo Compiling binary lustrec - @$(OCAMLBUILD) -cflags -I,@OCAMLGRAPH_PATH@ -lflag @OCAMLGRAPH_PATH@/graph.cmxa -I src -I src/backends/C src/main_lustre_compiler.native + @$(OCAMLBUILD) -cflags -I,@OCAMLGRAPH_PATH@ -lflag @OCAMLGRAPH_PATH@/graph.cmxa -lflag nums.cmxa -I src -I src/backends/C -I src/plugins/scopes src/main_lustre_compiler.native @mkdir -p $(LOCAL_BINDIR) @mv _build/src/main_lustre_compiler.native $(LOCAL_BINDIR)/lustrec @@ -31,7 +32,7 @@ clean: $(OCAMLBUILD) -clean dist-clean: clean - @rm -f Makefile myocamlbuild.ml config.log config.status configure include/*.lusic include/math.h include/conv.h + @rm -f Makefile myocamlbuild.ml config.log config.status configure include/*.lusic include/math.h include/conv.h include/mpfr_lustre.h %.lusic: %.lusi @echo Compiling $< @@ -39,10 +40,15 @@ dist-clean: clean clean-lusic: @rm -f $(LUSI_LIBS:%.lusi=%.lusic) + @rm -f $(LUSI_MPFR_LIB:%.lusi=%.lusic) compile-lusi: $(LUSI_LIBS:%.lusi=%.lusic) -install: clean-lusic compile-lusi +compile-mpfr-lusi: $(LUSI_MPFR_LIB) + @echo Compiling $< + @$(LOCAL_BINDIR)/lustrec -verbose 0 -mpfr 1 -d include $< + +install: clean-lusic compile-lusi compile-mpfr-lusi mkdir -p ${bindir} install -m 0755 $(LOCAL_BINDIR)/* ${bindir} mkdir -p ${includedir}/lustrec diff --git a/configure.ac b/configure.ac index 8ef82bad7b6abc4cdbc9a9bed7339b7ddd094765..54a3a158961ead40216e52a7f01f918692c791c5 100644 --- a/configure.ac +++ b/configure.ac @@ -1,9 +1,9 @@ -define([svnversion], esyscmd([sh -c "svnversion|sed "s/:.*//"|tr -d '\n'"]))dnl -AC_INIT([lustrec], [1.1-svnversion], [ploc@garoche.net]) +define([gitversion], esyscmd([sh -c "git log --oneline | wc -l | tr -d '\n'"])) +AC_INIT([lustrec], [1.1-gitversion], [ploc@garoche.net]) -AC_DEFINE(SVN_REVISION, "svnversion", [SVN Revision]) -AC_SUBST(SVN_REVISION) +#AC_DEFINE(SVN_REVISION, "svnversion", [SVN Revision]) +#AC_SUBST(SVN_REVISION) AC_CONFIG_SRCDIR([src/main_lustre_compiler.ml]) @@ -23,14 +23,15 @@ AC_ARG_WITH([ocamlgraph-path], ) AC_SUBST(OCAMLGRAPH_PATH) +AC_SUBST(SRC_PATH, esyscmd([sh -c "pwd" | tr -d '\n'])) AC_PATH_PROG([OCAMLC],[ocamlc],[:]) AC_MSG_CHECKING(OCaml version) ocamlc_version=`$OCAMLC -v | grep version | rev| cut -d \ -f 1 | rev` major=`echo $ocamlc_version | cut -d . -f 1` minor=`echo $ocamlc_version | cut -d . -f 2` -if (test "$major" -lt 3 -a "$minor" -lt 11 ); then - AC_MSG_ERROR([Ocaml version must be at least 3.11. You have version $ocamlc_version]) +if (test "$major" -lt 4 -a "$minor" -lt 0 ); then + AC_MSG_ERROR([Ocaml version must be at least 4.0. You have version $ocamlc_version]) fi AC_MSG_RESULT(valid ocaml version detected: $ocamlc_version) @@ -41,14 +42,24 @@ AC_PATH_PROG([OCAMLBUILD],[ocamlbuild],[:]) # Checks for libraries. OCamlgraph AC_MSG_CHECKING(ocamlgraph library) - ocamlgraph_lib=`find $OCAMLGRAPH_PATH -iname graph.cmxa | grep -m 1 -o "graph.cmxa"` + ocamlgraph_lib=`find $OCAMLGRAPH_PATH -iname graph.cmxa -nowarn | grep -m 1 -o "graph.cmxa"` if (test "x$ocamlgraph_lib" = xgraph.cmxa ); then - ocamlgraph_lib_full=`find $OCAMLGRAPH_PATH -iname graph.cmxa | grep -m 1 "graph.cmxa"` + ocamlgraph_lib_full=`find $OCAMLGRAPH_PATH -iname graph.cmxa -nowarn | grep -m 1 "graph.cmxa"` AC_MSG_RESULT(library detected: $ocamlgraph_lib_full ) else AC_MSG_ERROR([ocamlgraph library not installed in $OCAMLGRAPH_PATH]) fi +AC_CHECK_LIB(gmp, __gmpz_init, + [gmp=yes], + [AC_MSG_RESULT([GNU MP not found]) + gmp=no]) + +AC_CHECK_LIB(mpfr, mpfr_add, [mpfr=yes], + [AC_MSG_RESULT( +[MPFR not found]) +mpfr=no]) + # Workaround to solve an issue with ocamlbuild and C libraries. # oCFLAGS="$CFLAGS" @@ -87,10 +98,27 @@ AC_DEFINE_DIR([abs_datadir], [datadir]) AC_CONFIG_FILES([Makefile src/Makefile src/myocamlbuild.ml - src/version.ml]) + src/version.ml + test/test-compile.sh + ]) AC_OUTPUT # summary -dnl AC_MSG_NOTICE(******** Configuration ********) +AC_MSG_NOTICE(******** Configuration ********) +AC_MSG_NOTICE(bin path: $prefix/bin) +AC_MSG_NOTICE(include path: $prefix/include) +AC_MSG_NOTICE(******** Plugins ********) + + if (test "x$gmp" = xyes -a "x$mpfr" = xyes ); then + AC_MSG_NOTICE([-mpfr option enable]) + + else + AC_MSG_WARN([MPFR option cannot be activated. Requires GMP and MPFR libs]) + + fi + +AC_MSG_NOTICE +AC_MSG_NOTICE(******** Configuration ********) + diff --git a/include/arrow.h b/include/arrow.h index 509ddc9684b0e68c0b17f0ac064cea00f93458f4..1c6284d2f031f4470d358abe8084be9a142058c3 100644 --- a/include/arrow.h +++ b/include/arrow.h @@ -17,6 +17,10 @@ extern struct _arrow_mem *_arrow_alloc (); _arrow_DECLARE(attr, inst);\ _arrow_LINK(inst) +#define _arrow_init(self) {} + +#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;} diff --git a/lustrec.odocl b/lustrec.odocl index 81f5ff3a428a7560cfe46bf95456ba6802d35353..84bd32c96b6a6f52411949fb78657b8a8ca5c962 100644 --- a/lustrec.odocl +++ b/lustrec.odocl @@ -8,6 +8,7 @@ backends/C/C_backend_makefile backends/C/C_backend_spec backends/C/C_backend_src backends/Horn/Horn_backend +plugins/scopes/Scopes Basic_library Causality Clock_calculus diff --git a/src/Makefile.in b/src/Makefile.in index 9d7e902c678cdbd3fa7b89515f2724eeffa2bd5a..126a31f7253c95cb62dd436db79d0ecb71822650 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -1,4 +1,4 @@ -OCAMLBUILD=@OCAMLBUILD@ -classic-display -no-links +OCAMLBUILD=@OCAMLBUILD@ -classic-display -use-ocamlfind -no-links prefix=@prefix@ exec_prefix=@exec_prefix@ diff --git a/src/backends/C/c_backend.ml b/src/backends/C/c_backend.ml index a6d1d711bb632c67e58a10406033b45cc095cb2a..59666b9cbdc7dee1995a6267a4eac7c91013d815 100644 --- a/src/backends/C/c_backend.ml +++ b/src/backends/C/c_backend.ml @@ -38,15 +38,19 @@ let gen_files funs basename prog machines dependencies header_file source_lib_fi (* Generating Lib C file *) print_lib_c source_lib_fmt basename prog machines dependencies; - + close_out header_out; close_out source_lib_out; match !Options.main_node with - | "" -> () (* No main node: we do not genenrate main nor makefile *) + | "" -> () (* No main node: we do not generate main nor makefile *) | main_node -> ( match Machine_code.get_machine_opt main_node machines with - | None -> Format.eprintf "Unable to find a main node named %s@.@?" main_node; assert false + | None -> begin + Global.main_node := main_node; + Format.eprintf "Code generation error: %a@." Corelang.pp_error LustreSpec.Main_not_found; + raise (Corelang.Error (Location.dummy_loc, LustreSpec.Main_not_found)) + end | Some m -> begin let source_main_out = open_out source_main_file in let source_main_fmt = formatter_of_out_channel source_main_out in @@ -57,7 +61,7 @@ let gen_files funs basename prog machines dependencies header_file source_lib_fi print_main_c source_main_fmt m basename prog machines dependencies; (* Generating Makefile *) - print_makefile basename main_node dependencies makefile_fmt; + print_makefile basename main_node dependencies makefile_fmt; close_out source_main_out; close_out makefile_out diff --git a/src/backends/C/c_backend_common.ml b/src/backends/C/c_backend_common.ml index d7674274bb1d1593a3aaa9dafbd4c0ceea1794e3..32651e4f590fbc33b39df36398851aff39c2948f 100644 --- a/src/backends/C/c_backend_common.ml +++ b/src/backends/C/c_backend_common.ml @@ -17,11 +17,17 @@ open Machine_code let print_version fmt = Format.fprintf fmt - "/* @[<v>C code generated by %s@,SVN version number %s@,Code is %s compliant */@,@]@." + "/* @[<v>C code generated by %s@,Version number %s@,Code is %s compliant@,Using %s numbers */@,@]@." (Filename.basename Sys.executable_name) Version.number (if !Options.ansi then "ANSI C90" else "C99") - + (if !Options.mpfr then "MPFR multi-precision" else "(double) floating-point") + +let file_to_module_name basename = + let baseNAME = String.uppercase basename in + let baseNAME = Str.global_replace (Str.regexp "\\.\\|\\ ") "_" baseNAME in + baseNAME + (* Generation of a non-clashing name for the self memory variable (for step and reset functions) *) let mk_self m = let used name = @@ -83,6 +89,8 @@ let mk_addr_var m var = if List.exists (fun v -> v.var_id = s) vars then aux () else s in aux () *) +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 fmt id = fprintf fmt "struct %s_mem" id 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 @@ -90,6 +98,8 @@ 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_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 let rec pp_c_dimension fmt dim = @@ -116,16 +126,17 @@ let is_basic_c_type t = let pp_basic_c_type fmt t = match (Types.repr t).Types.tdesc with - | Types.Tbool -> fprintf fmt "_Bool" - | Types.Treal -> fprintf fmt "double" - | Types.Tint -> fprintf fmt "int" + | Types.Tbool -> fprintf fmt "_Bool" + | Types.Treal when !Options.mpfr -> fprintf fmt "%s" Mpfr.mpfr_t + | Types.Treal -> fprintf fmt "double" + | Types.Tint -> fprintf fmt "int" | _ -> assert false (* Not a basic C type. Do not handle arrays or pointers *) let pp_c_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 | Types.Treal | Types.Tint + | Types.Tbool | Types.Tint | Types.Treal -> fprintf fmt "%a %s%a" pp_basic_c_type t var pp_suffix () | Types.Tarray (d, t') -> let pp_suffix' fmt () = fprintf fmt "%a[%a]" pp_suffix () pp_c_dimension d in @@ -135,30 +146,28 @@ let pp_c_type var fmt t = | Types.Tarrow (_, _) -> fprintf fmt "void (*%s)()" var | _ -> eprintf "internal error: C_backend_common.pp_c_type %a@." Types.print_ty t; assert false in aux t (fun fmt () -> ()) - +(* let rec pp_c_initialize fmt t = match (Types.repr t).Types.tdesc with | Types.Tint -> pp_print_string fmt "0" | Types.Tclock t' -> pp_c_initialize fmt t' | Types.Tbool -> pp_print_string fmt "0" - | Types.Treal -> pp_print_string fmt "0." + | Types.Treal when not !Options.mpfr -> pp_print_string fmt "0." | Types.Tarray (d, t') when Dimension.is_dimension_const d -> fprintf fmt "{%a}" (Utils.fprintf_list ~sep:"," (fun fmt _ -> pp_c_initialize fmt t')) (Utils.duplicate 0 (Dimension.size_const_dimension d)) | _ -> assert false - - + *) let pp_c_tag fmt t = pp_print_string fmt (if t = tag_true then "1" else if t = tag_false then "0" else t) - (* Prints a constant value *) let rec pp_c_const fmt c = match c with | Const_int i -> pp_print_int fmt i - | Const_real r -> pp_print_string fmt r - | Const_float r -> pp_print_float fmt r + | Const_real (c,e,s)-> pp_print_string fmt s (* Format.fprintf fmt "%ie%i" c e*) + (* | Const_float r -> pp_print_float fmt r *) | Const_tag t -> pp_c_tag fmt t | Const_array ca -> fprintf fmt "{%a }" (Utils.fprintf_list ~sep:", " pp_c_const) ca | Const_struct fl -> fprintf fmt "{%a }" (Utils.fprintf_list ~sep:", " (fun fmt (f, c) -> pp_c_const fmt c)) fl @@ -169,17 +178,16 @@ let rec pp_c_const fmt c = but an offset suffix may be added for array variables *) let rec pp_c_val self pp_var fmt v = - (*Format.eprintf "C_backend_common.pp_c_val %a@." pp_val v;*) - match v with + match v.value_desc with | Cst c -> pp_c_const fmt c | Array vl -> fprintf fmt "{%a}" (Utils.fprintf_list ~sep:", " (pp_c_val self pp_var)) vl | Access (t, i) -> fprintf fmt "%a[%a]" (pp_c_val self pp_var) t (pp_c_val self pp_var) i - | Power (v, n) -> (Format.eprintf "internal error: C_backend_common.pp_c_val %a@." pp_val v; assert false) + | Power (v, n) -> assert false | LocalVar v -> pp_var fmt v | StateVar v -> (* array memory vars are represented by an indirection to a local var with the right type, in order to avoid casting everywhere. *) - if Types.is_array_type v.var_type + if Types.is_array_type v.var_type && not (Types.is_real_type v.var_type && !Options.mpfr) then fprintf fmt "%a" pp_var v else fprintf fmt "%s->_reg.%a" self pp_var v | Fun (n, vl) -> Basic_library.pp_c n (pp_c_val self pp_var) fmt vl @@ -191,9 +199,10 @@ let rec pp_c_val self pp_var fmt v = - moreover, dereference memory array variables. *) let pp_c_var_read m fmt id = + (* mpfr_t is a static array, not treated as general arrays *) if Types.is_address_type id.var_type then - if is_memory m id + if is_memory m id && not (Types.is_real_type id.var_type && !Options.mpfr) then fprintf fmt "(*%s)" id.var_id else fprintf fmt "%s" id.var_id else @@ -289,9 +298,9 @@ let pp_c_checks self fmt m = let pp_registers_struct fmt m = if m.mmemory <> [] then - fprintf fmt "@[%a {@[%a; @]}@] _reg; " + fprintf fmt "@[%a {@[<v>%a;@ @]}@] _reg; " pp_machine_regtype_name m.mname.node_id - (Utils.fprintf_list ~sep:"; " pp_c_decl_struct_var) m.mmemory + (Utils.fprintf_list ~sep:";@ " pp_c_decl_struct_var) m.mmemory else () @@ -302,11 +311,12 @@ let print_machine_struct fmt m = else begin (* Define struct *) - fprintf fmt "@[%a {@[%a%a%t@]};@]@." + fprintf fmt "@[%a {@[<v>%a%t%a%t@]};@]@." pp_machine_memtype_name m.mname.node_id pp_registers_struct m - (Utils.fprintf_list ~sep:"; " pp_c_decl_instance_var) m.minstances - (Utils.pp_final_char_if_non_empty "; " m.minstances) + (Utils.pp_final_char_if_non_empty "@ " m.mmemory) + (Utils.fprintf_list ~sep:";@ " pp_c_decl_instance_var) m.minstances + (Utils.pp_final_char_if_non_empty ";@ " m.minstances) end let print_machine_struct_from_header fmt inode = @@ -324,6 +334,14 @@ let print_machine_struct_from_header fmt inode = (* Prototype Printing functions *) (********************************************************************************************) +let print_global_init_prototype fmt baseNAME = + fprintf fmt "void %a ()" + pp_global_init_name baseNAME + +let print_global_clear_prototype fmt baseNAME = + fprintf fmt "void %a ()" + pp_global_clear_name baseNAME + let print_alloc_prototype fmt (name, static) = fprintf fmt "%a * %a (%a)" pp_machine_memtype_name name @@ -338,6 +356,22 @@ let print_reset_prototype self fmt (name, static) = pp_machine_memtype_name name self +let print_init_prototype self fmt (name, static) = + fprintf fmt "void %a (@[<v>%a%t%a *%s@])" + pp_machine_init_name name + (Utils.fprintf_list ~sep:",@ " pp_c_decl_input_var) static + (Utils.pp_final_char_if_non_empty ",@," static) + pp_machine_memtype_name name + self + +let print_clear_prototype self fmt (name, static) = + fprintf fmt "void %a (@[<v>%a%t%a *%s@])" + pp_machine_clear_name name + (Utils.fprintf_list ~sep:",@ " pp_c_decl_input_var) static + (Utils.pp_final_char_if_non_empty ",@," static) + pp_machine_memtype_name name + self + let print_stateless_prototype fmt (name, inputs, outputs) = fprintf fmt "void %a (@[<v>@[%a%t@]@,@[%a@]@,@])" pp_machine_step_name name @@ -366,7 +400,17 @@ let print_stateless_C_prototype fmt (name, inputs, outputs) = name (Utils.fprintf_list ~sep:",@ " pp_c_decl_input_var) inputs - +let print_import_init fmt (Dep (local, basename, _, _)) = + if local then + let baseNAME = file_to_module_name basename in + fprintf fmt "%a();" pp_global_init_name baseNAME + else () + +let print_import_clear fmt (Dep (local, basename, _, _)) = + if local then + let baseNAME = file_to_module_name basename in + fprintf fmt "%a();" pp_global_clear_name baseNAME + else () let print_import_prototype fmt (Dep (_, s, _, _)) = fprintf fmt "#include \"%s.h\"@," s @@ -383,6 +427,214 @@ let print_extern_alloc_prototypes fmt (Dep (_,_, header,_)) = | _ -> () ) header + +let pp_c_main_var_input fmt id = + fprintf fmt "%s" id.var_id + +let pp_c_main_var_output fmt id = + if Types.is_address_type id.var_type + then + fprintf fmt "%s" id.var_id + else + fprintf fmt "&%s" id.var_id + +let pp_main_call mname self fmt m (inputs: value_t list) (outputs: var_decl list) = + if fst (get_stateless_status m) + then + fprintf fmt "%a (%a%t%a);" + pp_machine_step_name mname + (Utils.fprintf_list ~sep:", " (pp_c_val self pp_c_main_var_input)) inputs + (Utils.pp_final_char_if_non_empty ", " inputs) + (Utils.fprintf_list ~sep:", " pp_c_main_var_output) outputs + else + fprintf fmt "%a (%a%t%a%t%s);" + pp_machine_step_name mname + (Utils.fprintf_list ~sep:", " (pp_c_val self pp_c_main_var_input)) inputs + (Utils.pp_final_char_if_non_empty ", " inputs) + (Utils.fprintf_list ~sep:", " pp_c_main_var_output) outputs + (Utils.pp_final_char_if_non_empty ", " outputs) + self + +let pp_c_var m self pp_var fmt var = + if is_memory m var + then + pp_c_val self pp_var fmt (mk_val (StateVar var) var.var_type) + else + pp_c_val self pp_var fmt (mk_val (LocalVar var) var.var_type) + +let pp_array_suffix fmt loop_vars = + Utils.fprintf_list ~sep:"" (fun fmt v -> fprintf fmt "[%s]" v) fmt loop_vars + +(* type directed initialization: useless wrt the lustre compilation model, + except for MPFR injection, where values are dynamically allocated +*) +let pp_initialize m self pp_var fmt var = + let rec aux indices fmt typ = + if Types.is_array_type typ + then + let dim = Types.array_type_dimension typ in + let idx = mk_loop_var m () in + fprintf fmt "@[<v 2>{@,int %s;@,for(%s=0;%s<%a;%s++)@,%a @]@,}" + idx idx idx pp_c_dimension dim idx + (aux (idx::indices)) (Types.array_element_type typ) + else + let indices = List.rev indices in + let pp_var_suffix fmt var = + fprintf fmt "%a%a" (pp_c_var m self pp_var) var pp_array_suffix indices in + Mpfr.pp_inject_init pp_var_suffix fmt var + in + if !Options.mpfr && Types.is_real_type (Types.array_base_type var.var_type) + then + begin + reset_loop_counter (); + aux [] fmt var.var_type + end + +let pp_const_initialize pp_var fmt const = + let m = Machine_code.empty_machine in + let var = mk_val (LocalVar (Corelang.var_decl_of_const const)) const.const_type in + let rec aux indices value fmt typ = + if Types.is_array_type typ + then + let dim = Types.array_type_dimension typ in + let szl = Utils.enumerate (Dimension.size_const_dimension dim) in + let typ' = Types.array_element_type typ in + let value = match value with + | Const_array ca -> List.nth ca + | _ -> assert false in + fprintf fmt "%a" + (Utils.fprintf_list ~sep:"@," (fun fmt i -> aux (string_of_int i::indices) (value i) fmt typ')) szl + else + let indices = List.rev indices in + let pp_var_suffix fmt var = + fprintf fmt "%a%a" (pp_c_val "" pp_var) var pp_array_suffix indices in + let pp_value fmt value = pp_c_val "" pp_var fmt value in + begin + Mpfr.pp_inject_init pp_var_suffix fmt var; + fprintf fmt "@,"; + Mpfr.pp_inject_real pp_var_suffix pp_c_const fmt var value + end + in + if !Options.mpfr && Types.is_real_type (Types.array_base_type const.const_type) + then + begin + reset_loop_counter (); + aux [] const.const_value fmt const.const_type + end + +(* type directed clear: useless wrt the lustre compilation model, + except for MPFR injection, where values are dynamically allocated +*) +let pp_clear m self pp_var fmt var = + let rec aux indices fmt typ = + if Types.is_array_type typ + then + let dim = Types.array_type_dimension typ in + let idx = mk_loop_var m () in + fprintf fmt "@[<v 2>{@,int %s;@,for(%s=0;%s<%a;%s++)@,%a @]@,}" + idx idx idx pp_c_dimension dim idx + (aux (idx::indices)) (Types.array_element_type typ) + else + let indices = List.rev indices in + let pp_var_suffix fmt var = + fprintf fmt "%a%a" (pp_c_var m self pp_var) var pp_array_suffix indices in + Mpfr.pp_inject_clear pp_var_suffix fmt var + in + if !Options.mpfr && Types.is_real_type (Types.array_base_type var.var_type) + then + begin + reset_loop_counter (); + aux [] fmt var.var_type + end + +let pp_const_clear pp_var fmt const = + let m = Machine_code.empty_machine in + let var = Corelang.var_decl_of_const const in + let rec aux indices fmt typ = + if Types.is_array_type typ + then + let dim = Types.array_type_dimension typ in + let idx = mk_loop_var m () in + fprintf fmt "@[<v 2>{@,int %s;@,for(%s=0;%s<%a;%s++)@,%a @]@,}" + idx idx idx pp_c_dimension dim idx + (aux (idx::indices)) (Types.array_element_type typ) + else + let indices = List.rev indices in + let pp_var_suffix fmt var = + fprintf fmt "%a%a" (pp_c_var m "" pp_var) var pp_array_suffix indices in + Mpfr.pp_inject_clear pp_var_suffix fmt var + in + if !Options.mpfr && Types.is_real_type (Types.array_base_type var.var_type) + then + begin + reset_loop_counter (); + aux [] fmt var.var_type + end + +let pp_call m self pp_read pp_write fmt i (inputs: value_t list) (outputs: var_decl list) = + try (* stateful node instance *) + let (n,_) = List.assoc i m.minstances in + fprintf fmt "%a (%a%t%a%t%s->%s);" + pp_machine_step_name (node_name n) + (Utils.fprintf_list ~sep:", " (pp_c_val self pp_read)) inputs + (Utils.pp_final_char_if_non_empty ", " inputs) + (Utils.fprintf_list ~sep:", " pp_write) outputs + (Utils.pp_final_char_if_non_empty ", " outputs) + self + i + with Not_found -> (* stateless node instance *) + let (n,_) = List.assoc i m.mcalls in + fprintf fmt "%a (%a%t%a);" + pp_machine_step_name (node_name n) + (Utils.fprintf_list ~sep:", " (pp_c_val self pp_read)) inputs + (Utils.pp_final_char_if_non_empty ", " inputs) + (Utils.fprintf_list ~sep:", " pp_write) outputs + +let pp_basic_instance_call m self fmt i (inputs: value_t list) (outputs: var_decl list) = + pp_call m self (pp_c_var_read m) (pp_c_var_write m) fmt i inputs outputs +(* + try (* stateful node instance *) + let (n,_) = List.assoc i m.minstances in + fprintf fmt "%a (%a%t%a%t%s->%s);" + pp_machine_step_name (node_name n) + (Utils.fprintf_list ~sep:", " (pp_c_val self (pp_c_var_read m))) inputs + (Utils.pp_final_char_if_non_empty ", " inputs) + (Utils.fprintf_list ~sep:", " (pp_c_var_write m)) outputs + (Utils.pp_final_char_if_non_empty ", " outputs) + self + i + with Not_found -> (* stateless node instance *) + let (n,_) = List.assoc i m.mcalls in + fprintf fmt "%a (%a%t%a);" + pp_machine_step_name (node_name n) + (Utils.fprintf_list ~sep:", " (pp_c_val self (pp_c_var_read m))) inputs + (Utils.pp_final_char_if_non_empty ", " inputs) + (Utils.fprintf_list ~sep:", " (pp_c_var_write m)) outputs +*) + +let pp_instance_call m self fmt i (inputs: value_t list) (outputs: var_decl list) = + let pp_offset pp_var indices fmt var = + match indices with + | [] -> fprintf fmt "%a" pp_var var + | _ -> fprintf fmt "%a[%a]" pp_var var (Utils.fprintf_list ~sep:"][" pp_print_string) indices in + let rec aux indices fmt typ = + if Types.is_array_type typ + then + let dim = Types.array_type_dimension typ in + let idx = mk_loop_var m () in + fprintf fmt "@[<v 2>{@,int %s;@,for(%s=0;%s<%a;%s++)@,%a @]@,}" + idx idx idx pp_c_dimension dim idx + (aux (idx::indices)) (Types.array_element_type typ) + else + let pp_read = pp_offset (pp_c_var_read m) indices in + let pp_write = pp_offset (pp_c_var_write m) indices in + pp_call m self pp_read pp_write fmt i inputs outputs + in + begin + reset_loop_counter (); + aux [] fmt (List.hd inputs).value_type + end + (* Local Variables: *) (* compile-command:"make -C ../../.." *) (* End: *) diff --git a/src/backends/C/c_backend_header.ml b/src/backends/C/c_backend_header.ml index ffe9575590e2e3f067856b31326073a5f09dcad7..272a3fb4df055f5a6401e3bd618cf6d0b391e769 100644 --- a/src/backends/C/c_backend_header.ml +++ b/src/backends/C/c_backend_header.ml @@ -34,10 +34,16 @@ module Main = functor (Mod: MODIFIERS_HDR) -> struct let print_import_standard fmt = - fprintf fmt "#include \"%s/arrow.h\"@.@." Version.include_path + begin + if !Options.mpfr then + begin + fprintf fmt "#include <mpfr.h>@." + end; + fprintf fmt "#include \"%s/arrow.h\"@.@." Version.include_path + end let rec print_static_val pp_var fmt v = - match v with + match v.value_desc with | Cst c -> pp_c_const fmt c | LocalVar v -> pp_var fmt v | Fun (n, vl) -> Basic_library.pp_c n (print_static_val pp_var) fmt vl @@ -145,40 +151,51 @@ let print_static_alloc_macro fmt (m, attr, inst) = inst let print_machine_decl fmt m = - Mod.print_machine_decl_prefix fmt m; - if fst (get_stateless_status m) then - begin - fprintf fmt "extern %a;@.@." - print_stateless_prototype - (m.mname.node_id, m.mstep.step_inputs, m.mstep.step_outputs) - end - else - begin - (* Static allocation *) - if !Options.static_mem - then - begin - let inst = mk_instance m in - let attr = mk_attribute m in - fprintf fmt "%a@.%a@.%a@." - print_static_declare_macro (m, attr, inst) - print_static_link_macro (m, attr, inst) - print_static_alloc_macro (m, attr, inst) - end - else - begin - (* Dynamic allocation *) - fprintf fmt "extern %a;@.@." - print_alloc_prototype (m.mname.node_id, m.mstatic) - end; - let self = mk_self m in - fprintf fmt "extern %a;@.@." - (print_reset_prototype self) (m.mname.node_id, m.mstatic); + begin + Mod.print_machine_decl_prefix fmt m; + if fst (get_stateless_status m) then + begin + fprintf fmt "extern %a;@.@." + print_stateless_prototype + (m.mname.node_id, m.mstep.step_inputs, m.mstep.step_outputs) + end + else + begin + (* Static allocation *) + if !Options.static_mem + then + begin + let inst = mk_instance m in + let attr = mk_attribute m in + fprintf fmt "%a@.%a@.%a@." + print_static_declare_macro (m, attr, inst) + print_static_link_macro (m, attr, inst) + print_static_alloc_macro (m, attr, inst) + end + else + begin + (* Dynamic allocation *) + fprintf fmt "extern %a;@.@." + print_alloc_prototype (m.mname.node_id, m.mstatic) + end; + let self = mk_self m in + fprintf fmt "extern %a;@.@." + (print_reset_prototype self) (m.mname.node_id, m.mstatic); - fprintf fmt "extern %a;@.@." - (print_step_prototype self) - (m.mname.node_id, m.mstep.step_inputs, m.mstep.step_outputs) - end + fprintf fmt "extern %a;@.@." + (print_step_prototype self) + (m.mname.node_id, m.mstep.step_inputs, m.mstep.step_outputs); + + if !Options.mpfr then + begin + fprintf fmt "extern %a;@.@." + (print_init_prototype self) (m.mname.node_id, m.mstatic); + + fprintf fmt "extern %a;@.@." + (print_clear_prototype self) (m.mname.node_id, m.mstatic); + end + end + end let print_machine_alloc_decl fmt m = Mod.print_machine_decl_prefix fmt m; @@ -215,8 +232,7 @@ let print_machine_decl_from_header fmt inode = print_stateless_C_prototype (inode.nodei_id, inode.nodei_inputs, inode.nodei_outputs) end - else ( - raise (Invalid_argument ("A node with declared prototype C cannot be stateful, it has to be a function"))) + else (Format.eprintf "internal error: print_machine_decl_from_header"; assert false) else if inode.nodei_stateless then begin @@ -233,15 +249,26 @@ let print_machine_decl_from_header fmt inode = let self = mk_new_name used "self" in fprintf fmt "extern %a;@.@." (print_reset_prototype self) (inode.nodei_id, static_inputs); - + + fprintf fmt "extern %a;@.@." + (print_init_prototype self) (inode.nodei_id, static_inputs); + + fprintf fmt "extern %a;@.@." + (print_clear_prototype self) (inode.nodei_id, static_inputs); + fprintf fmt "extern %a;@.@." (print_step_prototype self) (inode.nodei_id, inode.nodei_inputs, inode.nodei_outputs) end let print_const_decl fmt cdecl = - fprintf fmt "extern %a;@." - (pp_c_type cdecl.const_id) cdecl.const_type + if !Options.mpfr && Types.is_real_type (Types.array_base_type cdecl.const_type) + then + fprintf fmt "extern %a;@." + (pp_c_type cdecl.const_id) (Types.dynamic_type cdecl.const_type) + else + fprintf fmt "extern %a;@." + (pp_c_type cdecl.const_id) cdecl.const_type let rec pp_c_struct_type_field filename cpt fmt (label, tdesc) = fprintf fmt "%a;" (pp_c_type_decl filename cpt label) tdesc @@ -249,8 +276,10 @@ and pp_c_type_decl filename cpt var fmt tdecl = match tdecl with | Tydec_any -> assert false | Tydec_int -> fprintf fmt "int %s" var + | Tydec_real when !Options.mpfr + -> fprintf fmt "%s %s" Mpfr.mpfr_t var | Tydec_real -> fprintf fmt "double %s" var - | Tydec_float -> fprintf fmt "float %s" var + (* | Tydec_float -> fprintf fmt "float %s" var *) | Tydec_bool -> fprintf fmt "_Bool %s" var | Tydec_clock ty -> pp_c_type_decl filename cpt var fmt ty | Tydec_const c -> fprintf fmt "%s %s" c var @@ -290,10 +319,9 @@ let reset_type_definitions, print_type_definition_from_header = (********************************************************************************************) let print_header header_fmt basename prog machines dependencies = (* Include once: start *) - let baseNAME = String.uppercase basename in - let baseNAME = Str.global_replace (Str.regexp "\\.\\|\\ ") "_" baseNAME in + let baseNAME = file_to_module_name basename in begin - (* Print the svn version number and the supported C standard (C90 or C99) *) + (* Print the version number and the supported C standard (C90 or C99) *) print_version header_fmt; fprintf header_fmt "#ifndef _%s@.#define _%s@." baseNAME baseNAME; pp_print_newline header_fmt (); @@ -302,7 +330,7 @@ let print_header header_fmt basename prog machines dependencies = print_import_standard header_fmt; pp_print_newline header_fmt (); (* imports dependencies *) - fprintf header_fmt "/* Import Dependencies */@."; + fprintf header_fmt "/* Import dependencies */@."; fprintf header_fmt "@[<v>"; List.iter (print_import_prototype header_fmt) dependencies; fprintf header_fmt "@]@."; @@ -314,8 +342,18 @@ let print_header header_fmt basename prog machines dependencies = fprintf header_fmt "/* Global constant (declarations, definitions are in C file) */@."; List.iter (fun c -> print_const_decl header_fmt (const_of_top c)) (get_consts prog); pp_print_newline header_fmt (); + if !Options.mpfr then + begin + fprintf header_fmt "/* Global initialization declaration */@."; + fprintf header_fmt "extern %a;@.@." + print_global_init_prototype baseNAME; + + fprintf header_fmt "/* Global clear declaration */@."; + fprintf header_fmt "extern %a;@.@." + print_global_clear_prototype baseNAME; + end; (* Print the struct declarations of all machines. *) - fprintf header_fmt "/* Struct declarations */@."; + fprintf header_fmt "/* Structs declarations */@."; List.iter (print_machine_struct header_fmt) machines; pp_print_newline header_fmt (); (* Print the prototypes of all machines *) @@ -329,8 +367,7 @@ let print_header header_fmt basename prog machines dependencies = let print_alloc_header header_fmt basename prog machines dependencies = (* Include once: start *) - let baseNAME = String.uppercase basename in - let baseNAME = Str.global_replace (Str.regexp "\\.\\|\\ ") "_" baseNAME in + let baseNAME = file_to_module_name basename in begin (* Print the svn version number and the supported C standard (C90 or C99) *) print_version header_fmt; @@ -362,14 +399,13 @@ let print_alloc_header header_fmt basename prog machines dependencies = header. *) let print_header_from_header header_fmt basename header = (* Include once: start *) - let baseNAME = String.uppercase basename in - let baseNAME = Str.global_replace (Str.regexp "\\.\\|\\ ") "_" baseNAME in + let baseNAME = file_to_module_name basename in let types = get_typedefs header in let consts = get_consts header in let nodes = get_imported_nodes header in let dependencies = get_dependencies header in begin - (* Print the svn version number and the supported C standard (C90 or C99) *) + (* Print the version number and the supported C standard (C90 or C99) *) print_version header_fmt; fprintf header_fmt "#ifndef _%s@.#define _%s@." baseNAME baseNAME; pp_print_newline header_fmt (); @@ -395,8 +431,18 @@ let print_header_from_header header_fmt basename header = fprintf header_fmt "/* Global constant (declarations, definitions are in C file) */@."; List.iter (fun c -> print_const_decl header_fmt (const_of_top c)) consts; pp_print_newline header_fmt (); + if !Options.mpfr then + begin + fprintf header_fmt "/* Global initialization declaration */@."; + fprintf header_fmt "extern %a;@.@." + print_global_init_prototype baseNAME; + + fprintf header_fmt "/* Global clear declaration */@."; + fprintf header_fmt "extern %a;@.@." + print_global_clear_prototype baseNAME; + end; (* Print the struct declarations of all machines. *) - fprintf header_fmt "/* Struct declarations */@."; + fprintf header_fmt "/* Structs declarations */@."; List.iter (fun node -> print_machine_struct_from_header header_fmt (imported_node_of_top node)) nodes; pp_print_newline header_fmt (); (* Print the prototypes of all machines *) diff --git a/src/backends/C/c_backend_main.ml b/src/backends/C/c_backend_main.ml index 578c6a3e4e936fba9bce0280c176566db3c4d7d5..4cfa48ea080a837d5ec5bd65294d5151a6c67d46 100644 --- a/src/backends/C/c_backend_main.ml +++ b/src/backends/C/c_backend_main.ml @@ -30,80 +30,140 @@ struct (* Main related functions *) (********************************************************************************************) -let print_get_input fmt v = - match (Types.repr v.var_type).Types.tdesc with - | Types.Tint -> fprintf fmt "_get_int(\"%s\")" v.var_id - | Types.Tbool -> fprintf fmt "_get_bool(\"%s\")" v.var_id - | Types.Treal -> fprintf fmt "_get_double(\"%s\")" v.var_id - | _ -> assert false +let print_get_inputs fmt m = + let pi fmt (v', v) = + match (Types.unclock_type v.var_type).Types.tdesc with + | Types.Tint -> fprintf fmt "%s = _get_int(\"%s\")" v.var_id v'.var_id + | Types.Tbool -> fprintf fmt "%s = _get_bool(\"%s\")" v.var_id v'.var_id + | Types.Treal when !Options.mpfr -> fprintf fmt "mpfr_set_d(%s, _get_double(\"%s\"), %i)" v.var_id v'.var_id (Mpfr.mpfr_prec ()) + | Types.Treal -> fprintf fmt "%s = _get_double(\"%s\")" v.var_id v'.var_id + | _ -> + begin + Global.main_node := !Options.main_node; + Format.eprintf "Code generation error: %a%a@." + pp_error Main_wrong_kind + Location.pp_loc v'.var_loc; + raise (Error (v'.var_loc, Main_wrong_kind)) + end + in + List.iter2 (fun v' v -> fprintf fmt "@ %a;" pi (v', v)) m.mname.node_inputs m.mstep.step_inputs -let print_put_outputs fmt ol = - let po fmt o = - match (Types.repr o.var_type).Types.tdesc with - | Types.Tint -> fprintf fmt "_put_int(\"%s\", %s)" o.var_id o.var_id - | Types.Tbool -> fprintf fmt "_put_bool(\"%s\", %s)" o.var_id o.var_id - | Types.Treal -> fprintf fmt "_put_double(\"%s\", %s)" o.var_id o.var_id +let print_put_outputs fmt m = + let po fmt (o', o) = + match (Types.unclock_type o.var_type).Types.tdesc with + | Types.Tint -> fprintf fmt "_put_int(\"%s\", %s)" o'.var_id o.var_id + | Types.Tbool -> fprintf fmt "_put_bool(\"%s\", %s)" o'.var_id o.var_id + | Types.Treal when !Options.mpfr -> fprintf fmt "_put_double(\"%s\", mpfr_get_d(%s, %s))" o'.var_id o.var_id (Mpfr.mpfr_rnd ()) + | Types.Treal -> fprintf fmt "_put_double(\"%s\", %s)" o'.var_id o.var_id | _ -> assert false in - List.iter (fprintf fmt "@ %a;" po) ol + List.iter2 (fun v' v -> fprintf fmt "@ %a;" po (v', v)) m.mname.node_outputs m.mstep.step_outputs + +let print_main_inout_declaration fmt m = + begin + fprintf fmt "/* Declaration of inputs/outputs variables */@ "; + List.iter + (fun v -> fprintf fmt "%a;@ " (pp_c_type v.var_id) v.var_type + ) m.mstep.step_inputs; + List.iter + (fun v -> fprintf fmt "%a;@ " (pp_c_type v.var_id) v.var_type + ) m.mstep.step_outputs + end + +let print_main_memory_allocation mname main_mem fmt m = + if not (fst (get_stateless_status m)) then + begin + fprintf fmt "@ /* Main memory allocation */@ "; + if (!Options.static_mem && !Options.main_node <> "") + then (fprintf fmt "%a(static,main_mem);@ " pp_machine_static_alloc_name mname) + else (fprintf fmt "%a *main_mem = %a();@ " pp_machine_memtype_name mname pp_machine_alloc_name mname); + fprintf fmt "@ /* Initialize the main memory */@ "; + fprintf fmt "%a(%s);@ " pp_machine_reset_name mname main_mem; + end + +let print_global_initialize fmt basename = + let mNAME = file_to_module_name basename in + fprintf fmt "@ /* Initialize global constants */@ %a();@ " + pp_global_init_name mNAME + +let print_global_clear fmt basename = + let mNAME = file_to_module_name basename in + fprintf fmt "@ /* Clear global constants */@ %a();@ " + pp_global_clear_name mNAME + +let print_main_initialize mname main_mem fmt m = + if not (fst (get_stateless_status m)) + then + fprintf fmt "@ /* Initialize inputs, outputs and memories */@ %a%t%a%t%a(%s);@ " + (Utils.fprintf_list ~sep:"@ " (pp_initialize m main_mem (pp_c_var_read m))) m.mstep.step_inputs + (Utils.pp_newline_if_non_empty m.mstep.step_inputs) + (Utils.fprintf_list ~sep:"@ " (pp_initialize m main_mem (pp_c_var_read m))) m.mstep.step_outputs + (Utils.pp_newline_if_non_empty m.mstep.step_inputs) + pp_machine_init_name mname + main_mem + else + fprintf fmt "@ /* Initialize inputs and outputs */@ %a%t%a@ " + (Utils.fprintf_list ~sep:"@ " (pp_initialize m main_mem (pp_c_var_read m))) m.mstep.step_inputs + (Utils.pp_newline_if_non_empty m.mstep.step_inputs) + (Utils.fprintf_list ~sep:"@ " (pp_initialize m main_mem (pp_c_var_read m))) m.mstep.step_outputs + +let print_main_clear mname main_mem fmt m = + if not (fst (get_stateless_status m)) + then + fprintf fmt "@ /* Clear inputs, outputs and memories */@ %a%t%a%t%a(%s);@ " + (Utils.fprintf_list ~sep:"@ " (pp_clear m main_mem (pp_c_var_read m))) m.mstep.step_inputs + (Utils.pp_newline_if_non_empty m.mstep.step_inputs) + (Utils.fprintf_list ~sep:"@ " (pp_clear m main_mem (pp_c_var_read m))) m.mstep.step_outputs + (Utils.pp_newline_if_non_empty m.mstep.step_inputs) + pp_machine_clear_name mname + main_mem + else + fprintf fmt "@ /* Clear inputs and outputs */@ %a%t%a@ " + (Utils.fprintf_list ~sep:"@ " (pp_clear m main_mem (pp_c_var_read m))) m.mstep.step_inputs + (Utils.pp_newline_if_non_empty m.mstep.step_inputs) + (Utils.fprintf_list ~sep:"@ " (pp_clear m main_mem (pp_c_var_read m))) m.mstep.step_outputs + +let print_main_loop mname main_mem fmt m = + let input_values = + List.map (fun v -> mk_val (LocalVar v) v.var_type) + m.mstep.step_inputs in + begin + fprintf fmt "@ ISATTY = isatty(0);@ "; + fprintf fmt "@ /* Infinite loop */@ "; + fprintf fmt "@[<v 2>while(1){@ "; + fprintf fmt "fflush(stdout);@ "; + fprintf fmt "%a@ %t%a" + print_get_inputs m + (fun fmt -> pp_main_call mname main_mem fmt m input_values m.mstep.step_outputs) + print_put_outputs m + end -let print_main_fun machines m fmt = +let print_main_code fmt basename m = let mname = m.mname.node_id in let main_mem = if (!Options.static_mem && !Options.main_node <> "") then "&main_mem" else "main_mem" in fprintf fmt "@[<v 2>int main (int argc, char *argv[]) {@ "; - fprintf fmt "/* Declaration of inputs/outputs variables */@ "; - List.iter - (fun v -> fprintf fmt "%a = %a;@ " (pp_c_type v.var_id) v.var_type pp_c_initialize v.var_type - ) m.mstep.step_inputs; - List.iter - (fun v -> fprintf fmt "%a = %a;@ " (pp_c_type v.var_id) v.var_type pp_c_initialize v.var_type - ) m.mstep.step_outputs; - fprintf fmt "@ /* Main memory allocation */@ "; - if (!Options.static_mem && !Options.main_node <> "") - then (fprintf fmt "%a(static,main_mem);@ " pp_machine_static_alloc_name mname) - else (fprintf fmt "%a *main_mem = %a();@ " pp_machine_memtype_name mname pp_machine_alloc_name mname); - fprintf fmt "@ /* Initialize the main memory */@ "; - fprintf fmt "%a(%s);@ " pp_machine_reset_name mname main_mem; - fprintf fmt "@ ISATTY = isatty(0);@ "; - fprintf fmt "@ /* Infinite loop */@ "; - fprintf fmt "@[<v 2>while(1){@ "; - fprintf fmt "fflush(stdout);@ "; - List.iter - (fun v -> fprintf fmt "%s = %a;@ " - v.var_id - print_get_input v - ) m.mstep.step_inputs; - (match m.mstep.step_outputs with - (* | [] -> ( *) - (* fprintf fmt "%a(%a%t%s);@ " *) - (* pp_machine_step_name mname *) - (* (Utils.fprintf_list ~sep:", " (fun fmt v -> pp_print_string fmt v.var_id)) m.mstep.step_inputs *) - (* (pp_final_char_if_non_empty ", " m.mstep.step_inputs) *) - (* main_mem *) - (* ) *) - (* | [o] -> ( *) - (* fprintf fmt "%s = %a(%a%t%a, %s);%a" *) - (* o.var_id *) - (* pp_machine_step_name mname *) - (* (Utils.fprintf_list ~sep:", " (fun fmt v -> pp_print_string fmt v.var_id)) m.mstep.step_inputs *) - (* (pp_final_char_if_non_empty ", " m.mstep.step_inputs) *) - (* (Utils.fprintf_list ~sep:", " (fun fmt v -> fprintf fmt "&%s" v.var_id)) m.mstep.step_outputs *) - (* main_mem *) - (* print_put_outputs [o]) *) - | _ -> ( - fprintf fmt "%a(%a%t%a, %s);%a" - pp_machine_step_name mname - (Utils.fprintf_list ~sep:", " (fun fmt v -> pp_print_string fmt v.var_id)) m.mstep.step_inputs - (Utils.pp_final_char_if_non_empty ", " m.mstep.step_inputs) - (Utils.fprintf_list ~sep:", " (fun fmt v -> fprintf fmt "&%s" v.var_id)) m.mstep.step_outputs - main_mem - print_put_outputs m.mstep.step_outputs) - ); - fprintf fmt "@]@ }@ "; - fprintf fmt "return 1;"; + print_main_inout_declaration fmt m; + print_main_memory_allocation mname main_mem fmt m; + if !Options.mpfr then + begin + print_global_initialize fmt basename; + print_main_initialize mname main_mem fmt m; + end; + print_main_loop mname main_mem fmt m; + if Scopes.Plugin.is_active () then + begin + fprintf fmt "@ %t" Scopes.Plugin.pp + end; + fprintf fmt "@]@ }@ @ "; + if !Options.mpfr then + begin + print_main_clear mname main_mem fmt m; + print_global_clear fmt basename; + end; + fprintf fmt "@ return 1;"; fprintf fmt "@]@ }@." let print_main_header fmt = @@ -118,7 +178,7 @@ let print_main_c main_fmt main_machine basename prog machines _ (*dependencies*) (* Print the svn version number and the supported C standard (C90 or C99) *) print_version main_fmt; - print_main_fun machines main_machine main_fmt + print_main_code main_fmt basename main_machine end (* Local Variables: *) diff --git a/src/backends/C/c_backend_makefile.ml b/src/backends/C/c_backend_makefile.ml index 70371b40635e26fd83af6481e8ae457f4b7d9697..3bfee7e70f340fedf1efbe19333e42a5dc25cc49 100644 --- a/src/backends/C/c_backend_makefile.ml +++ b/src/backends/C/c_backend_makefile.ml @@ -18,7 +18,7 @@ let header_has_code header = (fun top -> match top.top_decl_desc with | Const _ -> true - | ImportedNode nd -> nd.nodei_in_lib = None + | ImportedNode nd -> nd.nodei_in_lib = [] | _ -> false ) header @@ -26,9 +26,7 @@ let header_has_code header = let header_libs header = List.fold_left (fun accu top -> match top.top_decl_desc with - | ImportedNode nd -> (match nd.nodei_in_lib with - | None -> accu - | Some lib -> Utils.list_union [lib] accu) + | ImportedNode nd -> Utils.list_union nd.nodei_in_lib accu | _ -> accu ) [] header @@ -73,10 +71,10 @@ let print_makefile basename nodename (dependencies: dep_t list) fmt = (* Main binary *) fprintf fmt "%s_%s:@." basename nodename; - fprintf fmt "\t${GCC} -I${INC} -I. -c %s.c@." basename; - fprintf fmt "\t${GCC} -I${INC} -I. -c %s_main.c@." basename; + fprintf fmt "\t${GCC} -O0 -I${INC} -I. -c %s.c@." basename; + fprintf fmt "\t${GCC} -O0 -I${INC} -I. -c %s_main.c@." basename; fprintf_dependencies fmt dependencies; - fprintf fmt "\t${GCC} -o %s_%s io_frontend.o %a %s.o %s_main.o %a@." basename nodename + fprintf fmt "\t${GCC} -O0 -o %s_%s io_frontend.o %a %s.o %s_main.o %a@." basename nodename (Utils.fprintf_list ~sep:" " (fun fmt (Dep (_, s, _, _)) -> Format.fprintf fmt "%s.o" s)) (compiled_dependencies dependencies) basename (* library .o *) @@ -87,6 +85,8 @@ let print_makefile basename nodename (dependencies: dep_t list) fmt = fprintf fmt "clean:@."; fprintf fmt "\t\\rm -f *.o %s_%s@." basename nodename; fprintf fmt "@."; + fprintf fmt ".PHONY: %s_%s@." basename nodename; + fprintf fmt "@."; Mod.other_targets fmt basename nodename dependencies; fprintf fmt "@."; diff --git a/src/backends/C/c_backend_src.ml b/src/backends/C/c_backend_src.ml index c8c06713286f0a921c669f4407bc1ccb8bcdaa36..0b08a7ebc0eb335493f65f43ca97295e0aa97363 100644 --- a/src/backends/C/c_backend_src.ml +++ b/src/backends/C/c_backend_src.ml @@ -30,42 +30,50 @@ struct (* Instruction Printing functions *) (********************************************************************************************) - (* Computes the depth to which multi-dimension array assignments should be expanded. It equals the maximum number of nested static array constructions accessible from root [v]. *) -let rec expansion_depth v = - match v with - | Cst (Const_array cl) -> 1 + List.fold_right (fun c -> max (expansion_depth (Cst c))) cl 0 - | Cst _ - | LocalVar _ - | StateVar _ -> 0 - | Fun (_, vl) -> List.fold_right (fun v -> max (expansion_depth v)) vl 0 - | Array vl -> 1 + List.fold_right (fun v -> max (expansion_depth v)) vl 0 - | Access (v, i) -> max 0 (expansion_depth v - 1) - | Power (v, n) -> 0 (*1 + expansion_depth v*) - -let rec merge_static_loop_profiles lp1 lp2 = - match lp1, lp2 with - | [] , _ -> lp2 - | _ , [] -> lp1 - | p1 :: q1, p2 :: q2 -> (p1 || p2) :: merge_static_loop_profiles q1 q2 + let rec expansion_depth v = + match v.value_desc with + | Cst cst -> expansion_depth_cst cst + | LocalVar _ + | StateVar _ -> 0 + | Fun (_, vl) -> List.fold_right (fun v -> max (expansion_depth v)) vl 0 + | Array vl -> 1 + List.fold_right (fun v -> max (expansion_depth v)) vl 0 + | Access (v, i) -> max 0 (expansion_depth v - 1) + | Power (v, n) -> 0 (*1 + expansion_depth v*) + and expansion_depth_cst c = + match c with + Const_array cl -> 1 + List.fold_right (fun c -> max (expansion_depth_cst c)) cl 0 + | _ -> 0 + + let rec merge_static_loop_profiles lp1 lp2 = + match lp1, lp2 with + | [] , _ -> lp2 + | _ , [] -> lp1 + | p1 :: q1, p2 :: q2 -> (p1 || p2) :: merge_static_loop_profiles q1 q2 (* Returns a list of bool values, indicating whether the indices must be static or not *) -let rec static_loop_profile v = - match v with - | Cst (Const_array cl) -> - List.fold_right (fun c lp -> merge_static_loop_profiles lp (static_loop_profile (Cst c))) cl [] - | Cst _ - | LocalVar _ - | StateVar _ -> [] - | Fun (_, vl) -> List.fold_right (fun v lp -> merge_static_loop_profiles lp (static_loop_profile v)) vl [] - | Array vl -> true :: List.fold_right (fun v lp -> merge_static_loop_profiles lp (static_loop_profile v)) vl [] - | Access (v, i) -> (match (static_loop_profile v) with [] -> [] | _ :: q -> q) - | Power (v, n) -> false :: static_loop_profile v - + let rec static_loop_profile v = + match v.value_desc with + | Cst cst -> static_loop_profile_cst cst + | LocalVar _ + | StateVar _ -> [] + | Fun (_, vl) -> List.fold_right (fun v lp -> merge_static_loop_profiles lp (static_loop_profile v)) vl [] + | Array vl -> true :: List.fold_right (fun v lp -> merge_static_loop_profiles lp (static_loop_profile v)) vl [] + | Access (v, i) -> (match (static_loop_profile v) with [] -> [] | _ :: q -> q) + | Power (v, n) -> false :: static_loop_profile v + and static_loop_profile_cst cst = + match cst with + Const_array cl -> List.fold_right + (fun c lp -> merge_static_loop_profiles lp (static_loop_profile_cst c)) + cl + [] + | _ -> [] + + let rec is_const_index v = - match v with + match v.value_desc with | Cst (Const_int _) -> true | Fun (_, vl) -> List.for_all is_const_index vl | _ -> false @@ -108,7 +116,7 @@ let pp_loop_var fmt lv = match snd lv with | LVar v -> fprintf fmt "[%s]" v | LInt r -> fprintf fmt "[%d]" !r - | LAcc i -> fprintf fmt "[%a]" pp_c_dimension (dimension_of_value i) + | LAcc i -> fprintf fmt "[%a]" pp_val i (* Prints a suffix of loop variables for arrays *) let pp_suffix fmt loop_vars = @@ -121,26 +129,25 @@ let pp_suffix fmt loop_vars = (* Prints a constant value before a suffix (needs casting) *) let rec pp_c_const_suffix var_type fmt c = match c with - | Const_int i -> pp_print_int fmt i - | Const_real r -> pp_print_string fmt r - | Const_float r -> pp_print_float fmt r - | Const_tag t -> pp_c_tag fmt t - | Const_array ca -> let var_type = Types.array_element_type var_type in - fprintf fmt "(%a[]){%a }" (pp_c_type "") var_type (Utils.fprintf_list ~sep:", " (pp_c_const_suffix var_type)) ca - | Const_struct fl -> fprintf fmt "{%a }" (Utils.fprintf_list ~sep:", " (fun fmt (f, c) -> (pp_c_const_suffix (Types.struct_field_type var_type f)) fmt c)) fl - | Const_string _ -> assert false (* string occurs in annotations not in C *) + | Const_int i -> pp_print_int fmt i + | Const_real (_, _, s) -> pp_print_string fmt s + | Const_tag t -> pp_c_tag fmt t + | Const_array ca -> let var_type = Types.array_element_type var_type in + fprintf fmt "(%a[]){%a }" (pp_c_type "") var_type (Utils.fprintf_list ~sep:", " (pp_c_const_suffix var_type)) ca + | Const_struct fl -> fprintf fmt "{%a }" (Utils.fprintf_list ~sep:", " (fun fmt (f, c) -> (pp_c_const_suffix (Types.struct_field_type var_type f)) fmt c)) fl + | Const_string _ -> assert false (* string occurs in annotations not in C *) (* Prints a [value] of type [var_type] indexed by the suffix list [loop_vars] *) let rec pp_value_suffix self var_type loop_vars pp_value fmt value = -(*Format.eprintf "pp_value_suffix: %a %a %a@." Types.print_ty var_type Machine_code.pp_val value pp_suffix loop_vars;*) - match loop_vars, value with + (*Format.eprintf "pp_value_suffix: %a %a %a@." Types.print_ty var_type Machine_code.pp_val value pp_suffix loop_vars;*) + match loop_vars, value.value_desc with | (x, LAcc i) :: q, _ when is_const_index i -> let r = ref (Dimension.size_const_dimension (Machine_code.dimension_of_value i)) in pp_value_suffix self var_type ((x, LInt r)::q) pp_value fmt value | (_, LInt r) :: q, Cst (Const_array cl) -> let var_type = Types.array_element_type var_type in - pp_value_suffix self var_type q pp_value fmt (Cst (List.nth cl !r)) + pp_value_suffix self var_type q pp_value fmt (mk_val (Cst (List.nth cl !r)) Type_predef.type_int) | (_, LInt r) :: q, Array vl -> let var_type = Types.array_element_type var_type in pp_value_suffix self var_type q pp_value fmt (List.nth vl !r) @@ -171,8 +178,17 @@ let rec pp_value_suffix self var_type loop_vars pp_value fmt value = which may yield constant arrays in expressions. Type is needed to correctly print constant arrays. *) -let pp_c_val self pp_var fmt (t, v) = - pp_value_suffix self t [] pp_var fmt v +let pp_c_val self pp_var fmt v = + pp_value_suffix self v.value_type [] pp_var fmt v + +let pp_basic_assign pp_var fmt typ var_name value = + if Types.is_real_type typ && !Options.mpfr + then + Mpfr.pp_inject_assign pp_var fmt var_name value + else + fprintf fmt "%a = %a;" + pp_var var_name + pp_var value (* type_directed assignment: array vs. statically sized type - [var_type]: type of variable to be assigned @@ -180,49 +196,69 @@ let pp_c_val self pp_var fmt (t, v) = - [value]: assigned value - [pp_var]: printer for variables *) -(* -let pp_assign_rec pp_var var_type var_name value = - match (Types.repr var_type).Types.tdesc, value with - | Types.Tarray (d, ty'), Array vl -> - let szl = Utils.enumerate (Dimension.size_const_dimension d) in - fprintf fmt "@[<v 2>{@,%a@]@,}" - (Utils.fprintf_list ~sep:"@," (fun fmt i -> r := i; aux fmt q)) szl - | Types.Tarray (d, ty'), Power (v, _) -> - | Types.Tarray (d, ty'), _ -> - | _ , _ -> - fprintf fmt "%a = %a;" - pp_var var_name - (pp_value_suffix self loop_vars pp_var) value -*) let pp_assign m self pp_var fmt var_type var_name value = let depth = expansion_depth value in -(*Format.eprintf "pp_assign %a %a %a %d@." Types.print_ty var_type pp_val var_name pp_val value depth;*) + (*Format.eprintf "pp_assign %a %a %a %d@." Types.print_ty var_type pp_val var_name pp_val value depth;*) let loop_vars = mk_loop_variables m var_type depth in let reordered_loop_vars = reorder_loop_variables loop_vars in - let rec aux fmt vars = + let rec aux typ fmt vars = match vars with | [] -> - fprintf fmt "%a = %a;" - (pp_value_suffix self var_type loop_vars pp_var) var_name - (pp_value_suffix self var_type loop_vars pp_var) value + pp_basic_assign (pp_value_suffix self var_type loop_vars pp_var) fmt typ var_name value | (d, LVar i) :: q -> -(*eprintf "pp_aux %a %s@." Dimension.pp_dimension d i;*) + let typ' = Types.array_element_type typ in + (*eprintf "pp_aux %a %s@." Dimension.pp_dimension d i;*) fprintf fmt "@[<v 2>{@,int %s;@,for(%s=0;%s<%a;%s++)@,%a @]@,}" - i i i Dimension.pp_dimension d i - aux q + i i i pp_c_dimension d i + (aux typ') q | (d, LInt r) :: q -> -(*eprintf "pp_aux %a %d@." Dimension.pp_dimension d (!r);*) - let szl = Utils.enumerate (Dimension.size_const_dimension d) in - fprintf fmt "@[<v 2>{@,%a@]@,}" - (Utils.fprintf_list ~sep:"@," (fun fmt i -> r := i; aux fmt q)) szl + (*eprintf "pp_aux %a %d@." Dimension.pp_dimension d (!r);*) + let typ' = Types.array_element_type typ in + let szl = Utils.enumerate (Dimension.size_const_dimension d) in + fprintf fmt "@[<v 2>{@,%a@]@,}" + (Utils.fprintf_list ~sep:"@," (fun fmt i -> r := i; aux typ' fmt q)) szl | _ -> assert false in begin reset_loop_counter (); (*reset_addr_counter ();*) - aux fmt reordered_loop_vars + aux var_type fmt reordered_loop_vars; + (*Format.eprintf "end pp_assign@.";*) end +let pp_machine_reset (m: machine_t) self fmt inst = + let (node, static) = + try + List.assoc inst m.minstances + with Not_found -> (Format.eprintf "internal error: pp_machine_reset %s %s %s:@." m.mname.node_id self inst; raise Not_found) in + fprintf fmt "%a(%a%t%s->%s);" + pp_machine_reset_name (node_name node) + (Utils.fprintf_list ~sep:", " Dimension.pp_dimension) static + (Utils.pp_final_char_if_non_empty ", " static) + self inst + +let pp_machine_init (m: machine_t) self fmt inst = + let (node, static) = + try + List.assoc inst m.minstances + with Not_found -> (Format.eprintf "internal error: pp_machine_init %s %s %s@." m.mname.node_id self inst; raise Not_found) in + fprintf fmt "%a(%a%t%s->%s);" + pp_machine_init_name (node_name node) + (Utils.fprintf_list ~sep:", " Dimension.pp_dimension) static + (Utils.pp_final_char_if_non_empty ", " static) + self inst + +let pp_machine_clear (m: machine_t) self fmt inst = + let (node, static) = + try + List.assoc inst m.minstances + with Not_found -> (Format.eprintf "internal error: pp_machine_clear %s %s %s@." m.mname.node_id self inst; raise Not_found) in + fprintf fmt "%a(%a%t%s->%s);" + pp_machine_clear_name (node_name node) + (Utils.fprintf_list ~sep:", " Dimension.pp_dimension) static + (Utils.pp_final_char_if_non_empty ", " static) + self inst + let has_c_prototype funname dependencies = let imported_node_opt = (* We select the last imported node with the name funname. The order of evaluation of dependencies should be @@ -247,7 +283,7 @@ let has_c_prototype funname dependencies = match imported_node_opt with | None -> false | Some nd -> (match nd.nodei_prototype with Some "C" -> true | _ -> false) - +(* let pp_instance_call dependencies m self fmt i (inputs: value_t list) (outputs: var_decl list) = try (* stateful node instance *) let (n,_) = List.assoc i m.minstances in @@ -278,21 +314,10 @@ let pp_instance_call dependencies m self fmt i (inputs: value_t list) (outputs: (Utils.fprintf_list ~sep:", " (pp_c_val self (pp_c_var_read m))) inputs (Utils.pp_final_char_if_non_empty ", " inputs) (Utils.fprintf_list ~sep:", " (pp_c_var_write m)) outputs - -let pp_machine_reset (m: machine_t) self fmt inst = - let (node, static) = - try - List.assoc inst m.minstances - with Not_found -> (Format.eprintf "pp_machine_reset %s %s %s: internal error@," m.mname.node_id self inst; raise Not_found) in - fprintf fmt "%a(%a%t%s->%s);" - pp_machine_reset_name (node_name node) - (Utils.fprintf_list ~sep:", " Dimension.pp_dimension) static - (Utils.pp_final_char_if_non_empty ", " static) - self inst - +*) let rec pp_conditional dependencies (m: machine_t) self fmt c tl el = fprintf fmt "@[<v 2>if (%a) {%t%a@]@,@[<v 2>} else {%t%a@]@,}" - (pp_c_val self (pp_c_var_read m)) (Type_predef.type_bool, c) + (pp_c_val self (pp_c_var_read m)) c (Utils.pp_newline_if_non_empty tl) (Utils.fprintf_list ~sep:"@," (pp_machine_instr dependencies m self)) tl (Utils.pp_newline_if_non_empty el) @@ -305,15 +330,23 @@ and pp_machine_instr dependencies (m: machine_t) self fmt instr = | MLocalAssign (i,v) -> pp_assign m self (pp_c_var_read m) fmt - i.var_type (LocalVar i) v + i.var_type (mk_val (LocalVar i) i.var_type) v | MStateAssign (i,v) -> pp_assign m self (pp_c_var_read m) fmt - i.var_type (StateVar i) v - | MStep ([i0], i, vl) when Basic_library.is_internal_fun i -> - pp_machine_instr dependencies m self fmt (MLocalAssign (i0, Fun (i, vl))) + i.var_type (mk_val (StateVar i) i.var_type) v + | MStep ([i0], i, vl) when Basic_library.is_value_internal_fun (mk_val (Fun (i, vl)) i0.var_type) -> + pp_machine_instr dependencies m self fmt + (MLocalAssign (i0, mk_val (Fun (i, vl)) i0.var_type)) + | MStep ([i0], i, vl) when has_c_prototype i dependencies -> + fprintf fmt "%a = %s(%a);" + (pp_c_val self (pp_c_var_read m)) (mk_val (LocalVar i0) i0.var_type) + i + (Utils.fprintf_list ~sep:", " (pp_c_val self (pp_c_var_read m))) vl + | MStep (il, i, vl) when Mpfr.is_homomorphic_fun i -> + pp_instance_call m self fmt i vl il | MStep (il, i, vl) -> - pp_instance_call dependencies m self fmt i vl il + pp_basic_instance_call m self fmt i vl il | MBranch (_, []) -> (Format.eprintf "internal error: C_backend_src.pp_machine_instr %a@." pp_instr instr; assert false) | MBranch (g, hl) -> if let t = fst (List.hd hl) in t = tag_true || t = tag_false @@ -323,13 +356,18 @@ and pp_machine_instr dependencies (m: machine_t) self fmt instr = let el = try List.assoc tag_false hl with Not_found -> [] in pp_conditional dependencies m self fmt g tl el else (* enum type case *) - let g_typ = Typing.type_const Location.dummy_loc (Const_tag (fst (List.hd hl))) in + (*let g_typ = Typing.type_const Location.dummy_loc (Const_tag (fst (List.hd hl))) in*) fprintf fmt "@[<v 2>switch(%a) {@,%a@,}@]" - (pp_c_val self (pp_c_var_read m)) (g_typ, g) + (pp_c_val self (pp_c_var_read m)) g (Utils.fprintf_list ~sep:"@," (pp_machine_branch dependencies m self)) hl + | MComment s -> + fprintf fmt "//%s@ " s + and pp_machine_branch dependencies m self fmt (t, h) = - fprintf fmt "@[<v 2>case %a:@,%a@,break;@]" pp_c_tag t (Utils.fprintf_list ~sep:"@," (pp_machine_instr dependencies m self)) h + fprintf fmt "@[<v 2>case %a:@,%a@,break;@]" + pp_c_tag t + (Utils.fprintf_list ~sep:"@," (pp_machine_instr dependencies m self)) h (********************************************************************************************) @@ -337,9 +375,14 @@ and pp_machine_branch dependencies m self fmt (t, h) = (********************************************************************************************) let print_const_def fmt cdecl = - fprintf fmt "%a = %a;@." - (pp_c_type cdecl.const_id) cdecl.const_type - pp_c_const cdecl.const_value + if !Options.mpfr && Types.is_real_type (Types.array_base_type cdecl.const_type) + then + fprintf fmt "%a;@." + (pp_c_type cdecl.const_id) (Types.dynamic_type cdecl.const_type) + else + fprintf fmt "%a = %a;@." + (pp_c_type cdecl.const_id) cdecl.const_type + pp_c_const cdecl.const_value let print_alloc_instance fmt (i, (m, static)) = @@ -374,36 +417,78 @@ let print_alloc_code fmt m = (Utils.fprintf_list ~sep:"" print_alloc_array) array_mem (Utils.fprintf_list ~sep:"" print_alloc_instance) m.minstances +let print_stateless_init_code dependencies fmt m self = + let minit = List.map (function MReset i -> i | _ -> assert false) m.minit in + let array_mems = List.filter (fun v -> Types.is_array_type v.var_type) m.mmemory in + fprintf fmt "@[<v 2>%a {@,%a%t%a%t%a%treturn;@]@,}@.@." + (print_init_prototype self) (m.mname.node_id, m.mstatic) + (* array mems *) + (Utils.fprintf_list ~sep:";@," (pp_c_decl_array_mem self)) array_mems + (Utils.pp_final_char_if_non_empty ";@," array_mems) + (* memory initialization *) + (Utils.fprintf_list ~sep:"@," (pp_initialize m self (pp_c_var_read m))) m.mmemory + (Utils.pp_newline_if_non_empty m.mmemory) + (* sub-machines initialization *) + (Utils.fprintf_list ~sep:"@," (pp_machine_init m self)) minit + (Utils.pp_newline_if_non_empty m.minit) + +let print_stateless_clear_code dependencies fmt m self = + let minit = List.map (function MReset i -> i | _ -> assert false) m.minit in + let array_mems = List.filter (fun v -> Types.is_array_type v.var_type) m.mmemory in + fprintf fmt "@[<v 2>%a {@,%a%t%a%t%a%treturn;@]@,}@.@." + (print_clear_prototype self) (m.mname.node_id, m.mstatic) + (* array mems *) + (Utils.fprintf_list ~sep:";@," (pp_c_decl_array_mem self)) array_mems + (Utils.pp_final_char_if_non_empty ";@," array_mems) + (* memory clear *) + (Utils.fprintf_list ~sep:"@," (pp_clear m self (pp_c_var_read m))) m.mmemory + (Utils.pp_newline_if_non_empty m.mmemory) + (* sub-machines clear*) + (Utils.fprintf_list ~sep:"@," (pp_machine_clear m self)) minit + (Utils.pp_newline_if_non_empty m.minit) + let print_stateless_code dependencies fmt m = let self = "__ERROR__" in if not (!Options.ansi && is_generic_node { top_decl_desc = Node m.mname; top_decl_loc = Location.dummy_loc; top_decl_owner = ""; top_decl_itf = false }) then (* C99 code *) - fprintf fmt "@[<v 2>%a {@,%a%t@,%a%a%t%t@]@,}@.@." + fprintf fmt "@[<v 2>%a {@,%a%t%a%t@,%a%a%t%a%t%t@]@,}@.@." print_stateless_prototype (m.mname.node_id, m.mstep.step_inputs, m.mstep.step_outputs) (* locals *) (Utils.fprintf_list ~sep:";@," (pp_c_decl_local_var m)) m.mstep.step_locals (Utils.pp_final_char_if_non_empty ";@," m.mstep.step_locals) + (* locals initialization *) + (Utils.fprintf_list ~sep:"@," (pp_initialize m self (pp_c_var_read m))) m.mstep.step_locals + (Utils.pp_newline_if_non_empty m.mstep.step_locals) (* check assertions *) (pp_c_checks self) m (* instrs *) (Utils.fprintf_list ~sep:"@," (pp_machine_instr dependencies m self)) m.mstep.step_instrs (Utils.pp_newline_if_non_empty m.mstep.step_instrs) + (* locals clear *) + (Utils.fprintf_list ~sep:"@," (pp_clear m self (pp_c_var_read m))) m.mstep.step_locals + (Utils.pp_newline_if_non_empty m.mstep.step_locals) (fun fmt -> fprintf fmt "return;") else (* C90 code *) let (gen_locals, base_locals) = List.partition (fun v -> Types.is_generic_type v.var_type) m.mstep.step_locals in let gen_calls = List.map (fun e -> let (id, _, _) = call_of_expr e in mk_call_var_decl e.expr_loc id) m.mname.node_gencalls in - fprintf fmt "@[<v 2>%a {@,%a%t@,%a%a%t%t@]@,}@.@." + fprintf fmt "@[<v 2>%a {@,%a%t%a%t@,%a%a%t%a%t%t@]@,}@.@." print_stateless_prototype (m.mname.node_id, (m.mstep.step_inputs@gen_locals@gen_calls), m.mstep.step_outputs) (* locals *) (Utils.fprintf_list ~sep:";@," (pp_c_decl_local_var m)) base_locals (Utils.pp_final_char_if_non_empty ";" base_locals) + (* locals initialization *) + (Utils.fprintf_list ~sep:"@," (pp_initialize m self (pp_c_var_read m))) m.mstep.step_locals + (Utils.pp_newline_if_non_empty m.mstep.step_locals) (* check assertions *) (pp_c_checks self) m (* instrs *) (Utils.fprintf_list ~sep:"@," (pp_machine_instr dependencies m self)) m.mstep.step_instrs (Utils.pp_newline_if_non_empty m.mstep.step_instrs) + (* locals clear *) + (Utils.fprintf_list ~sep:"@," (pp_clear m self (pp_c_var_read m))) m.mstep.step_locals + (Utils.pp_newline_if_non_empty m.mstep.step_locals) (fun fmt -> fprintf fmt "return;") let print_reset_code dependencies fmt m self = @@ -417,12 +502,42 @@ let print_reset_code dependencies fmt m self = (Utils.fprintf_list ~sep:"@," (pp_machine_instr dependencies m self)) m.minit (Utils.pp_newline_if_non_empty m.minit) +let print_init_code dependencies fmt m self = + let minit = List.map (function MReset i -> i | _ -> assert false) m.minit in + let array_mems = List.filter (fun v -> Types.is_array_type v.var_type) m.mmemory in + fprintf fmt "@[<v 2>%a {@,%a%t%a%t%a%treturn;@]@,}@.@." + (print_init_prototype self) (m.mname.node_id, m.mstatic) + (* array mems *) + (Utils.fprintf_list ~sep:";@," (pp_c_decl_array_mem self)) array_mems + (Utils.pp_final_char_if_non_empty ";@," array_mems) + (* memory initialization *) + (Utils.fprintf_list ~sep:"@," (pp_initialize m self (pp_c_var_read m))) m.mmemory + (Utils.pp_newline_if_non_empty m.mmemory) + (* sub-machines initialization *) + (Utils.fprintf_list ~sep:"@," (pp_machine_init m self)) minit + (Utils.pp_newline_if_non_empty m.minit) + +let print_clear_code dependencies fmt m self = + let minit = List.map (function MReset i -> i | _ -> assert false) m.minit in + let array_mems = List.filter (fun v -> Types.is_array_type v.var_type) m.mmemory in + fprintf fmt "@[<v 2>%a {@,%a%t%a%t%a%treturn;@]@,}@.@." + (print_clear_prototype self) (m.mname.node_id, m.mstatic) + (* array mems *) + (Utils.fprintf_list ~sep:";@," (pp_c_decl_array_mem self)) array_mems + (Utils.pp_final_char_if_non_empty ";@," array_mems) + (* memory clear *) + (Utils.fprintf_list ~sep:"@," (pp_clear m self (pp_c_var_read m))) m.mmemory + (Utils.pp_newline_if_non_empty m.mmemory) + (* sub-machines clear*) + (Utils.fprintf_list ~sep:"@," (pp_machine_clear m self)) minit + (Utils.pp_newline_if_non_empty m.minit) + let print_step_code dependencies fmt m self = if not (!Options.ansi && is_generic_node { top_decl_desc = Node m.mname; top_decl_loc = Location.dummy_loc; top_decl_owner = ""; top_decl_itf = false }) then (* C99 code *) let array_mems = List.filter (fun v -> Types.is_array_type v.var_type) m.mmemory in - fprintf fmt "@[<v 2>%a {@,%a%t%a%t@,%a%a%t%t@]@,}@.@." + fprintf fmt "@[<v 2>%a {@,%a%t%a%t%a%t@,%a%a%t%a%t%t@]@,}@.@." (print_step_prototype self) (m.mname.node_id, m.mstep.step_inputs, m.mstep.step_outputs) (* locals *) (Utils.fprintf_list ~sep:";@," (pp_c_decl_local_var m)) m.mstep.step_locals @@ -430,26 +545,38 @@ let print_step_code dependencies fmt m self = (* array mems *) (Utils.fprintf_list ~sep:";@," (pp_c_decl_array_mem self)) array_mems (Utils.pp_final_char_if_non_empty ";@," array_mems) + (* locals initialization *) + (Utils.fprintf_list ~sep:"@," (pp_initialize m self (pp_c_var_read m))) m.mstep.step_locals + (Utils.pp_newline_if_non_empty m.mstep.step_locals) (* check assertions *) (pp_c_checks self) m (* instrs *) (Utils.fprintf_list ~sep:"@," (pp_machine_instr dependencies m self)) m.mstep.step_instrs (Utils.pp_newline_if_non_empty m.mstep.step_instrs) + (* locals clear *) + (Utils.fprintf_list ~sep:"@," (pp_clear m self (pp_c_var_read m))) m.mstep.step_locals + (Utils.pp_newline_if_non_empty m.mstep.step_locals) (fun fmt -> fprintf fmt "return;") else (* C90 code *) let (gen_locals, base_locals) = List.partition (fun v -> Types.is_generic_type v.var_type) m.mstep.step_locals in let gen_calls = List.map (fun e -> let (id, _, _) = call_of_expr e in mk_call_var_decl e.expr_loc id) m.mname.node_gencalls in - fprintf fmt "@[<v 2>%a {@,%a%t@,%a%a%t%t@]@,}@.@." + fprintf fmt "@[<v 2>%a {@,%a%t%a%t@,%a%a%t%a%t%t@]@,}@.@." (print_step_prototype self) (m.mname.node_id, (m.mstep.step_inputs@gen_locals@gen_calls), m.mstep.step_outputs) (* locals *) (Utils.fprintf_list ~sep:";@," (pp_c_decl_local_var m)) base_locals (Utils.pp_final_char_if_non_empty ";" base_locals) + (* locals initialization *) + (Utils.fprintf_list ~sep:"@," (pp_initialize m self (pp_c_var_read m))) m.mstep.step_locals + (Utils.pp_newline_if_non_empty m.mstep.step_locals) (* check assertions *) (pp_c_checks self) m (* instrs *) (Utils.fprintf_list ~sep:"@," (pp_machine_instr dependencies m self)) m.mstep.step_instrs (Utils.pp_newline_if_non_empty m.mstep.step_instrs) + (* locals clear *) + (Utils.fprintf_list ~sep:"@," (pp_clear m self (pp_c_var_read m))) m.mstep.step_locals + (Utils.pp_newline_if_non_empty m.mstep.step_locals) (fun fmt -> fprintf fmt "return;") @@ -457,6 +584,28 @@ let print_step_code dependencies fmt m self = (* MAIN C file Printing functions *) (********************************************************************************************) +let print_global_init_code fmt basename prog dependencies = + let baseNAME = file_to_module_name basename in + let constants = List.map const_of_top (get_consts prog) in + fprintf fmt "@[<v 2>%a {@,static _Bool init = 0;@,@[<v 2>if (!init) { @,init = 1;@,%a%t%a@]@,}@,return;@]@,}@.@." + print_global_init_prototype baseNAME + (* constants *) + (Utils.fprintf_list ~sep:"@," (pp_const_initialize (pp_c_var_read Machine_code.empty_machine))) constants + (Utils.pp_final_char_if_non_empty "@," dependencies) + (* dependencies initialization *) + (Utils.fprintf_list ~sep:"@," print_import_init) dependencies + +let print_global_clear_code fmt basename prog dependencies = + let baseNAME = file_to_module_name basename in + let constants = List.map const_of_top (get_consts prog) in + fprintf fmt "@[<v 2>%a {@,static _Bool clear = 0;@,@[<v 2>if (!clear) { @,clear = 1;@,%a%t%a@]@,}@,return;@]@,}@.@." + print_global_clear_prototype baseNAME + (* constants *) + (Utils.fprintf_list ~sep:"@," (pp_const_clear (pp_c_var_read Machine_code.empty_machine))) constants + (Utils.pp_final_char_if_non_empty "@," dependencies) + (* dependencies initialization *) + (Utils.fprintf_list ~sep:"@," print_import_clear) dependencies + let print_machine dependencies fmt m = if fst (get_stateless_status m) then begin @@ -477,17 +626,32 @@ let print_machine dependencies fmt m = (* Reset function *) print_reset_code dependencies fmt m self; (* Step function *) - print_step_code dependencies fmt m self + print_step_code dependencies fmt m self; + + if !Options.mpfr then + begin + (* Init function *) + print_init_code dependencies fmt m self; + (* Clear function *) + print_clear_code dependencies fmt m self; + end end +let print_import_standard source_fmt = + begin + fprintf source_fmt "#include <assert.h>@."; + if not !Options.static_mem then + begin + fprintf source_fmt "#include <stdlib.h>@."; + end; + if !Options.mpfr then + begin + fprintf source_fmt "#include <mpfr.h>@."; + end + end let print_lib_c source_fmt basename prog machines dependencies = - - fprintf source_fmt "#include <assert.h>@."; - if not !Options.static_mem then - begin - fprintf source_fmt "#include <stdlib.h>@."; - end; + print_import_standard source_fmt; print_import_prototype source_fmt (Dep (true, basename, [], true (* assuming it is stateful *))); pp_print_newline source_fmt (); (* Print the svn version number and the supported C standard (C90 or C99) *) @@ -502,7 +666,13 @@ let print_lib_c source_fmt basename prog machines dependencies = fprintf source_fmt "@[<v>"; List.iter (fun c -> print_const_def source_fmt (const_of_top c)) (get_consts prog); fprintf source_fmt "@]@."; - + if !Options.mpfr then + begin + fprintf source_fmt "/* Global constants initialization */@."; + print_global_init_code source_fmt basename prog dependencies; + fprintf source_fmt "/* Global constants clearing */@."; + print_global_clear_code source_fmt basename prog dependencies; + end; if not !Options.static_mem then begin fprintf source_fmt "/* External allocation function prototypes */@."; diff --git a/src/backends/Horn/horn_backend.ml b/src/backends/Horn/horn_backend.ml index 24f58617739c40f7d8d9faf751b4271ae9d57f54..61b77b59d2c562224fca065ae549e1c60a613743 100644 --- a/src/backends/Horn/horn_backend.ml +++ b/src/backends/Horn/horn_backend.ml @@ -50,7 +50,6 @@ let pp_conj pp fmt l = | _ -> fprintf fmt "(and @[<v 0>%a@]@ )" (Utils.fprintf_list ~sep:" " pp) l - let concat prefix x = if prefix = "" then x else prefix ^ "." ^ x let rename f = (fun v -> {v with var_id = f v.var_id } ) let rename_machine p = rename (fun n -> concat p n) @@ -63,8 +62,13 @@ let rename_next_list = List.map rename_next let get_machine machines node_name = - List.find (fun m -> m.mname.node_id = node_name) machines - + try + List.find (fun m -> m.mname.node_id = node_name) machines + with Not_found -> + begin + Format.eprintf "internal error: get_machine %s@." node_name; + assert false + end let full_memory_vars machines machine = let rec aux fst prefix m = @@ -78,7 +82,6 @@ let full_memory_vars machines machine = in aux true machine.mname.node_id machine - let stateless_vars machines m = (rename_machine_list m.mname.node_id m.mstep.step_inputs)@ (rename_machine_list m.mname.node_id m.mstep.step_outputs) @@ -111,8 +114,8 @@ let pp_horn_tag fmt t = let rec pp_horn_const fmt c = match c with | Const_int i -> pp_print_int fmt i - | Const_real r -> pp_print_string fmt r - | Const_float r -> pp_print_float fmt r + | Const_real (c,e,s) -> assert false (* TODO rational pp_print_string fmt r *) + (* | Const_float r -> pp_print_float fmt r *) | Const_tag t -> pp_horn_tag fmt t | _ -> assert false @@ -121,7 +124,7 @@ let rec pp_horn_const fmt c = but an offset suffix may be added for array variables *) let rec pp_horn_val ?(is_lhs=false) self pp_var fmt v = - match v with + match v.value_desc with | Cst c -> pp_horn_const fmt c | Array _ | Access _ -> assert false (* no arrays *) @@ -135,7 +138,7 @@ let rec pp_horn_val ?(is_lhs=false) self pp_var fmt v = (* Prints a [value] indexed by the suffix list [loop_vars] *) let rec pp_value_suffix self pp_value fmt value = - match value with + match value.value_desc with | Fun (n, vl) -> Basic_library.pp_horn n (pp_value_suffix self pp_value) fmt vl | _ -> @@ -163,16 +166,16 @@ let pp_instance_call self (pp_horn_var m) fmt - o.var_type (LocalVar o) i1 + o.var_type (mk_val (LocalVar o) o.var_type) i1 else pp_assign m self (pp_horn_var m) fmt - o.var_type (LocalVar o) i2 - + o.var_type (mk_val (LocalVar o) o.var_type) i2 + end | name, _, _ -> begin - let target_machine = List.find (fun m -> m.mname.node_id = name) machines in + let target_machine = get_machine machines name in if init then Format.fprintf fmt "(%a %a%t%a%t%a)" pp_machine_init_name (node_name n) @@ -182,7 +185,7 @@ let pp_instance_call (Utils.pp_final_char_if_non_empty " " inputs) (* outputs *) (Utils.fprintf_list ~sep:" " (pp_horn_val self (pp_horn_var m))) - (List.map (fun v -> LocalVar v) outputs) + (List.map (fun v -> mk_val (LocalVar v) v.var_type) outputs) (Utils.pp_final_char_if_non_empty " " outputs) (* memories (next) *) (Utils.fprintf_list ~sep:" " pp_var) ( @@ -197,7 +200,7 @@ let pp_instance_call (Utils.fprintf_list ~sep:" " (pp_horn_val self (pp_horn_var m))) inputs (Utils.pp_final_char_if_non_empty " " inputs) (Utils.fprintf_list ~sep:" " (pp_horn_val self (pp_horn_var m))) - (List.map (fun v -> LocalVar v) outputs) + (List.map (fun v -> mk_val (LocalVar v) v.var_type) outputs) (Utils.pp_final_char_if_non_empty " " outputs) (Utils.fprintf_list ~sep:" " pp_var) ( (rename_machine_list @@ -220,7 +223,7 @@ let pp_instance_call inputs (Utils.pp_final_char_if_non_empty " " inputs) (Utils.fprintf_list ~sep:" " (pp_horn_val self (pp_horn_var m))) - (List.map (fun v -> LocalVar v) outputs) + (List.map (fun v -> mk_val (LocalVar v) v.var_type) outputs) ) let pp_machine_init (m: machine_t) self fmt inst = @@ -247,12 +250,12 @@ and pp_machine_instr machines ?(init=false) (m: machine_t) self fmt instr = | MLocalAssign (i,v) -> pp_assign m self (pp_horn_var m) fmt - i.var_type (LocalVar i) v + i.var_type (mk_val (LocalVar i) i.var_type) v | MStateAssign (i,v) -> pp_assign m self (pp_horn_var m) fmt - i.var_type (StateVar i) v - | MStep ([i0], i, vl) when Basic_library.is_internal_fun i -> + i.var_type (mk_val (StateVar i) i.var_type) v + | MStep ([i0], i, vl) when Basic_library.is_value_internal_fun (mk_val (Fun (i, vl)) i0.var_type) -> assert false (* This should not happen anymore *) | MStep (il, i, vl) -> pp_instance_call machines ~init:init m self fmt i vl il @@ -264,6 +267,7 @@ and pp_machine_instr machines ?(init=false) (m: machine_t) self fmt instr = let el = try List.assoc tag_false hl with Not_found -> [] in pp_conditional machines ~init:init m self fmt g tl el else assert false (* enum type case *) + | MComment _ -> () (**************************************************************) @@ -600,10 +604,6 @@ let traces_file fmt basename prog machines = memories_old in - (* let pp_prefix_rev fmt prefix = *) - (* Utils.fprintf_list ~sep:"." (fun fmt (id,n) -> fprintf fmt "(%s,%s)" id n.mname.node_id) fmt (List.rev prefix) *) - (* in *) - let pp_prefix_rev fmt prefix = Utils.fprintf_list ~sep:"." (fun fmt (id,n) -> fprintf fmt "(%s,%s)" id n.mname.node_id) fmt (List.rev prefix) in diff --git a/src/basic_library.ml b/src/basic_library.ml index 7e35b8a4707702184fba76724b00c32b308f4615..e353ed28b43bbe179a2198974a0924c6da9ca0d5 100644 --- a/src/basic_library.ml +++ b/src/basic_library.ml @@ -111,9 +111,34 @@ let eval_env = VE.initial defs -let internal_funs = ["+";"-";"*";"/";"mod";"&&";"||";"xor";"equi";"impl";"<";">";"<=";">=";"!=";"=";"uminus";"not"] +let arith_funs = ["+";"-";"*";"/";"mod"; "uminus"] +let bool_funs = ["&&";"||";"xor";"equi";"impl"; "not"] +let rel_funs = ["<";">";"<=";">=";"!=";"="] + +let internal_funs = arith_funs@bool_funs@rel_funs + +let rec is_internal_fun x targs = +(*Format.eprintf "is_internal_fun %s %a@." x Types.print_ty (List.hd targs);*) + match targs with + | [] -> assert false + | t::_ when Types.is_real_type t -> List.mem x internal_funs && not !Options.mpfr + | t::_ when Types.is_array_type t -> is_internal_fun x [Types.array_element_type t] + | _ -> List.mem x internal_funs + +let is_expr_internal_fun expr = + match expr.expr_desc with + | Expr_appl (f, e, _) -> is_internal_fun f (Types.type_list_of_type e.expr_type) + | _ -> assert false + +let is_value_internal_fun v = + match v.value_desc with + | Fun (f, vl) -> is_internal_fun f (List.map (fun v -> v.value_type) vl) + | _ -> assert false + +let is_homomorphic_fun x = + List.mem x internal_funs -let is_internal_fun x = +let is_stateless_fun x = List.mem x internal_funs let pp_c i pp_val fmt vl = diff --git a/src/causality.ml b/src/causality.ml index 00efa5430444f442100b588759a61d47b95b1269..e616ec5fee8ab2ad408c7da01534c8e193508ac5 100644 --- a/src/causality.ml +++ b/src/causality.ml @@ -225,7 +225,7 @@ let add_eq_dependencies mems inputs node_vars eq (g, g') = | Expr_arrow (e1, e2) -> add_dep lhs_is_mem lhs e2 (add_dep lhs_is_mem lhs e1 g) | Expr_when (e, c, _) -> add_dep lhs_is_mem lhs e (add_var lhs_is_mem lhs c g) | Expr_appl (f, e, None) -> - if Basic_library.is_internal_fun f + if Basic_library.is_expr_internal_fun rhs (* tuple component-wise dependency for internal operators *) then List.fold_right (add_dep lhs_is_mem lhs) (expr_list_of_expr e) g @@ -278,7 +278,7 @@ module NodeDep = struct | Expr_pre e | Expr_when (e,_,_) -> get_expr_calls prednode e | Expr_appl (id,e, _) -> - if not (Basic_library.is_internal_fun id) && prednode id + if not (Basic_library.is_expr_internal_fun expr) && prednode id then ESet.add expr (get_expr_calls prednode e) else (get_expr_calls prednode e) diff --git a/src/clock_calculus.ml b/src/clock_calculus.ml index ee201a880f60b37691cf4e0f8e6ec1566000628b..879d4313f800333e05c8f07368d7d7cd748e867c 100755 --- a/src/clock_calculus.ml +++ b/src/clock_calculus.ml @@ -608,7 +608,7 @@ and clock_subtyping_arg env ?(sub=true) real_arg formal_clock = (* computes clocks for node application *) and clock_appl env f args clock_reset loc = let args = expr_list_of_expr args in - if Basic_library.is_internal_fun f && List.exists is_tuple_expr args + if Basic_library.is_homomorphic_fun f && List.exists is_tuple_expr args then let args = Utils.transpose_list (List.map expr_list_of_expr args) in Clocks.clock_of_clock_list (List.map (fun args -> clock_call env f args clock_reset loc) args) diff --git a/src/clocks.ml b/src/clocks.ml index a172d89783d18989e1a7fe23376afbe5d7301602..7b703487051ed2a74c7f8fb896e51613e52f05db 100755 --- a/src/clocks.ml +++ b/src/clocks.ml @@ -123,6 +123,9 @@ let rec print_ck_long fmt ck = let new_id = ref (-1) +let rec bottom = + { cdesc = Clink bottom; cid = -666; cscoped = false } + let new_ck desc scoped = incr new_id; {cdesc=desc; cid = !new_id; cscoped = scoped} diff --git a/src/compiler_common.ml b/src/compiler_common.ml index f375d06a707913c8bf92272e6a9b2aaf7a7d9922..44dd47a7c831618f51f8e59b26733ebebc45d5a3 100644 --- a/src/compiler_common.ml +++ b/src/compiler_common.ml @@ -14,6 +14,13 @@ open Format open LustreSpec open Corelang +let check_main () = + if !Options.main_node = "" then + begin + eprintf "Code generation error: %a@." pp_error No_main_specified; + raise (Error (Location.dummy_loc, No_main_specified)) + end + let create_dest_dir () = begin if not (Sys.file_exists !Options.dest_dir) then @@ -43,7 +50,7 @@ let parse_header own filename = close_in h_in; header with - | (Lexer_lustre.Error err) | (Parse.Syntax_err err) as exc -> + | (Parse.Error err) as exc -> Parse.report_error err; raise exc | Corelang.Error (loc, err) as exc -> ( @@ -69,7 +76,7 @@ let parse_source source_name = close_in s_in; prog with - | (Lexer_lustre.Error err) | (Parse.Syntax_err err) as exc -> + | (Parse.Error err) as exc -> Parse.report_error err; raise exc | Corelang.Error (loc, err) as exc -> @@ -78,6 +85,16 @@ let parse_source source_name = Location.pp_loc loc; raise exc +let expand_automata decls = + Log.report ~level:1 (fun fmt -> fprintf fmt ".. expanding automata@ "); + try + Automata.expand_decls decls + with (Corelang.Error (loc, err)) as exc -> + eprintf "Automata error: %a%a@." + Corelang.pp_error err + Location.pp_loc loc; + raise exc + let check_stateless_decls decls = Log.report ~level:1 (fun fmt -> fprintf fmt ".. checking stateless/stateful status@ "); try @@ -88,6 +105,16 @@ let check_stateless_decls decls = Location.pp_loc loc; raise exc +let force_stateful_decls decls = + Log.report ~level:1 (fun fmt -> fprintf fmt ".. forcing stateful status@ "); + try + Stateless.force_prog decls + with (Stateless.Error (loc, err)) as exc -> + eprintf "Stateless status error: %a%a@." + Stateless.pp_error err + Location.pp_loc loc; + raise exc + let type_decls env decls = Log.report ~level:1 (fun fmt -> fprintf fmt ".. typing@ "); let new_env = diff --git a/src/corelang.ml b/src/corelang.ml index 857209ec6e00c1a1a4a8b3ebfa2596ea7b8ea9c7..07eeff427b0000814893c5c81461783d93619d78 100755 --- a/src/corelang.ml +++ b/src/corelang.ml @@ -245,14 +245,14 @@ let mktop = mktop_decl Location.dummy_loc Version.include_path false let top_int_type = mktop (TypeDef {tydef_id = "int"; tydef_desc = Tydec_int}) let top_bool_type = mktop (TypeDef {tydef_id = "bool"; tydef_desc = Tydec_bool}) -let top_float_type = mktop (TypeDef {tydef_id = "float"; tydef_desc = Tydec_float}) +(* let top_float_type = mktop (TypeDef {tydef_id = "float"; tydef_desc = Tydec_float}) *) let top_real_type = mktop (TypeDef {tydef_id = "real"; tydef_desc = Tydec_real}) let type_table = Utils.create_hashtable 20 [ Tydec_int , top_int_type; Tydec_bool , top_bool_type; - Tydec_float, top_float_type; + (* Tydec_float, top_float_type; *) Tydec_real , top_real_type ] @@ -270,7 +270,7 @@ let print_type_table fmt () = let rec is_user_type typ = match typ with | Tydec_int | Tydec_bool | Tydec_real - | Tydec_float | Tydec_any | Tydec_const _ -> false + (* | Tydec_float *) | Tydec_any | Tydec_const _ -> false | Tydec_clock typ' -> is_user_type typ' | _ -> true @@ -289,7 +289,7 @@ let rec coretype_equal ty1 ty2 = | _ , Tydec_const _ -> coretype_equal ty2 ty1 | Tydec_int , Tydec_int | Tydec_real , Tydec_real - | Tydec_float , Tydec_float + (* | Tydec_float , Tydec_float *) | Tydec_bool , Tydec_bool -> true | Tydec_clock ty1 , Tydec_clock ty2 -> coretype_equal ty1 ty2 | Tydec_array (d1,ty1), Tydec_array (d2, ty2) -> Dimension.is_eq_dimension d1 d2 && coretype_equal ty1 ty2 @@ -461,7 +461,7 @@ let rec dimension_of_expr expr = match expr.expr_desc with | Expr_const c -> dimension_of_const expr.expr_loc c | Expr_ident id -> mkdim_ident expr.expr_loc id - | Expr_appl (f, args, None) when Basic_library.is_internal_fun f -> + | Expr_appl (f, args, None) when Basic_library.is_expr_internal_fun expr -> let k = Types.get_static_value (Env.lookup_value Basic_library.type_env f) in if k = None then raise InvalidDimension; mkdim_appl expr.expr_loc f (List.map dimension_of_expr (expr_list_of_expr args)) @@ -501,7 +501,7 @@ let mk_new_node_name nd id = mk_new_name used id let get_var id var_list = - List.find (fun v -> v.var_id = id) var_list + List.find (fun v -> v.var_id = id) var_list let get_node_var id node = get_var id (get_node_vars node) @@ -579,7 +579,7 @@ let get_node_interface nd = nodei_stateless = nd.node_dec_stateless; nodei_spec = nd.node_spec; nodei_prototype = None; - nodei_in_lib = None; + nodei_in_lib = []; } (************************************************************************) @@ -624,16 +624,15 @@ let rec rename_carrier rename cck = let eq_replace_rhs_var pvar fvar eq = let pvar l = List.exists pvar l in let rec replace lhs rhs = - { rhs with expr_desc = replace_desc lhs rhs.expr_desc } - and replace_desc lhs rhs_desc = + { rhs with expr_desc = match lhs with | [] -> assert false - | [_] -> if pvar lhs then expr_desc_replace_var fvar rhs_desc else rhs_desc + | [_] -> if pvar lhs then expr_desc_replace_var fvar rhs.expr_desc else rhs.expr_desc | _ -> - (match rhs_desc with + (match rhs.expr_desc with | Expr_tuple tl -> Expr_tuple (List.map2 (fun v e -> replace [v] e) lhs tl) - | Expr_appl (f, arg, None) when Basic_library.is_internal_fun f -> + | Expr_appl (f, arg, None) when Basic_library.is_expr_internal_fun rhs -> let args = expr_list_of_expr arg in Expr_appl (f, expr_of_expr_list arg.expr_loc (List.map (replace lhs) args), None) | Expr_array _ @@ -643,8 +642,8 @@ let rec rename_carrier rename cck = | Expr_ident _ | Expr_appl _ -> if pvar lhs - then expr_desc_replace_var fvar rhs_desc - else rhs_desc + then expr_desc_replace_var fvar rhs.expr_desc + else rhs.expr_desc | Expr_ite (c, t, e) -> Expr_ite (replace lhs c, replace lhs t, replace lhs e) | Expr_arrow (e1, e2) -> Expr_arrow (replace lhs e1, replace lhs e2) | Expr_fby (e1, e2) -> Expr_fby (replace lhs e1, replace lhs e2) @@ -654,6 +653,7 @@ let rec rename_carrier rename cck = | Expr_merge (i, hl) -> let i' = if pvar lhs then fvar i else i in Expr_merge (i', List.map (fun (t, h) -> (t, replace lhs h)) hl) ) + } in { eq with eq_rhs = replace eq.eq_lhs eq.eq_rhs } @@ -792,15 +792,15 @@ let pp_prog_clock fmt prog = Utils.fprintf_list ~sep:"" pp_decl_clock fmt prog let pp_error fmt = function - | Main_not_found -> - fprintf fmt "cannot compile node %s: could not find the node definition.@." - !Options.main_node + Main_not_found -> + fprintf fmt "Could not find the definition of main node %s.@." + !Global.main_node | Main_wrong_kind -> fprintf fmt - "name %s does not correspond to a (non-imported) node definition.@." - !Options.main_node + "Node %s does not correspond to a valid main node definition.@." + !Global.main_node | No_main_specified -> - fprintf fmt "no main node specified.@." + fprintf fmt "No main node specified (use -node option)@." | Unbound_symbol sym -> fprintf fmt "%s is undefined.@." @@ -844,7 +844,7 @@ let mk_internal_node id = nodei_stateless = Types.get_static_value ty <> None; nodei_spec = spec; nodei_prototype = None; - nodei_in_lib = None; + nodei_in_lib = []; }) let add_internal_funs () = @@ -927,10 +927,8 @@ let rec substitute_expr vars_to_replace defs e = *) let rec get_expr_calls nodes e = - get_calls_expr_desc nodes e.expr_desc -and get_calls_expr_desc nodes expr_desc = let get_calls = get_expr_calls nodes in - match expr_desc with + match e.expr_desc with | Expr_const _ | Expr_ident _ -> Utils.ISet.empty | Expr_tuple el @@ -944,7 +942,7 @@ and get_calls_expr_desc nodes expr_desc = | Expr_fby (e1, e2) -> Utils.ISet.union (get_calls e1) (get_calls e2) | Expr_merge (_, hl) -> List.fold_left (fun accu (_, h) -> Utils.ISet.union accu (get_calls h)) Utils.ISet.empty hl | Expr_appl (i, e', i') -> - if Basic_library.is_internal_fun i then + if Basic_library.is_expr_internal_fun e then (get_calls e') else let calls = Utils.ISet.add i (get_calls e') in diff --git a/src/corelang.mli b/src/corelang.mli index d4a1d5689f2c337a4698c3f420e02f7970acd843..e68fded179067dee8febe6aaeabb5796e26eb83f 100755 --- a/src/corelang.mli +++ b/src/corelang.mli @@ -29,6 +29,8 @@ val mktop_decl: Location.t -> ident -> bool -> top_decl_desc -> top_decl val mkpredef_call: Location.t -> ident -> expr list -> expr val mk_new_name: (ident -> bool) -> ident -> ident val mk_new_node_name: node_desc -> ident -> ident +val mktop: top_decl_desc -> top_decl + val node_table : (ident, top_decl) Hashtbl.t val print_node_table: Format.formatter -> unit -> unit @@ -134,7 +136,7 @@ val copy_prog: top_decl list -> top_decl list val mkeexpr: Location.t -> expr -> eexpr val merge_node_annot: node_annot -> node_annot -> node_annot val extend_eexpr: (quantifier_type * var_decl list) list -> eexpr -> eexpr -val update_expr_annot: ident -> expr -> LustreSpec.expr_annot -> expr +val update_expr_annot: ident -> expr -> expr_annot -> expr (* val mkpredef_call: Location.t -> ident -> eexpr list -> eexpr*) (* Local Variables: *) diff --git a/src/env.ml b/src/env.ml index 31111bb59225979aae7d0254c583a75e8cf8e371..9fc32db2e9504a8e0406f90f3529d3ed01e9f70c 100755 --- a/src/env.ml +++ b/src/env.ml @@ -13,6 +13,7 @@ clock-calculus. *) open Utils +type 'a t = 'a IMap.t (* Same namespace for nodes, variables and constants *) let initial = IMap.empty diff --git a/src/inliner.ml b/src/inliner.ml index 1a2dd1034d7042c705fcf0392db24650e23cca93..50ac9b813e24b47d88c8f60d439bde55a431d0c8 100644 --- a/src/inliner.ml +++ b/src/inliner.ml @@ -64,6 +64,7 @@ We select the called node equations and variables. the resulting expression is tuple_of_renamed_outputs TODO: convert the specification/annotation/assert and inject them +DONE: annotations TODO: deal with reset *) let inline_call node orig_expr args reset locals caller = @@ -136,10 +137,14 @@ in }) node.node_asserts in + let annots' = + Plugins.inline_annots rename node.node_annot + in expr, inputs'@outputs'@locals'@locals, assign_inputs::eqs', - asserts' + asserts', + annots' @@ -156,27 +161,27 @@ let rec inline_expr ?(selection_on_annotation=false) expr locals node nodes = let inline_expr = inline_expr ~selection_on_annotation:selection_on_annotation in let inline_node = inline_node ~selection_on_annotation:selection_on_annotation in let inline_tuple el = - List.fold_right (fun e (el_tail, locals, eqs, asserts) -> - let e', locals', eqs', asserts' = inline_expr e locals node nodes in - e'::el_tail, locals', eqs'@eqs, asserts@asserts' - ) el ([], locals, [], []) + List.fold_right (fun e (el_tail, locals, eqs, asserts, annots) -> + let e', locals', eqs', asserts', annots' = inline_expr e locals node nodes in + e'::el_tail, locals', eqs'@eqs, asserts@asserts', annots@annots' + ) el ([], locals, [], [], []) in let inline_pair e1 e2 = - let el', l', eqs', asserts' = inline_tuple [e1;e2] in + let el', l', eqs', asserts', annots' = inline_tuple [e1;e2] in match el' with - | [e1'; e2'] -> e1', e2', l', eqs', asserts' + | [e1'; e2'] -> e1', e2', l', eqs', asserts', annots' | _ -> assert false in let inline_triple e1 e2 e3 = - let el', l', eqs', asserts' = inline_tuple [e1;e2;e3] in + let el', l', eqs', asserts', annots' = inline_tuple [e1;e2;e3] in match el' with - | [e1'; e2'; e3'] -> e1', e2', e3', l', eqs', asserts' + | [e1'; e2'; e3'] -> e1', e2', e3', l', eqs', asserts', annots' | _ -> assert false in match expr.expr_desc with | Expr_appl (id, args, reset) -> - let args', locals', eqs', asserts' = inline_expr args locals node nodes in + let args', locals', eqs', asserts', annots' = inline_expr args locals node nodes in if List.exists (check_node_name id) nodes && (* the current node call is provided as arguments nodes *) (not selection_on_annotation || is_inline_expr expr) (* and if selection on annotation is activated, @@ -188,68 +193,70 @@ let rec inline_expr ?(selection_on_annotation=false) expr locals node nodes = with Not_found -> (assert false) in let called = node_of_top called in let called' = inline_node called nodes in - let expr, locals', eqs'', asserts'' = + let expr, locals', eqs'', asserts'', annots'' = inline_call called' expr args' reset locals' node in - expr, locals', eqs'@eqs'', asserts'@asserts'' + expr, locals', eqs'@eqs'', asserts'@asserts'', annots'@annots'' else (* let _ = Format.eprintf "Not inlining call to %s@." id in *) { expr with expr_desc = Expr_appl(id, args', reset)}, locals', eqs', - asserts' + asserts', + annots' (* For other cases, we just keep the structure, but convert sub-expressions *) | Expr_const _ - | Expr_ident _ -> expr, locals, [], [] + | Expr_ident _ -> expr, locals, [], [], [] | Expr_tuple el -> - let el', l', eqs', asserts' = inline_tuple el in - { expr with expr_desc = Expr_tuple el' }, l', eqs', asserts' + let el', l', eqs', asserts', annots' = inline_tuple el in + { expr with expr_desc = Expr_tuple el' }, l', eqs', asserts', annots' | Expr_ite (g, t, e) -> - let g', t', e', l', eqs', asserts' = inline_triple g t e in - { expr with expr_desc = Expr_ite (g', t', e') }, l', eqs', asserts' + let g', t', e', l', eqs', asserts', annots' = inline_triple g t e in + { expr with expr_desc = Expr_ite (g', t', e') }, l', eqs', asserts', annots' | Expr_arrow (e1, e2) -> - let e1', e2', l', eqs', asserts' = inline_pair e1 e2 in - { expr with expr_desc = Expr_arrow (e1', e2') } , l', eqs', asserts' + let e1', e2', l', eqs', asserts', annots' = inline_pair e1 e2 in + { expr with expr_desc = Expr_arrow (e1', e2') } , l', eqs', asserts', annots' | Expr_fby (e1, e2) -> - let e1', e2', l', eqs', asserts' = inline_pair e1 e2 in - { expr with expr_desc = Expr_fby (e1', e2') }, l', eqs', asserts' + let e1', e2', l', eqs', asserts', annots' = inline_pair e1 e2 in + { expr with expr_desc = Expr_fby (e1', e2') }, l', eqs', asserts', annots' | Expr_array el -> - let el', l', eqs', asserts' = inline_tuple el in - { expr with expr_desc = Expr_array el' }, l', eqs', asserts' + let el', l', eqs', asserts', annots' = inline_tuple el in + { expr with expr_desc = Expr_array el' }, l', eqs', asserts', annots' | Expr_access (e, dim) -> - let e', l', eqs', asserts' = inline_expr e locals node nodes in - { expr with expr_desc = Expr_access (e', dim) }, l', eqs', asserts' + let e', l', eqs', asserts', annots' = inline_expr e locals node nodes in + { expr with expr_desc = Expr_access (e', dim) }, l', eqs', asserts', annots' | Expr_power (e, dim) -> - let e', l', eqs', asserts' = inline_expr e locals node nodes in - { expr with expr_desc = Expr_power (e', dim) }, l', eqs', asserts' + let e', l', eqs', asserts', annots' = inline_expr e locals node nodes in + { expr with expr_desc = Expr_power (e', dim) }, l', eqs', asserts', annots' | Expr_pre e -> - let e', l', eqs', asserts' = inline_expr e locals node nodes in - { expr with expr_desc = Expr_pre e' }, l', eqs', asserts' + let e', l', eqs', asserts', annots' = inline_expr e locals node nodes in + { expr with expr_desc = Expr_pre e' }, l', eqs', asserts', annots' | Expr_when (e, id, label) -> - let e', l', eqs', asserts' = inline_expr e locals node nodes in - { expr with expr_desc = Expr_when (e', id, label) }, l', eqs', asserts' + let e', l', eqs', asserts', annots' = inline_expr e locals node nodes in + { expr with expr_desc = Expr_when (e', id, label) }, l', eqs', asserts', annots' | Expr_merge (id, branches) -> - let el, l', eqs', asserts' = inline_tuple (List.map snd branches) in + let el, l', eqs', asserts', annots' = inline_tuple (List.map snd branches) in let branches' = List.map2 (fun (label, _) v -> label, v) branches el in - { expr with expr_desc = Expr_merge (id, branches') }, l', eqs', asserts' + { expr with expr_desc = Expr_merge (id, branches') }, l', eqs', asserts', annots' and inline_node ?(selection_on_annotation=false) node nodes = try copy_node (Hashtbl.find inline_table node.node_id) with Not_found -> let inline_expr = inline_expr ~selection_on_annotation:selection_on_annotation in - let new_locals, eqs, asserts = - List.fold_left (fun (locals, eqs, asserts) eq -> - let eq_rhs', locals', new_eqs', asserts' = + let new_locals, eqs, asserts, annots = + List.fold_left (fun (locals, eqs, asserts, annots) eq -> + let eq_rhs', locals', new_eqs', asserts', annots' = inline_expr eq.eq_rhs locals node nodes in - locals', { eq with eq_rhs = eq_rhs' }::new_eqs'@eqs, asserts'@asserts - ) (node.node_locals, [], node.node_asserts) (get_node_eqs node) + locals', { eq with eq_rhs = eq_rhs' }::new_eqs'@eqs, asserts'@asserts, annots'@annots + ) (node.node_locals, [], node.node_asserts, node.node_annot) (get_node_eqs node) in let inlined = { node with node_locals = new_locals; node_stmts = List.map (fun eq -> Eq eq) eqs; node_asserts = asserts; + node_annot = annots; } in begin @@ -363,6 +370,11 @@ let witness filename main_name orig inlined type_env clock_env = in let main = [{ top_decl_desc = Node main_node; top_decl_loc = loc; top_decl_owner = filename; top_decl_itf = false }] in let new_prog = others@nodes_origs@nodes_inlined@main in +(* + let _ = Typing.type_prog type_env new_prog in + let _ = Clock_calculus.clock_prog clock_env new_prog in +*) + let witness_file = (Options.get_witness_dir filename) ^ "/" ^ "inliner_witness.lus" in let witness_out = open_out witness_file in let witness_fmt = Format.formatter_of_out_channel witness_out in @@ -387,7 +399,6 @@ let global_inline basename prog type_env clock_env = | _ -> main_opt, nodes, top::others) prog (None, [], []) in - (* Recursively each call of a node in the top node is replaced *) let main_node = Utils.desome main_node in let main_node' = inline_all_calls main_node other_nodes in diff --git a/src/lexerLustreSpec.mll b/src/lexerLustreSpec.mll index da4ca6caeab124ec8928ca365b423c35b634e4fc..869aa31dddc2531ae5534c2242a6a6ed073aec62 100644 --- a/src/lexerLustreSpec.mll +++ b/src/lexerLustreSpec.mll @@ -15,9 +15,9 @@ open Parser_lustre open Utils - let str_buf = Buffer.create 1024 - exception Error of Location.t + + let str_buf = Buffer.create 1024 (* As advised by Caml documentation. This way a single lexer rule is used to handle all the possible keywords. *) @@ -44,7 +44,7 @@ let keyword_table = "wcet", WCET; "int", TINT; "bool", TBOOL; - "float", TFLOAT; + (* "float", TFLOAT; *) "real", TREAL; "clock", TCLOCK; "not", NOT; @@ -86,11 +86,12 @@ rule token = parse token lexbuf } | blank + {token lexbuf} - | '-'? ['0'-'9'] ['0'-'9']* '.' ['0'-'9']* - {FLOAT (float_of_string (Lexing.lexeme lexbuf))} + | (('-'? ['0'-'9'] ['0'-'9']* as l) '.' (['0'-'9']* as r)) as s + {REAL (Num.num_of_string (l^r), String.length r, s)} + | (('-'? ['0'-'9']+ as l) '.' (['0'-'9']+ as r) ('E'|'e') (('+'|'-') ['0'-'9'] ['0'-'9']* as exp)) as s + {REAL (Num.num_of_string (l^r), String.length r + -1 * int_of_string exp, s)} | '-'? ['0'-'9']+ {INT (int_of_string (Lexing.lexeme lexbuf)) } - | '-'? ['0'-'9']+ '.' ['0'-'9']+ ('E'|'e') ('+'|'-') ['0'-'9'] ['0'-'9'] as s {REAL s} (* | '/' (['_' 'A'-'Z' 'a'-'z'] ['A'-'Z' 'a'-'z' '_' '0'-'9']* '/')+ as s {IDENT s} *) @@ -126,10 +127,10 @@ rule token = parse | "^" {POWER} | '"' { Buffer.clear str_buf; string_parse lexbuf } | eof { EOF } - | _ { raise (Error (Location.curr lexbuf)) } + | _ { raise (Parse.Error (Location.curr lexbuf, Unexpected_eof)) } and comment_line n = parse | eof - { raise (Error (Location.curr lexbuf)) } + { raise (Parse.Error (Location.curr lexbuf, Unfinished_comment)) } | "(*" { comment_line (n+1) lexbuf } | "*)" @@ -139,6 +140,7 @@ and comment_line n = parse comment_line n lexbuf } | _ { comment_line n lexbuf } and string_parse = parse + | eof { raise (Parse.Error (Location.curr lexbuf, Unfinished_string)) } | "\\\"" as s { Buffer.add_string str_buf s; string_parse lexbuf} | '"' { STRING (Buffer.contents str_buf) } | _ as c { Buffer.add_char str_buf c; string_parse lexbuf } @@ -146,18 +148,20 @@ and string_parse = parse { let annot s = - let lb = Lexing.from_string s in + let lexbuf = Lexing.from_string s in try - Parser_lustre.lustre_annot(* ParserLustreSpec.lustre_annot *) token lb + Parser_lustre.lustre_annot(* ParserLustreSpec.lustre_annot *) token lexbuf with Parsing.Parse_error as _e -> ( Format.eprintf "Lexing error at position %a:@.unexpected token %s@.@?" - (fun fmt p -> Format.fprintf fmt "%s l%i c%i" p.Lexing.pos_fname p.Lexing.pos_lnum p.Lexing.pos_cnum) lb.Lexing.lex_curr_p - (Lexing.lexeme lb); - raise Parsing.Parse_error) + (fun fmt p -> Format.fprintf fmt "%s l%i c%i" p.Lexing.pos_fname p.Lexing.pos_lnum p.Lexing.pos_cnum) lexbuf.Lexing.lex_curr_p + (Lexing.lexeme lexbuf); + raise (Error (Location.curr lexbuf))) let spec s = - let lb = Lexing.from_string s in - Parser_lustre.lustre_spec (*ParserLustreSpec.lustre_spec*) token lb - + let lexbuf = Lexing.from_string s in + try + Parser_lustre.lustre_spec (*ParserLustreSpec.lustre_spec*) token lexbuf + with Parsing.Parse_error -> + raise (Error (Location.curr lexbuf)) } diff --git a/src/lexer_lustre.mll b/src/lexer_lustre.mll index 6fa09b53675bcf7fb9888084e80b7496ab849656..8f01a25b51282b94e22c1444d80dccc583733919 100755 --- a/src/lexer_lustre.mll +++ b/src/lexer_lustre.mll @@ -13,8 +13,6 @@ open Parser_lustre open Utils -exception Error of Location.t - (* As advised by Caml documentation. This way a single lexer rule is used to handle all the possible keywords. *) let keyword_table = @@ -48,7 +46,7 @@ let keyword_table = "type", TYPE; "int", TINT; "bool", TBOOL; - "float", TFLOAT; + (* "float", TFLOAT; *) "real", TREAL; "clock", TCLOCK; "not", NOT; @@ -75,13 +73,13 @@ let make_annot lexbuf s = try let ann = LexerLustreSpec.annot s in ANNOT ann - with _ -> (Format.eprintf "Impossible to parse the following annotation:@.%s@.@?" s; exit 1) + with LexerLustreSpec.Error loc -> raise (Parse.Error (Location.shift (Location.curr lexbuf) loc, Annot_error s)) let make_spec lexbuf s = try let ns = LexerLustreSpec.spec s in NODESPEC ns - with _ -> (Format.eprintf "Impossible to parse the following node specification:@.%s@.@?" s; exit 1) + with LexerLustreSpec.Error loc -> raise (Parse.Error (Location.shift (Location.curr lexbuf) loc, Node_spec_error s)) } @@ -108,11 +106,12 @@ rule token = parse token lexbuf } | blank + {token lexbuf} -| ['0'-'9'] ['0'-'9']* '.' ['0'-'9']* - {FLOAT (float_of_string (Lexing.lexeme lexbuf))} +| ((['0'-'9']+ as l) '.' (['0'-'9']* as r) ('E'|'e') (('+'|'-')? ['0'-'9']+ as exp)) as s + {REAL (Num.num_of_string (l^r), String.length r + -1 * int_of_string exp , s)} +| ((['0'-'9']+ as l) '.' (['0'-'9']* as r)) as s + {REAL (Num.num_of_string (l^r), String.length r, s)} | ['0'-'9']+ {INT (int_of_string (Lexing.lexeme lexbuf)) } -| ['0'-'9']+ '.' ['0'-'9']+ ('E'|'e') ('+'|'-') ['0'-'9'] ['0'-'9']* as s {REAL s} | "tel." {TEL} | "tel;" {TEL} | "#open" { OPEN } @@ -158,11 +157,11 @@ rule token = parse | "^" {POWER} | '"' {QUOTE} | eof { EOF } -| _ { raise (Error (Location.curr lexbuf)) } +| _ { raise (Parse.Error (Location.curr lexbuf, Undefined_token (Lexing.lexeme lexbuf))) } and comment n = parse | eof - { raise (Error (Location.curr lexbuf)) } + { raise (Parse.Error (Location.curr lexbuf, Unfinished_comment)) } | "(*" { comment (n+1) lexbuf } | "*)" @@ -173,10 +172,12 @@ and comment n = parse | _ { comment n lexbuf } and annot_singleline = parse + | eof { make_annot lexbuf (Buffer.contents buf) } | newline { incr_line lexbuf; make_annot lexbuf (Buffer.contents buf) } | _ as c { Buffer.add_char buf c; annot_singleline lexbuf } and annot_multiline n = parse + | eof { raise (Parse.Error (Location.curr lexbuf, Unfinished_annot)) } | "*)" as s { if n > 0 then (Buffer.add_string buf s; annot_multiline (n-1) lexbuf) @@ -187,10 +188,12 @@ and annot_multiline n = parse | _ as c { Buffer.add_char buf c; annot_multiline n lexbuf } and spec_singleline = parse + | eof { make_spec lexbuf (Buffer.contents buf) } | newline { incr_line lexbuf; make_spec lexbuf (Buffer.contents buf) } | _ as c { Buffer.add_char buf c; spec_singleline lexbuf } and spec_multiline n = parse + | eof { raise (Parse.Error (Location.curr lexbuf, Unfinished_node_spec)) } | "*)" as s { if n > 0 then (Buffer.add_string buf s; spec_multiline (n-1) lexbuf) else diff --git a/src/liveness.ml b/src/liveness.ml index 21b716df1f8f441f41ea8846e0748fc601b454c7..23bd59449713ec8472605153f35c2cafb4b547e1 100755 --- a/src/liveness.ml +++ b/src/liveness.ml @@ -115,7 +115,7 @@ let remove_roots ctx = (* checks whether a variable is aliasable, depending on its (address) type *) let is_aliasable var = - Types.is_address_type var.var_type + (not (!Options.mpfr && Types.is_real_type var.var_type)) && Types.is_address_type var.var_type (* checks whether a variable [v] is an input of the [var] equation, with an address type. if so, [var] could not safely reuse/alias [v], should [v] be dead in the caller node, diff --git a/src/location.ml b/src/location.ml index 3b99fde85aaad526085523e45b2fb4142846bfa0..ea2584c399e9667110102d447c56ae073bfa6c11 100755 --- a/src/location.ml +++ b/src/location.ml @@ -34,7 +34,20 @@ let init lexbuf fname = Lexing.pos_bol = 0; Lexing.pos_cnum = 0; } - + +let shift_pos pos1 pos2 = + assert (pos1.Lexing.pos_fname = pos2.Lexing.pos_fname); + {Lexing.pos_fname = pos1.Lexing.pos_fname; + Lexing.pos_lnum = pos1.Lexing.pos_lnum + pos2.Lexing.pos_lnum; + Lexing.pos_bol = pos1.Lexing.pos_bol + pos2.Lexing.pos_bol; + Lexing.pos_cnum =if pos2.Lexing.pos_lnum = 1 then pos1.Lexing.pos_cnum + pos2.Lexing.pos_cnum else pos2.Lexing.pos_cnum + } + +let shift loc1 loc2 = + {loc_start = shift_pos loc1.loc_start loc2.loc_start; + loc_end = shift_pos loc1.loc_start loc2.loc_end + } + let symbol_rloc () = { loc_start = Parsing.symbol_start_pos (); diff --git a/src/lusic.ml b/src/lusic.ml index a1835f38ee08f805f466479480baf0acaa7c8c00..76ed1611815d7ecba6ed48cdf5878e67cdf4dedd 100644 --- a/src/lusic.ml +++ b/src/lusic.ml @@ -33,7 +33,7 @@ let extract_header dirname basename prog = let owner = dirname ^ "/" ^ basename in List.fold_right (fun decl header -> -(*Format.eprintf "Lusic.extract_header: owner = %s decl_owner = %s@." owner decl.top_decl_owner;*) + (*Format.eprintf "Lusic.extract_header: header = %B, owner = %s, decl_owner = %s@." decl.top_decl_itf owner decl.top_decl_owner;*) if decl.top_decl_itf || decl.top_decl_owner <> owner then header else match decl.top_decl_desc with | Node nd -> { decl with top_decl_desc = ImportedNode (Corelang.get_node_interface nd) } :: header @@ -51,6 +51,7 @@ let write_lusic lusi (header : top_decl list) basename extension = let target_name = basename ^ extension in let outchan = open_out_bin target_name in begin + (*Format.eprintf "write_lusic: %i items.@." (List.length header);*) Marshal.to_channel outchan (Version.number, lusi : string * bool) []; Marshal.to_channel outchan (header : top_decl list) []; close_out outchan @@ -89,6 +90,7 @@ let print_lusic_to_h basename extension = let h_fmt = formatter_of_out_channel h_out in begin assert (not lusic.obsolete); + (*Format.eprintf "lusic to h: %i items.@." (List.length lusic.contents);*) Typing.uneval_prog_generics lusic.contents; Clock_calculus.uneval_prog_generics lusic.contents; Header.print_header_from_header h_fmt (Filename.basename basename) lusic.contents; diff --git a/src/lustreSpec.ml b/src/lustreSpec.ml index 4202fe412f55ae631629b0dd34dc4c3b0490cec0..991c5ed7102f5071d178efd3bce0c383da5e725f 100644 --- a/src/lustreSpec.ml +++ b/src/lustreSpec.ml @@ -24,7 +24,7 @@ and type_dec_desc = | Tydec_any | Tydec_int | Tydec_real - | Tydec_float + (* | Tydec_float *) | Tydec_bool | Tydec_clock of type_dec_desc | Tydec_const of ident @@ -50,8 +50,7 @@ and clock_dec_desc = type constant = | Const_int of int - | Const_real of string - | Const_float of float + | Const_real of Num.num * int * string (* (a, b, c) means a * 10^-b. c is the original string *) | Const_array of constant list | Const_tag of label | Const_string of string (* used only for annotations *) @@ -188,7 +187,7 @@ type imported_node_desc = nodei_stateless: bool; nodei_spec: node_annot option; nodei_prototype: string option; - nodei_in_lib: string option; + nodei_in_lib: string list; } type const_desc = @@ -220,6 +219,33 @@ type dep_t = Dep of * (top_decl list) * bool (* is stateful *) + +(************ Machine code types *************) + +type value_t = + { + value_desc: value_t_desc; + value_type: Types.type_expr; + value_annot: expr_annot option + } +and value_t_desc = + | Cst of constant + | LocalVar of var_decl + | StateVar of var_decl + | Fun of ident * value_t list + | Array of value_t list + | Access of value_t * value_t + | Power of value_t * value_t + +type instr_t = + | MLocalAssign of var_decl * value_t + | MStateAssign of var_decl * value_t + | MReset of ident + | MStep of var_decl list * ident * value_t list + | MBranch of value_t * (label * instr_t list) list + | MComment of string + + type error = Main_not_found | Main_wrong_kind diff --git a/src/machine_code.ml b/src/machine_code.ml index cd1fc9d71d48603edb1b71966c2bba042deb6b66..770462ff4b7088c55b7492162cfa652291ba8ca3 100644 --- a/src/machine_code.ml +++ b/src/machine_code.ml @@ -21,25 +21,9 @@ module OrdVarDecl:Map.OrderedType with type t=var_decl = module ISet = Set.Make(OrdVarDecl) -type value_t = - | Cst of constant - | LocalVar of var_decl - | StateVar of var_decl - | Fun of ident * value_t list - | Array of value_t list - | Access of value_t * value_t - | Power of value_t * value_t - -type instr_t = - | MLocalAssign of var_decl * value_t - | MStateAssign of var_decl * value_t - | MReset of ident - | MStep of var_decl list * ident * value_t list - | MBranch of value_t * (label * instr_t list) list - let rec pp_val fmt v = - match v with - | Cst c -> Printers.pp_const fmt c + match v.value_desc with + | Cst c -> Printers.pp_const fmt c | LocalVar v -> Format.pp_print_string fmt v.var_id | StateVar v -> Format.pp_print_string fmt v.var_id | Array vl -> Format.fprintf fmt "[%a]" (Utils.fprintf_list ~sep:", " pp_val) vl @@ -61,6 +45,7 @@ let rec pp_instr fmt i = Format.fprintf fmt "@[<v 2>case(%a) {@,%a@,}@]" pp_val g (Utils.fprintf_list ~sep:"@," pp_branch) hl + | MComment s -> Format.pp_print_string fmt s and pp_branch fmt (t, h) = Format.fprintf fmt "@[<v 2>%s:@,%a@]" t (Utils.fprintf_list ~sep:"@," pp_instr) h @@ -119,6 +104,12 @@ let pp_machine fmt m = (fun fmt -> match m.mspec with | None -> () | Some spec -> Printers.pp_spec fmt spec) (Utils.fprintf_list ~sep:"@ " Printers.pp_expr_annot) m.mannot +let rec is_const_value v = + match v.value_desc with + | Cst _ -> true + | Fun (id, args) -> Basic_library.is_value_internal_fun v && List.for_all is_const_value args + | _ -> false + (* Returns the declared stateless status and the computed one. *) let get_stateless_status m = (m.mname.node_dec_stateless, Utils.desome m.mname.node_stateless) @@ -177,29 +168,73 @@ let arrow_top_decl = top_decl_loc = Location.dummy_loc } +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 (Types.new_ty Types.Tbool) in let var_input1 = List.nth arrow_desc.node_inputs 0 in let var_input2 = List.nth arrow_desc.node_inputs 1 in let var_output = List.nth arrow_desc.node_outputs 0 in + let cst b = mk_val (Cst (const_of_bool b)) Type_predef.type_bool in + let t_arg = Types.new_univar () in (* TODO Xavier: c'est bien la bonne def ? *) { mname = arrow_desc; mmemory = [var_state]; mcalls = []; minstances = []; - minit = [MStateAssign(var_state, Cst (const_of_bool true))]; - mconst = []; + minit = [MStateAssign(var_state, cst true)]; mstatic = []; + mconst = []; mstep = { step_inputs = arrow_desc.node_inputs; step_outputs = arrow_desc.node_outputs; step_locals = []; step_checks = []; - step_instrs = [conditional (StateVar var_state) - [MStateAssign(var_state, Cst (const_of_bool false)); - MLocalAssign(var_output, LocalVar var_input1)] - [MLocalAssign(var_output, LocalVar var_input2)] ]; + step_instrs = [conditional (mk_val (StateVar var_state) Type_predef.type_bool) + [MStateAssign(var_state, cst false); + MLocalAssign(var_output, mk_val (LocalVar var_input1) t_arg)] + [MLocalAssign(var_output, mk_val (LocalVar var_input2) t_arg)] ]; + step_asserts = []; + }; + mspec = None; + mannot = []; + } + +let empty_desc = + { + node_id = arrow_id; + node_type = Types.bottom; + node_clock = Clocks.bottom; + node_inputs= []; + node_outputs= []; + node_locals= []; + node_gencalls = []; + node_checks = []; + node_asserts = []; + node_stmts= []; + node_dec_stateless = true; + node_stateless = Some true; + node_spec = None; + node_annot = []; } + +let empty_machine = + { + mname = empty_desc; + mmemory = []; + mcalls = []; + minstances = []; + minit = []; + mstatic = []; + mconst = []; + mstep = { + step_inputs = []; + step_outputs = []; + step_locals = []; + step_checks = []; + step_instrs = []; step_asserts = []; }; mspec = None; @@ -233,14 +268,21 @@ let translate_ident node (m, si, j, d, s) id = try (* id is a node var *) let var_id = get_node_var id node in if ISet.exists (fun v -> v.var_id = id) m - then StateVar var_id - else LocalVar var_id + then mk_val (StateVar var_id) var_id.var_type + else mk_val (LocalVar var_id) var_id.var_type with Not_found -> try (* id is a constant *) - LocalVar (Corelang.var_decl_of_const (const_of_top (Hashtbl.find Corelang.consts_table id))) + let vdecl = (Corelang.var_decl_of_const (const_of_top (Hashtbl.find Corelang.consts_table id))) in + mk_val (LocalVar vdecl) vdecl.var_type with Not_found -> (* id is a tag *) - Cst (Const_tag id) + (* DONE construire une liste des enum declarés et alors chercher dedans la liste + qui contient id *) + 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) + with Not_found -> (Format.eprintf "internal error: Machine_code.translate_ident %s" id; + assert false) let rec control_on_clock node ((m, si, j, d, s) as args) ck inst = match (Clocks.repr ck).cdesc with @@ -292,36 +334,36 @@ let specialize_op expr = | "C" -> specialize_to_c expr | _ -> expr -let rec translate_expr ?(ite=false) node ((m, si, j, d, s) as args) expr = +let rec translate_expr node ((m, si, j, d, s) as args) expr = let expr = specialize_op expr in - match expr.expr_desc with - | Expr_const v -> Cst v - | Expr_ident x -> translate_ident node args x - | Expr_array el -> Array (List.map (translate_expr node args) el) - | Expr_access (t, i) -> Access (translate_expr node args t, translate_expr node args (expr_of_dimension i)) - | Expr_power (e, n) -> Power (translate_expr node args e, translate_expr node args (expr_of_dimension n)) - | Expr_tuple _ - | Expr_arrow _ - | Expr_fby _ - | Expr_pre _ -> (Printers.pp_expr Format.err_formatter expr; Format.pp_print_flush Format.err_formatter (); raise NormalizationError) - | Expr_when (e1, _, _) -> translate_expr node args e1 - | Expr_merge (x, _) -> raise NormalizationError - | Expr_appl (id, e, _) when Basic_library.is_internal_fun id -> - let nd = node_from_name id in - Fun (node_name nd, List.map (translate_expr node args) (expr_list_of_expr e)) - | Expr_ite (g,t,e) -> ( - (* special treatment depending on the active backend. For horn backend, ite - are preserved in expression. While they are removed for C or Java - backends. *) - match !Options.output with - | "horn" -> - Fun ("ite", [translate_expr node args g; translate_expr node args t; translate_expr node args e]) - | ("C" | "java") when ite -> - Fun ("ite", [translate_expr node args g; translate_expr node args t; translate_expr node args e]) - | _ -> - (Format.eprintf "option:%s@." !Options.output; Printers.pp_expr Format.err_formatter expr; Format.pp_print_flush Format.err_formatter (); raise NormalizationError) - ) - | _ -> raise NormalizationError + let value_desc = + match expr.expr_desc with + | Expr_const v -> Cst v + | Expr_ident x -> (translate_ident node args x).value_desc + | Expr_array el -> Array (List.map (translate_expr node args) el) + | Expr_access (t, i) -> Access (translate_expr node args t, translate_expr node args (expr_of_dimension i)) + | Expr_power (e, n) -> Power (translate_expr node args e, translate_expr node args (expr_of_dimension n)) + | Expr_tuple _ + | Expr_arrow _ + | Expr_fby _ + | Expr_pre _ -> (Printers.pp_expr Format.err_formatter expr; Format.pp_print_flush Format.err_formatter (); raise NormalizationError) + | Expr_when (e1, _, _) -> (translate_expr node args e1).value_desc + | Expr_merge (x, _) -> raise NormalizationError + | Expr_appl (id, e, _) when Basic_library.is_expr_internal_fun expr -> + let nd = node_from_name id in + Fun (node_name nd, List.map (translate_expr node args) (expr_list_of_expr e)) + | Expr_ite (g,t,e) -> ( + (* special treatment depending on the active backend. For horn backend, ite + are preserved in expression. While they are removed for C or Java + backends. *) + match !Options.output with | "horn" -> + Fun ("ite", [translate_expr node args g; translate_expr node args t; translate_expr node args e]) + | "C" | "java" | _ -> + (Printers.pp_expr Format.err_formatter expr; Format.pp_print_flush Format.err_formatter (); raise NormalizationError) + ) + | _ -> raise NormalizationError + in + mk_val value_desc expr.expr_type let translate_guard node args expr = match expr.expr_desc with @@ -334,8 +376,7 @@ let rec translate_act node ((m, si, j, d, s) as args) (y, expr) = conditional g [translate_act node args (y, t)] [translate_act node args (y, e)] | Expr_merge (x, hl) -> MBranch (translate_ident node args x, List.map (fun (t, h) -> t, [translate_act node args (y, h)]) hl) - | _ -> - MLocalAssign (y, translate_expr node args expr) + | _ -> MLocalAssign (y, translate_expr node args expr) let reset_instance node args i r c = match r with @@ -371,7 +412,7 @@ let translate_eq node ((m, si, j, d, s) as args) eq = d, control_on_clock node args eq.eq_rhs.expr_clock (MStateAssign (var_x, translate_expr node args e2)) :: s) - | p , Expr_appl (f, arg, r) when not (Basic_library.is_internal_fun f) -> + | p , Expr_appl (f, arg, r) when not (Basic_library.is_expr_internal_fun eq.eq_rhs) -> let var_p = List.map (fun v -> get_node_var v node) p in let el = expr_list_of_expr arg in let vl = List.map (translate_expr node args) el in @@ -421,7 +462,7 @@ let translate_eq node ((m, si, j, d, s) as args) eq = ) | _ -> begin - Format.eprintf "unsupported equation: %a@?" Printers.pp_node_eq eq; + Format.eprintf "internal error: Machine_code.translate_eq %a@?" Printers.pp_node_eq eq; assert false end @@ -444,9 +485,9 @@ let find_eq xl eqs = to the computed schedule [sch] *) let sort_equations_from_schedule nd sch = -(*Format.eprintf "%s schedule: %a@." - nd.node_id - (Utils.fprintf_list ~sep:" ; " Scheduling.pp_eq_schedule) sch;*) + (* Format.eprintf "%s schedule: %a@." *) + (* nd.node_id *) + (* (Utils.fprintf_list ~sep:" ; " Scheduling.pp_eq_schedule) sch; *) let split_eqs = Splitting.tuple_split_eq_list (get_node_eqs nd) in let eqs_rev, remainder = List.fold_left @@ -554,32 +595,49 @@ let get_const_assign m id = with Not_found -> assert false -let value_of_ident m id = +let value_of_ident loc m id = (* is is a state var *) try - StateVar (List.find (fun v -> v.var_id = id) m.mmemory) + let v = List.find (fun v -> v.var_id = id) m.mmemory + in mk_val (StateVar v) v.var_type with Not_found -> - try (* id is a node var *) - LocalVar (get_node_var id m.mname) + try (* id is a node var *) + let v = get_node_var id m.mname + in mk_val (LocalVar v) v.var_type with Not_found -> try (* id is a constant *) - LocalVar (Corelang.var_decl_of_const (const_of_top (Hashtbl.find Corelang.consts_table id))) + let c = Corelang.var_decl_of_const (const_of_top (Hashtbl.find Corelang.consts_table id)) + in mk_val (LocalVar c) c.var_type with Not_found -> (* id is a tag *) - Cst (Const_tag id) + let t = Const_tag id + in mk_val (Cst t) (Typing.type_const loc t) + +(* type of internal fun used in dimension expression *) +let type_of_value_appl f args = + if List.mem f Basic_library.arith_funs + then (List.hd args).value_type + else Type_predef.type_bool let rec value_of_dimension m dim = match dim.Dimension.dim_desc with - | Dimension.Dbool b -> Cst (Const_tag (if b then Corelang.tag_true else Corelang.tag_false)) - | Dimension.Dint i -> Cst (Const_int i) - | Dimension.Dident v -> value_of_ident m v - | Dimension.Dappl (f, args) -> Fun (f, List.map (value_of_dimension m) args) - | Dimension.Dite (i, t, e) -> Fun ("ite", List.map (value_of_dimension m) [i; t; e]) + | Dimension.Dbool b -> + mk_val (Cst (Const_tag (if b then Corelang.tag_true else Corelang.tag_false))) Type_predef.type_bool + | Dimension.Dint i -> + mk_val (Cst (Const_int i)) Type_predef.type_int + | Dimension.Dident v -> value_of_ident dim.Dimension.dim_loc m v + | Dimension.Dappl (f, args) -> + let vargs = List.map (value_of_dimension m) args + in mk_val (Fun (f, vargs)) (type_of_value_appl f vargs) + | Dimension.Dite (i, t, e) -> + (match List.map (value_of_dimension m) [i; t; e] with + | [vi; vt; ve] -> mk_val (Fun ("ite", [vi; vt; ve])) vt.value_type + | _ -> assert false) | Dimension.Dlink dim' -> value_of_dimension m dim' | _ -> assert false let rec dimension_of_value value = - match value with + match value.value_desc with | Cst (Const_tag t) when t = Corelang.tag_true -> Dimension.mkdim_bool Location.dummy_loc true | Cst (Const_tag t) when t = Corelang.tag_false -> Dimension.mkdim_bool Location.dummy_loc false | Cst (Const_int i) -> Dimension.mkdim_int Location.dummy_loc i diff --git a/src/main_lustre_compiler.ml b/src/main_lustre_compiler.ml index a0d5b62313c826a5a41deca08c5922e62fa700e3..a44cd04ccd44517e18d5acdb37062d60d59baba8 100644 --- a/src/main_lustre_compiler.ml +++ b/src/main_lustre_compiler.ml @@ -15,8 +15,10 @@ open Log open Utils open LustreSpec open Compiler_common + +exception StopPhase1 of program -let usage = "Usage: lustrec [options] <source-file>" +let usage = "Usage: lustrec [options] \x1b[4msource file\x1b[0m" let extensions = [".ec"; ".lus"; ".lusi"] @@ -86,19 +88,12 @@ let compile_source_to_header prog computed_types_env computed_clocks_env dirname end +(* From prog to prog *) +let stage1 prog dirname basename = + (* Removing automata *) + let prog = expand_automata prog in -(* compile a .lus source file *) -let rec compile_source dirname basename extension = - - Log.report ~level:1 (fun fmt -> fprintf fmt "@[<v>"); - - (* Parsing source *) - let prog = parse_source (dirname ^ "/" ^ basename ^ extension) in - - (* Removing automata *) - let prog = Automata.expand_decls prog in - - Log.report ~level:4 (fun fmt -> fprintf fmt "After automata expansion:@.@[<v 2>@ %a@]@," Printers.pp_prog prog); + Log.report ~level:4 (fun fmt -> fprintf fmt ".. after automata expansion:@.@[<v 2>@ %a@]@," Printers.pp_prog prog); (* Importing source *) let _ = Modules.load_program ISet.empty prog in @@ -120,26 +115,40 @@ let rec compile_source dirname basename extension = in (* Checking stateless/stateful status *) - check_stateless_decls prog; + if Scopes.Plugin.is_active () then + force_stateful_decls prog + else + check_stateless_decls prog; (* Typing *) let computed_types_env = type_decls type_env prog in - + (* Clock calculus *) let computed_clocks_env = clock_decls clock_env prog in (* Generating a .lusi header file only *) if !Options.lusi then - begin - let lusi_ext = extension ^ "i" in - Log.report ~level:1 (fun fmt -> fprintf fmt ".. generating interface file %s@," (dirname ^ "/" ^ basename ^ lusi_ext)); - print_lusi prog dirname basename lusi_ext; - Log.report ~level:1 (fun fmt -> fprintf fmt ".. done !@ @]@."); - exit 0 - end; + (* We stop here the processing and produce the current prog. It will be + exported as a lusi *) + raise (StopPhase1 prog); + (* Optimization of prog: + - Unfold consts + - eliminate trivial expressions + *) + (* + let prog = + if !Options.const_unfold || !Options.optimization >= 5 then + begin + Log.report ~level:1 (fun fmt -> fprintf fmt ".. eliminating constants and aliases@,"); + Optimize_prog.prog_unfold_consts prog + end + else + prog + in + *) (* Delay calculus *) - (* TO BE DONE LATER (Xavier) + (* if(!Options.delay_calculus) then begin @@ -159,13 +168,8 @@ let rec compile_source dirname basename extension = (* Compatibility with Lusi *) (* Checking the existence of a lusi (Lustre Interface file) *) - (match !Options.output with - "C" -> - begin - let extension = ".lusi" in - compile_source_to_header prog computed_types_env computed_clocks_env dirname basename extension; - end - |_ -> ()); + let extension = ".lusi" in + compile_source_to_header prog computed_types_env computed_clocks_env dirname basename extension; Typing.uneval_prog_generics prog; Clock_calculus.uneval_prog_generics prog; @@ -184,12 +188,13 @@ let rec compile_source dirname basename extension = !Options.main_node orig prog type_env clock_env end; - -(*Format.eprintf "Inliner.global_inline<<@.%a@.>>@." Printers.pp_prog prog;*) + (* Computes and stores generic calls for each node, only useful for ANSI C90 compliant generic node compilation *) if !Options.ansi then Causality.NodeDep.compute_generic_calls prog; - (*Hashtbl.iter (fun id td -> match td.Corelang.top_decl_desc with Corelang.Node nd -> Format.eprintf "%s calls %a" id Causality.NodeDep.pp_generic_calls nd | _ -> ()) Corelang.node_table;*) + (*Hashtbl.iter (fun id td -> match td.Corelang.top_decl_desc with + Corelang.Node nd -> Format.eprintf "%s calls %a" id + Causality.NodeDep.pp_generic_calls nd | _ -> ()) Corelang.node_table;*) (* Normalization phase *) Log.report ~level:1 (fun fmt -> fprintf fmt ".. normalization@,"); @@ -197,8 +202,22 @@ let rec compile_source dirname basename extension = if !Options.output = "lustre" then Normalization.unfold_arrow_active := false; let prog = Normalization.normalize_prog prog in + Log.report ~level:2 (fun fmt -> fprintf fmt "@[<v 2>@ %a@]@," Printers.pp_prog prog); + let prog = + if !Options.mpfr + then + begin + Log.report ~level:1 (fun fmt -> fprintf fmt ".. targetting MPFR library@,"); + Mpfr.inject_prog prog + end + else + begin + Log.report ~level:1 (fun fmt -> fprintf fmt ".. keeping FP numbers@,"); + prog + end in Log.report ~level:2 (fun fmt -> fprintf fmt "@[<v 2>@ %a@]@," Printers.pp_prog prog); + (* Checking array accesses *) if !Options.check then begin @@ -206,35 +225,33 @@ let rec compile_source dirname basename extension = Access.check_prog prog; end; + prog, dependencies + +(* from source to machine code, with optimization *) +let stage2 prog = (* Computation of node equation scheduling. It also breaks dependency cycles and warns about unused input or memory variables *) Log.report ~level:1 (fun fmt -> fprintf fmt ".. scheduling@,"); let prog, node_schs = Scheduling.schedule_prog prog in - Log.report ~level:1 (fun fmt -> fprintf fmt "@[<v 2>@ %a@]@," Scheduling.pp_warning_unused node_schs); + Log.report ~level:1 (fun fmt -> fprintf fmt "%a" Scheduling.pp_warning_unused node_schs); Log.report ~level:3 (fun fmt -> fprintf fmt "@[<v 2>@ %a@]@," Scheduling.pp_schedule node_schs); Log.report ~level:3 (fun fmt -> fprintf fmt "@[<v 2>@ %a@]@," Scheduling.pp_fanin_table node_schs); + Log.report ~level:5 (fun fmt -> fprintf fmt "@[<v 2>@ %a@]@," Scheduling.pp_dep_graph node_schs); Log.report ~level:3 (fun fmt -> fprintf fmt "@[<v 2>@ %a@]@," Printers.pp_prog prog); - (* Optimization of prog: - - Unfold consts - - eliminate trivial expressions - *) - let prog = - if !Options.optimization >= 5 then - begin - Log.report ~level:1 (fun fmt -> fprintf fmt ".. constants elimination@,"); - Optimize_prog.prog_unfold_consts prog - end - else - prog - in + + (* TODO Salsa optimize prog: + - emits warning for programs with pre inside expressions + - make sure each node arguments and memory is bounded by a local annotation + - introduce fresh local variables for each real pure subexpression + *) (* DFS with modular code generation *) - Log.report ~level:1 (fun fmt -> fprintf fmt ".. machines generation@,"); + Log.report ~level:1 (fun fmt -> fprintf fmt ".. machines generation@ "); let machine_code = Machine_code.translate_prog prog node_schs in - Log.report ~level:2 (fun fmt -> fprintf fmt "@[<v 2>@ %a@]@," + Log.report ~level:4 (fun fmt -> fprintf fmt "@[<v 2>@ %a@]@," (Utils.fprintf_list ~sep:"@ " Machine_code.pp_machine) - machine_code); + machine_code); (* Optimize machine code *) let machine_code = @@ -246,41 +263,66 @@ let rec compile_source dirname basename extension = else machine_code in - (* Optimize machine code *) - let machine_code = + let machine_code, removed_table = if !Options.optimization >= 2 && !Options.output <> "horn" then begin - Log.report ~level:1 (fun fmt -> fprintf fmt ".. machines optimization (phase 1)@,"); + Log.report ~level:1 (fun fmt -> fprintf fmt ".. machines optimization (phase 1)@ "); Optimize_machine.machines_unfold (Corelang.get_consts prog) node_schs machine_code end else - machine_code - in + machine_code, IMap.empty + in (* Optimize machine code *) - let machine_code = + let machine_code = if !Options.optimization >= 3 && !Options.output <> "horn" then begin - Log.report ~level:1 (fun fmt -> fprintf fmt ".. machines optimization (phase 2)@,"); - Optimize_machine.machines_fusion (Optimize_machine.machines_reuse_variables machine_code node_schs) + Log.report ~level:1 (fun fmt -> fprintf fmt ".. machines optimization (phase 2)@ "); + let node_schs = Scheduling.remove_prog_inlined_locals removed_table node_schs in + let reuse_tables = Scheduling.compute_prog_reuse_table node_schs in + Optimize_machine.machines_fusion (Optimize_machine.machines_reuse_variables machine_code reuse_tables) end else machine_code in + + (* Salsa optimize machine code *) + (* + let machine_code = + if !Options.salsa_enabled then + begin + check_main (); + Log.report ~level:1 (fun fmt -> fprintf fmt ".. salsa machines optimization (phase 3)@ "); + (* Selecting float constants for Salsa *) + let constEnv = List.fold_left ( + fun accu c_topdecl -> + match c_topdecl.top_decl_desc with + | Const c when Types.is_real_type c.const_type -> + (c.const_id, c.const_value) :: accu + | _ -> accu + ) [] (Corelang.get_consts prog) + in + List.map + (Machine_salsa_opt.machine_t2machine_t_optimized_by_salsa constEnv) + machine_code + end + else + machine_code + in + Log.report ~level:3 (fun fmt -> fprintf fmt "@[<v 2>@ %a@]@ " + (Utils.fprintf_list ~sep:"@ " Machine_code.pp_machine) + machine_code); + *) + machine_code - if !Options.optimization >= 2 then - begin - Log.report ~level:3 (fun fmt -> fprintf fmt "@[<v 2>@ %a@]@," - (Utils.fprintf_list ~sep:"@ " Machine_code.pp_machine) - machine_code); - end; - (* Printing code *) +(* printing code *) +let stage3 prog machine_code dependencies basename = let basename = Filename.basename basename in let destname = !Options.dest_dir ^ "/" ^ basename in - let _ = match !Options.output with - | "C" -> - begin + match !Options.output with + "C" -> + begin let alloc_header_file = destname ^ "_alloc.h" in (* Could be changed *) let source_lib_file = destname ^ ".c" in (* Could be changed *) let source_main_file = destname ^ "_main.c" in (* Could be changed *) @@ -292,7 +334,7 @@ let rec compile_source dirname basename extension = end | "java" -> begin - failwith "Sorry, but not yet supported !" + (Format.eprintf "internal error: sorry, but not yet supported !"; assert false) (*let source_file = basename ^ ".java" in Log.report ~level:1 (fun fmt -> fprintf fmt ".. opening file %s@,@?" source_file); let source_out = open_out source_file in @@ -301,7 +343,7 @@ let rec compile_source dirname basename extension = Java_backend.translate_to_java source_fmt basename normalized_prog machine_code;*) end | "horn" -> - begin + begin let source_file = destname ^ ".smt2" in (* Could be changed *) let source_out = open_out source_file in let fmt = formatter_of_out_channel source_out in @@ -309,7 +351,7 @@ let rec compile_source dirname basename extension = Horn_backend.translate fmt basename prog machine_code; (* Tracability file if option is activated *) if !Options.traces then ( - let traces_file = destname ^ ".traces.xml" in (* Could be changed *) + let traces_file = destname ^ ".traces" in (* Could be changed *) let traces_out = open_out traces_file in let fmt = formatter_of_out_channel traces_out in Log.report ~level:1 (fun fmt -> fprintf fmt ".. tracing info@,"); @@ -327,12 +369,64 @@ let rec compile_source dirname basename extension = end | _ -> assert false + +(* compile a .lus source file *) +let rec compile_source dirname basename extension = + let source_name = dirname ^ "/" ^ basename ^ extension in + + Log.report ~level:1 (fun fmt -> fprintf fmt "@[<v>"); + + (* Parsing source *) + let prog = parse_source source_name in + + let prog = + if !Options.mpfr then + Mpfr.mpfr_module::prog + else + prog + in + let prog, dependencies = + try + stage1 prog dirname basename + with StopPhase1 prog -> ( + if !Options.lusi then + begin + let lusi_ext = extension ^ "i" in + Log.report ~level:1 (fun fmt -> fprintf fmt ".. generating interface file %s@," (basename ^ lusi_ext)); + print_lusi prog dirname basename lusi_ext; + Log.report ~level:1 (fun fmt -> fprintf fmt ".. done !@ @]@."); + exit 0 + end + else + assert false + ) in - begin - Log.report ~level:1 (fun fmt -> fprintf fmt ".. done @ @]@."); - (* We stop the process here *) - exit 0 - end + + let machine_code = + stage2 prog + in + if Scopes.Plugin.show_scopes () then + begin + let all_scopes = Scopes.compute_scopes prog !Options.main_node in + (* Printing scopes *) + if !Options.verbose_level >= 1 then + Format.printf "Possible scopes are:@ "; + Format.printf "@[<v>%a@ @]@.@?" Scopes.print_scopes all_scopes; + exit 0 + + end; + + let machine_code = + if Scopes.Plugin.is_active () then + Scopes.Plugin.process_scopes !Options.main_node prog machine_code + else + machine_code + in + + stage3 prog machine_code dependencies basename; + Log.report ~level:1 (fun fmt -> fprintf fmt ".. done @ @]@."); + (* We stop the process here *) + exit 0 let compile dirname basename extension = match extension with @@ -356,12 +450,22 @@ let anonymous filename = raise (Arg.Bad ("Can only compile *.lusi, *.lus or *.ec files")) let _ = + Global.initialize (); Corelang.add_internal_funs (); try Printexc.record_backtrace true; - Arg.parse Options.options anonymous usage + + let options = Options.options @ + List.flatten ( + List.map Options.plugin_opt [ + Scopes.Plugin.name, Scopes.Plugin.activate, Scopes.Plugin.options + ] + ) + in + + Arg.parse options anonymous usage with - | Parse.Syntax_err _ | Lexer_lustre.Error _ + | Parse.Error _ | Types.Error (_,_) | Clocks.Error (_,_) | Corelang.Error _ (*| Task_set.Error _*) | Causality.Cycle _ -> exit 1 diff --git a/src/normalization.ml b/src/normalization.ml index 30e4066f57552477226934afcb04387730be9769..968fb2cc91be5da771271f536af3b8566b05d135 100644 --- a/src/normalization.ml +++ b/src/normalization.ml @@ -127,16 +127,29 @@ let mk_expr_alias node (defs, vars) expr = (* Create an alias for [expr], if [expr] is not already an alias (i.e. an ident) and [opt] is true *) -let mk_expr_alias_opt opt node defvars expr = +let mk_expr_alias_opt opt node (defs, vars) expr = +(*Format.eprintf "mk_expr_alias_opt %B %a %a %a@." opt Printers.pp_expr expr Types.print_ty expr.expr_type Clocks.print_ck expr.expr_clock;*) match expr.expr_desc with | Expr_ident alias -> - defvars, expr + (defs, vars), expr | _ -> - if opt - then - mk_expr_alias node defvars expr - else - defvars, expr + match get_expr_alias defs expr with + | Some eq -> + let aliases = List.map (fun id -> List.find (fun v -> v.var_id = id) vars) eq.eq_lhs in + (defs, vars), replace_expr aliases expr + | None -> + if opt + then + let new_aliases = + List.map2 + (mk_fresh_var node expr.expr_loc) + (Types.type_list_of_type expr.expr_type) + (Clocks.clock_list_of_clock expr.expr_clock) in + let new_def = + mkeq expr.expr_loc (List.map (fun v -> v.var_id) new_aliases, expr) + in (new_def::defs, new_aliases@vars), replace_expr new_aliases expr + else + (defs, vars), expr (* Create a (normalized) expression from [ref_e], replacing description with [norm_d], @@ -159,7 +172,7 @@ let rec normalize_list alias node offsets norm_element defvars elist = ) elist (defvars, []) let rec normalize_expr ?(alias=true) node offsets defvars expr = -(* Format.eprintf "normalize %B %a [%a]@." alias Printers.pp_expr expr (Utils.fprintf_list ~sep:"," Dimension.pp_dimension) offsets;*) +(*Format.eprintf "normalize %B %a:%a [%a]@." alias Printers.pp_expr expr Types.print_ty expr.expr_type (Utils.fprintf_list ~sep:"," Dimension.pp_dimension) offsets;*) match expr.expr_desc with | Expr_const _ | Expr_ident _ -> defvars, unfold_offsets expr offsets @@ -180,7 +193,7 @@ let rec normalize_expr ?(alias=true) node offsets defvars expr = normalize_list alias node offsets (fun alias -> normalize_expr ~alias:alias) defvars elist in defvars, mk_norm_expr offsets expr (Expr_tuple norm_elist) | Expr_appl (id, args, None) - when Basic_library.is_internal_fun id + when Basic_library.is_homomorphic_fun id && Types.is_array_type expr.expr_type -> let defvars, norm_args = normalize_list @@ -192,7 +205,7 @@ let rec normalize_expr ?(alias=true) node offsets defvars expr = (expr_list_of_expr args) in defvars, mk_norm_expr offsets expr (Expr_appl (id, expr_of_expr_list args.expr_loc norm_args, None)) - | Expr_appl (id, args, None) when Basic_library.is_internal_fun id -> + | Expr_appl (id, args, None) when Basic_library.is_expr_internal_fun expr -> let defvars, norm_args = normalize_expr ~alias:true node offsets defvars args in defvars, mk_norm_expr offsets expr (Expr_appl (id, norm_args, None)) | Expr_appl (id, args, r) -> @@ -203,7 +216,7 @@ let rec normalize_expr ?(alias=true) node offsets defvars expr = let defvars, norm_expr = normalize_expr node [] defvars norm_expr in normalize_expr ~alias:alias node offsets defvars norm_expr else - mk_expr_alias_opt (alias && not (Basic_library.is_internal_fun id)) node defvars norm_expr + mk_expr_alias_opt (alias && not (Basic_library.is_expr_internal_fun expr)) node defvars norm_expr | Expr_arrow (e1,e2) when !unfold_arrow_active && not (is_expr_once expr) -> (* Here we differ from Colaco paper: arrows are pushed to the top *) normalize_expr ~alias:alias node offsets defvars (unfold_arrow expr) | Expr_arrow (e1,e2) -> @@ -251,7 +264,7 @@ and normalize_branches node offsets defvars hl = hl (defvars, []) and normalize_array_expr ?(alias=true) node offsets defvars expr = -(* Format.eprintf "normalize_array %B %a [%a]@." alias Printers.pp_expr expr (Utils.fprintf_list ~sep:"," Dimension.pp_dimension) offsets;*) + (*Format.eprintf "normalize_array %B %a [%a]@." alias Printers.pp_expr expr (Utils.fprintf_list ~sep:"," Dimension.pp_dimension) offsets;*) match expr.expr_desc with | Expr_power (e1, d) when offsets = [] -> let defvars, norm_e1 = normalize_expr node offsets defvars e1 in @@ -262,7 +275,7 @@ and normalize_array_expr ?(alias=true) node offsets defvars expr = | Expr_array elist when offsets = [] -> let defvars, norm_elist = normalize_list alias node offsets (fun _ -> normalize_array_expr ~alias:true) defvars elist in defvars, mk_norm_expr offsets expr (Expr_array norm_elist) - | Expr_appl (id, args, None) when Basic_library.is_internal_fun id -> + | Expr_appl (id, args, None) when Basic_library.is_expr_internal_fun expr -> let defvars, norm_args = normalize_list alias node offsets (fun _ -> normalize_array_expr ~alias:true) defvars (expr_list_of_expr args) in defvars, mk_norm_expr offsets expr (Expr_appl (id, expr_of_expr_list args.expr_loc norm_args, None)) | _ -> normalize_expr ~alias:alias node offsets defvars expr @@ -310,6 +323,7 @@ let decouple_outputs node defvars eq = defvars', {eq with eq_lhs = lhs' } let rec normalize_eq node defvars eq = +(*Format.eprintf "normalize_eq %a@." Types.print_ty eq.eq_rhs.expr_type;*) match eq.eq_rhs.expr_desc with | Expr_pre _ | Expr_fby _ -> @@ -321,7 +335,7 @@ let rec normalize_eq node defvars eq = let (defs', vars'), norm_rhs = normalize_array_expr ~alias:false node [] defvars eq.eq_rhs in let norm_eq = { eq with eq_rhs = norm_rhs } in (norm_eq::defs', vars') - | Expr_appl (id, _, None) when Basic_library.is_internal_fun id && Types.is_array_type eq.eq_rhs.expr_type -> + | Expr_appl (id, _, None) when Basic_library.is_homomorphic_fun id && Types.is_array_type eq.eq_rhs.expr_type -> let (defs', vars'), norm_rhs = normalize_array_expr ~alias:false node [] defvars eq.eq_rhs in let norm_eq = { eq with eq_rhs = norm_rhs } in (norm_eq::defs', vars') @@ -353,10 +367,10 @@ let normalize_node node = List.fold_left ( fun (vars, def_accu, assert_accu) assert_ -> let assert_expr = assert_.assert_expr in - let (defs, vars'), expr = - normalize_expr - ~alias:true - node + let (defs, vars'), expr = + normalize_expr + ~alias:false + node [] (* empty offset for arrays *) ([], vars) (* defvar only contains vars *) assert_expr diff --git a/src/optimize_machine.ml b/src/optimize_machine.ml index 48a36f9645d02443478077b6814609477a868e6a..c87b86b76823f051d468924071381605adeb0dc3 100644 --- a/src/optimize_machine.ml +++ b/src/optimize_machine.ml @@ -26,7 +26,8 @@ let pp_elim fmt elim = let rec eliminate elim instr = let e_expr = eliminate_expr elim in - match instr with + match instr with + | MComment _ -> instr | MLocalAssign (i,v) -> MLocalAssign (i, e_expr v) | MStateAssign (i,v) -> MStateAssign (i, e_expr v) | MReset i -> instr @@ -41,50 +42,55 @@ let rec eliminate elim instr = ) and eliminate_expr elim expr = - match expr with - | StateVar v + match expr.value_desc with | LocalVar v -> (try IMap.find v.var_id elim with Not_found -> expr) - | Fun (id, vl) -> Fun (id, List.map (eliminate_expr elim) vl) - | Array(vl) -> Array(List.map (eliminate_expr elim) vl) - | Access(v1, v2) -> Access(eliminate_expr elim v1, eliminate_expr elim v2) - | Power(v1, v2) -> Power(eliminate_expr elim v1, eliminate_expr elim v2) - | Cst _ -> expr + | Fun (id, vl) -> {expr with value_desc = Fun (id, List.map (eliminate_expr elim) vl)} + | Array(vl) -> {expr with value_desc = Array(List.map (eliminate_expr elim) vl)} + | Access(v1, v2) -> { expr with value_desc = Access(eliminate_expr elim v1, eliminate_expr elim v2)} + | Power(v1, v2) -> { expr with value_desc = Power(eliminate_expr elim v1, eliminate_expr elim v2)} + | Cst _ | StateVar _ -> expr let eliminate_dim elim dim = Dimension.expr_replace_expr (fun v -> try dimension_of_value (IMap.find v elim) with Not_found -> mkdim_ident dim.dim_loc v) dim let unfold_expr_offset m offset expr = - List.fold_left (fun res -> (function Index i -> Access(res, value_of_dimension m i) | Field f -> failwith "not yet implemented")) expr offset + List.fold_left + (fun res -> (function | Index i -> mk_val (Access (res, value_of_dimension m i)) + (Types.array_element_type res.value_type) + | Field f -> Format.eprintf "internal error: not yet implemented !"; assert false)) + expr offset -let rec simplify_cst_expr m offset cst = +let rec simplify_cst_expr m offset typ cst = match offset, cst with | [] , _ - -> Cst cst + -> mk_val (Cst cst) typ | Index i :: q, Const_array cl when Dimension.is_dimension_const i - -> simplify_cst_expr m q (List.nth cl (Dimension.size_const_dimension i)) + -> let elt_typ = Types.array_element_type typ in + simplify_cst_expr m q elt_typ (List.nth cl (Dimension.size_const_dimension i)) | Index i :: q, Const_array cl - -> unfold_expr_offset m [Index i] (Array (List.map (simplify_cst_expr m q) cl)) + -> let elt_typ = Types.array_element_type typ in + unfold_expr_offset m [Index i] (mk_val (Array (List.map (simplify_cst_expr m q elt_typ) cl)) typ) | Field f :: q, Const_struct fl - -> simplify_cst_expr m q (List.assoc f fl) + -> let fld_typ = Types.struct_field_type typ f in + simplify_cst_expr m q fld_typ (List.assoc f fl) | _ -> (Format.eprintf "internal error: Optimize_machine.simplify_cst_expr %a@." Printers.pp_const cst; assert false) let simplify_expr_offset m expr = let rec simplify offset expr = - match offset, expr with + match offset, expr.value_desc with | Field f ::q , _ -> failwith "not yet implemented" - | _ , Fun (id, vl) when Basic_library.is_internal_fun id - -> Fun (id, List.map (simplify offset) vl) + | _ , Fun (id, vl) when Basic_library.is_value_internal_fun expr + -> mk_val (Fun (id, List.map (simplify offset) vl)) expr.value_type | _ , Fun _ | _ , StateVar _ | _ , LocalVar _ -> unfold_expr_offset m offset expr - | _ , Cst cst -> simplify_cst_expr m offset cst + | _ , Cst cst -> simplify_cst_expr m offset expr.value_type cst | _ , Access (expr, i) -> simplify (Index (dimension_of_value i) :: offset) expr | [] , _ -> expr | Index _ :: q, Power (expr, _) -> simplify q expr | Index i :: q, Array vl when Dimension.is_dimension_const i -> simplify q (List.nth vl (Dimension.size_const_dimension i)) - | Index i :: q, Array vl -> unfold_expr_offset m [Index i] (Array (List.map (simplify q) vl)) - | _ -> (Format.eprintf "internal error: Optimize_machine.simplify_expr_offset %a@." pp_val expr; assert false) + | Index i :: q, Array vl -> unfold_expr_offset m [Index i] (mk_val (Array (List.map (simplify q) vl)) expr.value_type) (*Format.eprintf "simplify_expr %a %a = %a@." pp_val expr (Utils.fprintf_list ~sep:"" Printers.pp_offset) offset pp_val res; res) with e -> (Format.eprintf "simplify_expr %a %a = <FAIL>@." pp_val expr (Utils.fprintf_list ~sep:"" Printers.pp_offset) offset; raise e*) in simplify [] expr @@ -97,15 +103,15 @@ let rec simplify_instr_offset m instr = | MStep (outputs, id, inputs) -> MStep (outputs, id, List.map (simplify_expr_offset m) inputs) | MBranch (cond, brl) -> MBranch(simplify_expr_offset m cond, List.map (fun (l, il) -> l, simplify_instrs_offset m il) brl) + | MComment _ -> instr and simplify_instrs_offset m instrs = List.map (simplify_instr_offset m) instrs let is_scalar_const c = match c with - | Const_int _ | Const_real _ - | Const_float _ + | Const_int _ | Const_tag _ -> true | _ -> false @@ -119,7 +125,6 @@ let is_unfoldable_expr fanin expr = match offset, cst with | _ , Const_int _ | _ , Const_real _ - | _ , Const_float _ | _ , Const_tag _ -> true | Field f :: q, Const_struct fl -> unfold_const q (List.assoc f fl) | [] , Const_struct _ -> false @@ -128,7 +133,7 @@ let is_unfoldable_expr fanin expr = | _ , Const_array _ -> false | _ -> assert false in let rec unfold offset expr = - match offset, expr with + match offset, expr.value_desc with | _ , Cst cst -> unfold_const offset cst | _ , LocalVar _ | _ , StateVar _ -> true @@ -139,28 +144,22 @@ let is_unfoldable_expr fanin expr = -> unfold q (List.nth vl (Dimension.size_const_dimension i)) | _ , Array _ -> false | _ , Access (v, i) -> unfold (Index (dimension_of_value i) :: offset) v - | _ , Fun (id, vl) when fanin < 2 && Basic_library.is_internal_fun id + | _ , Fun (id, vl) when fanin < 2 && Basic_library.is_value_internal_fun expr -> List.for_all (unfold offset) vl | _ , Fun _ -> false | _ -> assert false in unfold [] expr -let unfoldable_assign fanin v expr = +let basic_unfoldable_assign fanin v expr = try let d = Hashtbl.find fanin v.var_id in is_unfoldable_expr d expr with Not_found -> false -(* + let unfoldable_assign fanin v expr = - try - let d = Hashtbl.find fanin v.var_id - in is_basic_expr expr || - match expr with - | Cst c when d < 2 -> true - | Fun (id, _) when d < 2 && Basic_library.is_internal_fun id -> true - | _ -> false - with Not_found -> false -*) + (if !Options.mpfr then Mpfr.unfoldable_value expr else true) +&& basic_unfoldable_assign fanin v expr + let merge_elim elim1 elim2 = let merge k e1 e2 = match e1, e2 with @@ -189,8 +188,8 @@ and instr_unfold fanin instrs elim instr = (* Format.eprintf "SHOULD WE STORE THE EXPRESSION IN INSTR %a TO ELIMINATE IT@." pp_instr instr;*) match instr with (* Simple cases*) - | MStep([v], id, vl) when Basic_library.is_internal_fun id - -> instr_unfold fanin instrs elim (MLocalAssign (v, Fun (id, vl))) + | MStep([v], id, vl) when Basic_library.is_value_internal_fun (mk_val (Fun (id, vl)) v.var_type) + -> instr_unfold fanin instrs elim (MLocalAssign (v, mk_val (Fun (id, vl)) v.var_type)) | MLocalAssign(v, expr) when unfoldable_assign fanin v expr -> (IMap.add v.var_id expr elim, instrs) | MBranch(g, hl) when false @@ -242,26 +241,29 @@ let machine_unfold fanin elim machine = mconst = mconst; minstances = minstances; mcalls = mcalls; - } + }, + elim_vars let instr_of_const top_const = let const = const_of_top top_const in let vdecl = mkvar_decl Location.dummy_loc (const.const_id, mktyp Location.dummy_loc Tydec_any, mkclock Location.dummy_loc Ckdec_any, true, None) in let vdecl = { vdecl with var_type = const.const_type } - in MLocalAssign (vdecl, Cst const.const_value) + in MLocalAssign (vdecl, mk_val (Cst const.const_value) vdecl.var_type) let machines_unfold consts node_schs machines = - List.map - (fun m -> - let fanin = (IMap.find m.mname.node_id node_schs).Scheduling.fanin_table in - let elim_consts, _ = instrs_unfold fanin IMap.empty (List.map instr_of_const consts) - in machine_unfold fanin elim_consts m) + List.fold_right (fun m (machines, removed) -> + let fanin = (IMap.find m.mname.node_id node_schs).Scheduling.fanin_table in + let elim_consts, _ = instrs_unfold fanin IMap.empty (List.map instr_of_const consts) in + let (m, removed_m) = machine_unfold fanin elim_consts m in + (m::machines, IMap.add m.mname.node_id removed_m removed) + ) machines + ([], IMap.empty) let get_assign_lhs instr = match instr with - | MLocalAssign(v, _) -> LocalVar v - | MStateAssign(v, _) -> StateVar v + | MLocalAssign(v, e) -> mk_val (LocalVar v) e.value_type + | MStateAssign(v, e) -> mk_val (StateVar v) e.value_type | _ -> assert false let get_assign_rhs instr = @@ -277,7 +279,7 @@ let is_assign instr = | _ -> false let mk_assign v e = - match v with + match v.value_desc with | LocalVar v -> MLocalAssign(v, e) | StateVar v -> MStateAssign(v, e) | _ -> assert false @@ -315,18 +317,19 @@ let subst_instr subst instrs instr = let e = get_assign_rhs instr in try let instr' = List.find (fun instr' -> is_assign instr' && get_assign_rhs instr' = e) instrs in - match v with + match v.value_desc with | LocalVar v -> IMap.add v.var_id (get_assign_lhs instr') subst, instrs - | StateVar v -> - (match get_assign_lhs instr' with + | StateVar stv -> + let lhs = get_assign_lhs instr' in + (match lhs.value_desc with | LocalVar v' -> - let instr = eliminate subst (mk_assign (StateVar v) (LocalVar v')) in + let instr = eliminate subst (mk_assign v lhs) in subst, instr :: instrs - | StateVar v' -> - let subst_v' = IMap.add v'.var_id (StateVar v) IMap.empty in + | StateVar stv' -> + let subst_v' = IMap.add stv'.var_id v IMap.empty in let instrs' = snd (List.fold_right (fun instr (ok, instrs) -> (ok || instr = instr', if ok then instr :: instrs else if instr = instr' then instrs else eliminate subst_v' instr :: instrs)) instrs (false, [])) in - IMap.add v'.var_id (StateVar v) subst, instr :: instrs' + IMap.add stv'.var_id v subst, instr :: instrs' | _ -> assert false) | _ -> assert false with Not_found -> subst, instr :: instrs @@ -341,8 +344,8 @@ let subst_instr subst instrs instr = let rec instr_cse (subst, instrs) instr = match instr with (* Simple cases*) - | MStep([v], id, vl) when Basic_library.is_internal_fun id - -> instr_cse (subst, instrs) (MLocalAssign (v, Fun (id, vl))) + | MStep([v], id, vl) when Basic_library.is_internal_fun id (List.map (fun v -> v.value_type) vl) + -> instr_cse (subst, instrs) (MLocalAssign (v, mk_val (Fun (id, vl)) v.var_type)) | MLocalAssign(v, expr) when is_unfoldable_expr 2 expr -> (IMap.add v.var_id expr subst, instr :: instrs) | _ when is_assign instr @@ -384,8 +387,8 @@ let machines_cse machines = (* checks whether an [instr] is skip and can be removed from program *) let rec instr_is_skip instr = match instr with - | MLocalAssign (i, LocalVar v) when i = v -> true - | MStateAssign (i, StateVar v) when i = v -> true + | MLocalAssign (i, { value_desc = (LocalVar v) ; _}) when i = v -> true + | MStateAssign (i, { value_desc = StateVar v; _}) when i = v -> true | MBranch (g, hl) -> List.for_all (fun (_, il) -> instrs_are_skip il) hl | _ -> false and instrs_are_skip instrs = @@ -396,8 +399,8 @@ let instr_cons instr cont = let rec instr_remove_skip instr cont = match instr with - | MLocalAssign (i, LocalVar v) when i = v -> cont - | MStateAssign (i, StateVar v) when i = v -> cont + | MLocalAssign (i, { value_desc = LocalVar v; _ }) when i = v -> cont + | MStateAssign (i, { value_desc = StateVar v; _ }) when i = v -> cont | MBranch (g, hl) -> MBranch (g, List.map (fun (h, il) -> (h, instrs_remove_skip il [])) hl) :: cont | _ -> instr::cont @@ -405,17 +408,18 @@ and instrs_remove_skip instrs cont = List.fold_right instr_remove_skip instrs cont let rec value_replace_var fvar value = - match value with + match value.value_desc with | Cst c -> value - | LocalVar v -> LocalVar (fvar v) + | LocalVar v -> { value with value_desc = LocalVar (fvar v) } | StateVar v -> value - | Fun (id, args) -> Fun (id, List.map (value_replace_var fvar) args) - | Array vl -> Array (List.map (value_replace_var fvar) vl) - | Access (t, i) -> Access(value_replace_var fvar t, i) - | Power (v, n) -> Power(value_replace_var fvar v, n) + | Fun (id, args) -> { value with value_desc = Fun (id, List.map (value_replace_var fvar) args) } + | Array vl -> { value with value_desc = Array (List.map (value_replace_var fvar) vl)} + | Access (t, i) -> { value with value_desc = Access(value_replace_var fvar t, i)} + | Power (v, n) -> { value with value_desc = Power(value_replace_var fvar v, n)} let rec instr_replace_var fvar instr cont = match instr with + | MComment _ -> instr_cons instr cont | MLocalAssign (i, v) -> instr_cons (MLocalAssign (fvar i, value_replace_var fvar v)) cont | MStateAssign (i, v) -> instr_cons (MStateAssign (i, value_replace_var fvar v)) cont | MReset i -> instr_cons instr cont @@ -457,10 +461,10 @@ let machine_reuse_variables m reuse = with Not_found -> v in machine_replace_variables fvar m -let machines_reuse_variables prog node_schs = +let machines_reuse_variables prog reuse_tables = List.map (fun m -> - machine_reuse_variables m (Utils.IMap.find m.mname.node_id node_schs).Scheduling.reuse_table + machine_reuse_variables m (Utils.IMap.find m.mname.node_id reuse_tables) ) prog let rec instr_assign res instr = @@ -476,8 +480,8 @@ and instrs_assign res instrs = let rec instr_constant_assign var instr = match instr with - | MLocalAssign (i, Cst (Const_tag _)) - | MStateAssign (i, Cst (Const_tag _)) -> i = var + | MLocalAssign (i, { value_desc = Cst (Const_tag _); _ }) + | MStateAssign (i, { value_desc = Cst (Const_tag _); _ }) -> i = var | MBranch (g, hl) -> List.for_all (fun (h, b) -> instrs_constant_assign var b) hl | _ -> false @@ -486,8 +490,8 @@ and instrs_constant_assign var instrs = let rec instr_reduce branches instr1 cont = match instr1 with - | MLocalAssign (_, Cst (Const_tag c)) -> instr1 :: (List.assoc c branches @ cont) - | MStateAssign (_, Cst (Const_tag c)) -> instr1 :: (List.assoc c branches @ cont) + | MLocalAssign (_, { value_desc = Cst (Const_tag c); _}) -> instr1 :: (List.assoc c branches @ cont) + | MStateAssign (_, { value_desc = Cst (Const_tag c); _}) -> instr1 :: (List.assoc c branches @ cont) | MBranch (g, hl) -> MBranch (g, List.map (fun (h, b) -> (h, instrs_reduce branches b [])) hl) :: cont | _ -> instr1 :: cont @@ -502,9 +506,9 @@ let rec instrs_fusion instrs = | [] | [_] -> instrs - | i1::(MBranch (LocalVar v, hl))::q when instr_constant_assign v i1 -> + | i1::(MBranch ({ value_desc = LocalVar v; _}, hl))::q when instr_constant_assign v i1 -> instr_reduce (List.map (fun (h, b) -> h, instrs_fusion b) hl) i1 (instrs_fusion q) - | i1::(MBranch (StateVar v, hl))::q when instr_constant_assign v i1 -> + | i1::(MBranch ({ value_desc = StateVar v; _}, hl))::q when instr_constant_assign v i1 -> instr_reduce (List.map (fun (h, b) -> h, instrs_fusion b) hl) i1 (instrs_fusion q) | i1::i2::q -> i1 :: instrs_fusion (i2::q) diff --git a/src/options.ml b/src/options.ml index 16ada24b2e0d51f8a03eb87cb560dc4d86a7c99a..8f40a9cf8d214c12799e8ee19d2171007adac83d 100755 --- a/src/options.ml +++ b/src/options.ml @@ -33,24 +33,36 @@ let witnesses = ref false let optimization = ref 2 let lusi = ref false let print_reuse = ref false -let traces = ref false +let const_unfold = ref false +let mpfr = ref false +let mpfr_prec = ref 0 -let horntraces = ref false +let traces = ref false let horn_cex = ref false let horn_query = ref true +let salsa_enabled = ref true +let set_mpfr prec = + if prec > 0 then ( + mpfr := true; + mpfr_prec := prec; + salsa_enabled := false; (* We deactivate salsa *) + ) + else + failwith "mpfr requires a positive integer" + let options = [ "-d", Arg.Set_string dest_dir, - "uses the specified directory as root for generated/imported object and C files (default: .)"; - "-node", Arg.Set_string main_node, "specifies the main node"; + "uses the specified directory \x1b[4mdir\x1b[0m as root for generated/imported object and C files <default: .>"; + "-node", Arg.Set_string main_node, "specifies the \x1b[4mmain\x1b[0m node"; "-init", Arg.Set delay_calculus, "performs an initialisation analysis for Lustre nodes <default: no analysis>"; "-dynamic", Arg.Clear static_mem, "specifies a dynamic allocation scheme for main Lustre node <default: static>"; - "-ansi", Arg.Set ansi, "specifies that generated C code is ansi C90 compliant <default: C99>"; "-check-access", Arg.Set check, "checks at runtime that array accesses always lie within bounds <default: no check>"; + "-mpfr", Arg.Int set_mpfr, "replaces FP numbers by the MPFR library multiple precision numbers with a precision of \x1b[4mprec\x1b[0m bits <default: keep FP numbers>"; "-lusi", Arg.Set lusi, "only generates a .lusi interface source file from a Lustre source <default: no generation>"; "-no-spec", Arg.Unit (fun () -> spec := "no"), "do not generate any specification"; - "-acsl-spec", Arg.Unit (fun () -> spec := "acsl"), "generates an ACSL encoding of the specification. Only meaningful for the C backend (default)"; + "-acsl-spec", Arg.Unit (fun () -> spec := "acsl"), "generates an ACSL encoding of the specification. Only meaningful for the C backend <default>"; "-c-spec", Arg.Unit (fun () -> spec := "c"), "generates a C encoding of the specification instead of ACSL contracts and annotations. Only meaningful for the C backend"; "-java", Arg.Unit (fun () -> output := "java"), "generates Java output instead of C"; "-horn", Arg.Unit (fun () -> output := "horn"), "generates Horn clauses encoding output instead of C"; @@ -59,15 +71,20 @@ let options = "-horn-query", Arg.Unit (fun () -> output := "horn"; horn_query:=true), "generate queries in generated Horn file. Enable the horn backend (work in progress)"; "-print_reuse", Arg.Set print_reuse, "prints variable reuse policy"; "-lustre", Arg.Unit (fun () -> output := "lustre"), "generates Lustre output, performing all active optimizations"; - "-inline", Arg.Set global_inline, "inline all node calls (require a main node)"; + "-inline", Arg.Unit (fun () -> global_inline := true; const_unfold := true), "inline all node calls (require a main node). Implies constant unfolding"; "-witnesses", Arg.Set witnesses, "enable production of witnesses during compilation"; "-print_types", Arg.Set print_types, "prints node types"; "-print_clocks", Arg.Set print_clocks, "prints node clocks"; - "-O", Arg.Set_int optimization, " changes optimization level <default: 2>"; - "-verbose", Arg.Set_int verbose_level, " changes verbose level <default: 1>"; + "-O", Arg.Set_int optimization, "changes optimization \x1b[4mlevel\x1b[0m <default: 2>"; + "-verbose", Arg.Set_int verbose_level, "changes verbose \x1b[4mlevel\x1b[0m <default: 1>"; "-version", Arg.Unit print_version, " displays the version";] +let plugin_opt (name, activate, options) = + ( "-" ^ name , Arg.Unit activate, "activate plugin " ^ name ) :: + (List.map (fun (opt, act, desc) -> "-" ^ name ^ opt, act, desc) options) + + let get_witness_dir filename = (* Make sure the directory exists *) let dir = !dest_dir ^ "/" ^ (Filename.basename filename) ^ "_witnesses" in diff --git a/src/parse.ml b/src/parse.ml index 0bd7e961720a77974906bca2d534e7a57f9dc659..84ac6b3a049d18fb8080c5bd68237f36be1d681d 100755 --- a/src/parse.ml +++ b/src/parse.ml @@ -8,16 +8,40 @@ (* version 2.1. *) (* *) (********************************************************************) - -exception Syntax_err of Location.t - open Format open LustreSpec open Corelang -let report_error loc = - Location.print loc; - print_string "Syntax error\n" +type error = + | Undefined_token of string + | Unexpected_eof + | Unfinished_string + | Unfinished_comment + | Syntax_error + | Unfinished_annot + | Unfinished_node_spec + | Annot_error of string + | Node_spec_error of string + +exception Error of (Location.t * error) + + +let pp_error fmt err = + match err with + | Unexpected_eof -> fprintf fmt "unexpected end of file" + | Undefined_token tok -> fprintf fmt "undefined token '%s'" tok + | Unfinished_string -> fprintf fmt "unfinished string" + | Unfinished_comment -> fprintf fmt "unfinished comment" + | Syntax_error -> fprintf fmt "syntax error" + | Unfinished_annot -> fprintf fmt "unfinished annotation" + | Unfinished_node_spec -> fprintf fmt "unfinished node specification" + | Annot_error s -> fprintf fmt "impossible to parse the following annotation:@.%s@.@?" s + | Node_spec_error s -> fprintf fmt "Impossible to parse the following node specification:@.%s@.@?" s + +let report_error (loc, err) = + eprintf "Syntax error: %a%a@." + pp_error err + Location.pp_loc loc let header parsing_fun token_fun lexbuf = try @@ -27,7 +51,7 @@ let header parsing_fun token_fun lexbuf = with | Parsing.Parse_error -> let loc = Location.curr lexbuf in - raise (Syntax_err loc) + raise (Error (loc, Syntax_error)) let prog parsing_fun token_fun lexbuf = try @@ -37,7 +61,7 @@ let prog parsing_fun token_fun lexbuf = with | Parsing.Parse_error -> let loc = Location.curr lexbuf in - raise (Syntax_err loc) + raise (Error (loc, Syntax_error)) (* Local Variables: *) (* compile-command:"make -C .." *) diff --git a/src/parser_lustre.mly b/src/parser_lustre.mly index ab4b17667086efaad40d2814e96f9ac39145e80e..bc50bc6401167bdba79949392c0a64fc2b3dfbc0 100755 --- a/src/parser_lustre.mly +++ b/src/parser_lustre.mly @@ -18,9 +18,10 @@ open Parse let get_loc () = Location.symbol_rloc () +let mkident x = x, get_loc () let mktyp x = mktyp (get_loc ()) x let mkclock x = mkclock (get_loc ()) x -let mkvar_decl x = mkvar_decl (get_loc ()) ~orig:true x +let mkvar_decl x loc = mkvar_decl loc ~orig:true x let mkexpr x = mkexpr (get_loc ()) x let mkeexpr x = mkeexpr (get_loc ()) x let mkeq x = mkeq (get_loc ()) x @@ -52,8 +53,8 @@ let rec fby expr n init = %} %token <int> INT -%token <string> REAL -%token <float> FLOAT +%token <Num.num * int * string> REAL + %token <string> STRING %token AUTOMATON STATE UNTIL UNLESS RESTART RESUME LAST %token STATELESS ASSERT OPEN QUOTE FUNCTION @@ -69,7 +70,7 @@ let rec fby expr n init = %token MERGE FBY WHEN WHENNOT EVERY %token NODE LET TEL RETURNS VAR IMPORTED SENSOR ACTUATOR WCET TYPE CONST %token STRUCT ENUM -%token TINT TFLOAT TREAL TBOOL TCLOCK +%token TINT TREAL TBOOL TCLOCK %token RATE DUE %token EQ LT GT LTE GTE NEQ %token AND OR XOR IMPL @@ -116,6 +117,9 @@ let rec fby expr n init = %start lustre_spec %type <LustreSpec.node_annot> lustre_spec +%start signed_const +%type <LustreSpec.constant> signed_const + %% module_ident: @@ -135,8 +139,8 @@ node_ident_decl: node_ident { push_node $1; $1 } vdecl_ident: - UIDENT { $1 } -| IDENT { $1 } + UIDENT { mkident $1 } +| IDENT { mkident $1 } const_ident: UIDENT { $1 } @@ -180,7 +184,7 @@ state_annot: top_decl_header: | CONST cdecl_list { List.rev ($2 true) } -| nodespec_list state_annot node_ident LPAR vdecl_list SCOL_opt RPAR RETURNS LPAR vdecl_list SCOL_opt RPAR prototype_opt in_lib_opt SCOL +| nodespec_list state_annot node_ident LPAR vdecl_list SCOL_opt RPAR RETURNS LPAR vdecl_list SCOL_opt RPAR prototype_opt in_lib_list SCOL {let nd = mktop_decl true (ImportedNode {nodei_id = $3; nodei_type = Types.new_var (); @@ -198,15 +202,15 @@ prototype_opt: { None } | PROTOTYPE node_ident { Some $2} -in_lib_opt: -{ None } -| LIB module_ident {Some $2} +in_lib_list: +{ [] } +| LIB module_ident in_lib_list { $2::$3 } top_decl: | CONST cdecl_list { List.rev ($2 false) } | nodespec_list state_annot node_ident_decl LPAR vdecl_list SCOL_opt RPAR RETURNS LPAR vdecl_list SCOL_opt RPAR SCOL_opt locals LET stmt_list TEL { - let stmts, asserts, annots = $16 in + let stmts, asserts, annots = $16 in (* Declaring eqs annots *) List.iter (fun ann -> List.iter (fun (key, _) -> @@ -214,26 +218,26 @@ top_decl: ) ann.annots ) annots; (* Building the node *) - let nd = mktop_decl false (Node - {node_id = $3; - node_type = Types.new_var (); - node_clock = Clocks.new_var true; - node_inputs = List.rev $5; - node_outputs = List.rev $10; - node_locals = List.rev $14; - node_gencalls = []; - node_checks = []; - node_asserts = asserts; - node_stmts = stmts; - node_dec_stateless = $2; - node_stateless = None; - node_spec = $1; - node_annot = annots}) - in - pop_node (); + let nd = mktop_decl false (Node + {node_id = $3; + node_type = Types.new_var (); + node_clock = Clocks.new_var true; + node_inputs = List.rev $5; + node_outputs = List.rev $10; + node_locals = List.rev $14; + node_gencalls = []; + node_checks = []; + node_asserts = asserts; + node_stmts = stmts; + node_dec_stateless = $2; + node_stateless = None; + node_spec = $1; + node_annot = annots}) + in + pop_node (); (*add_node $3 nd;*) [nd] } - - nodespec_list: + +nodespec_list: { None } | NODESPEC nodespec_list { (function @@ -264,7 +268,7 @@ typeconst: TINT array_typ_decl { $2 Tydec_int } | TBOOL array_typ_decl { $2 Tydec_bool } | TREAL array_typ_decl { $2 Tydec_real } -| TFLOAT array_typ_decl { $2 Tydec_float } +/* | TFLOAT array_typ_decl { $2 Tydec_float } */ | type_ident array_typ_decl { $2 (Tydec_const $1) } | TBOOL TCLOCK { Tydec_clock Tydec_bool } | IDENT TCLOCK { Tydec_clock (Tydec_const $1) } @@ -313,8 +317,8 @@ assert_: | ASSERT expr SCOL {mkassert ($2)} eq: - ident_list EQ expr SCOL {mkeq (List.rev $1,$3)} -| LPAR ident_list RPAR EQ expr SCOL {mkeq (List.rev $2,$5)} + ident_list EQ expr SCOL {mkeq (List.rev (List.map fst $1), $3)} +| LPAR ident_list RPAR EQ expr SCOL {mkeq (List.rev (List.map fst $2), $5)} lustre_spec: | contract EOF { $1 } @@ -369,8 +373,8 @@ dim_list: expr: /* constants */ INT {mkexpr (Expr_const (Const_int $1))} -| REAL {mkexpr (Expr_const (Const_real $1))} -| FLOAT {mkexpr (Expr_const (Const_float $1))} +| REAL {let c,e,s = $1 in mkexpr (Expr_const (Const_real (c,e,s)))} +/* | FLOAT {mkexpr (Expr_const (Const_float $1))}*/ /* Idents or type enum tags */ | IDENT { mkexpr (Expr_ident $1) } | tag_ident { mkexpr (Expr_ident $1) (*(Expr_const (Const_tag $1))*) } @@ -395,13 +399,13 @@ expr: {(*mkexpr (Expr_fby ($1,$3))*) mkexpr (Expr_arrow ($1, mkexpr (Expr_pre $3)))} | expr WHEN vdecl_ident - {mkexpr (Expr_when ($1,$3,tag_true))} + {mkexpr (Expr_when ($1,fst $3,tag_true))} | expr WHENNOT vdecl_ident - {mkexpr (Expr_when ($1,$3,tag_false))} + {mkexpr (Expr_when ($1,fst $3,tag_false))} | expr WHEN tag_ident LPAR vdecl_ident RPAR - {mkexpr (Expr_when ($1, $5, $3))} + {mkexpr (Expr_when ($1, fst $5, $3))} | MERGE vdecl_ident handler_expr_list - {mkexpr (Expr_merge ($2,$3))} + {mkexpr (Expr_merge (fst $2,$3))} /* Applications */ | node_ident LPAR expr RPAR @@ -497,12 +501,12 @@ signed_const_struct: signed_const: INT {Const_int $1} -| REAL {Const_real $1} -| FLOAT {Const_float $1} +| REAL {let c,e,s =$1 in Const_real (c,e,s)} +/* | FLOAT {Const_float $1} */ | tag_ident {Const_tag $1} | MINUS INT {Const_int (-1 * $2)} -| MINUS REAL {Const_real ("-" ^ $2)} -| MINUS FLOAT {Const_float (-1. *. $2)} +| MINUS REAL {let c,e,s = $2 in Const_real (Num.minus_num c, e, "-" ^ s)} +/* | MINUS FLOAT {Const_float (-1. *. $2)} */ | LCUR signed_const_struct RCUR { Const_struct $2 } | LBRACKET signed_const_array RBRACKET { Const_array $2 } @@ -567,11 +571,11 @@ vdecl_list: vdecl: ident_list COL typeconst clock - { List.map (fun id -> mkvar_decl (id, mktyp $3, $4, false, None)) $1 } + { List.map (fun (id, loc) -> mkvar_decl (id, mktyp $3, $4, false, None) loc) $1 } | CONST ident_list /* static parameters don't have clocks */ - { List.map (fun id -> mkvar_decl (id, mktyp Tydec_any, mkclock Ckdec_any, true, None)) $2 } + { List.map (fun (id, loc) -> mkvar_decl (id, mktyp Tydec_any, mkclock Ckdec_any, true, None) loc) $2 } | CONST ident_list COL typeconst /* static parameters don't have clocks */ - { List.map (fun id -> mkvar_decl (id, mktyp $4, mkclock Ckdec_any, true, None)) $2 } + { List.map (fun (id, loc) -> mkvar_decl (id, mktyp $4, mkclock Ckdec_any, true, None) loc) $2 } local_vdecl_list: local_vdecl {$1} @@ -579,13 +583,13 @@ local_vdecl_list: local_vdecl: /* Useless no ?*/ ident_list - { List.map (fun id -> mkvar_decl (id, mktyp Tydec_any, mkclock Ckdec_any, false, None)) $1 } + { List.map (fun (id, loc) -> mkvar_decl (id, mktyp Tydec_any, mkclock Ckdec_any, false, None) loc) $1 } | ident_list COL typeconst clock - { List.map (fun id -> mkvar_decl (id, mktyp $3, $4, false, None)) $1 } + { List.map (fun (id, loc) -> mkvar_decl (id, mktyp $3, $4, false, None) loc) $1 } | CONST vdecl_ident EQ expr /* static parameters don't have clocks */ - { [ mkvar_decl ($2, mktyp Tydec_any, mkclock Ckdec_any, true, Some $4) ] } + { let (id, loc) = $2 in [ mkvar_decl (id, mktyp Tydec_any, mkclock Ckdec_any, true, Some $4) loc] } | CONST vdecl_ident COL typeconst EQ expr /* static parameters don't have clocks */ - { [ mkvar_decl ($2, mktyp $4, mkclock Ckdec_any, true, Some $6) ] } + { let (id, loc) = $2 in [ mkvar_decl (id, mktyp $4, mkclock Ckdec_any, true, Some $6) loc] } cdecl_list: cdecl SCOL { (fun itf -> [$1 itf]) } diff --git a/src/printers.ml b/src/printers.ml index f2cb78de90939b4e16689b82c89f8a199bdfdfdf..769dd1a8234951f914ac38d97327588ea651d42f 100644 --- a/src/printers.ml +++ b/src/printers.ml @@ -16,12 +16,16 @@ open Utils (* Prints [v] as [pp_fun] would do, but adds a backslash at each end of line, following the C convention for multiple lines macro *) let pp_as_c_macro pp_fun fmt v = - let (out, flush, newline, spaces) = pp_get_all_formatter_output_functions fmt () in - let macro_newline () = (out "\\" 0 1; newline ()) in + let formatter_out_funs = pp_get_formatter_out_functions fmt () in + let macro_newline () = + begin + formatter_out_funs.out_string "\\" 0 1; + formatter_out_funs.out_newline () + end in begin - pp_set_all_formatter_output_functions fmt out flush macro_newline spaces; + pp_set_formatter_out_functions fmt { formatter_out_funs with out_newline = macro_newline }; pp_fun fmt v; - pp_set_all_formatter_output_functions fmt out flush newline spaces; + pp_set_formatter_out_functions fmt formatter_out_funs; end let rec print_dec_struct_ty_field fmt (label, cty) = @@ -30,8 +34,7 @@ and print_dec_ty fmt cty = match (*get_repr_type*) cty with | Tydec_any -> fprintf fmt "Any" | Tydec_int -> fprintf fmt "int" - | Tydec_real - | Tydec_float -> fprintf fmt "real" + | Tydec_real -> fprintf fmt "real" | Tydec_bool -> fprintf fmt "bool" | Tydec_clock cty' -> fprintf fmt "%a clock" print_dec_ty cty' | Tydec_const c -> fprintf fmt "%s" c @@ -57,8 +60,8 @@ let rec pp_struct_const_field fmt (label, c) = and pp_const fmt c = match c with | Const_int i -> pp_print_int fmt i - | Const_real r -> pp_print_string fmt r - | Const_float r -> pp_print_float fmt r + | Const_real (c, e, s) -> pp_print_string fmt s (*if e = 0 then pp_print_int fmt c else if e < 0 then Format.fprintf fmt "%ie%i" c (-e) else Format.fprintf fmt "%ie-%i" c e *) + (* | Const_float r -> pp_print_float fmt r *) | Const_tag t -> pp_print_string fmt t | Const_array ca -> Format.fprintf fmt "[%a]" (Utils.fprintf_list ~sep:"," pp_const) ca | Const_struct fl -> Format.fprintf fmt "{%a }" (Utils.fprintf_list ~sep:" " pp_struct_const_field) fl @@ -131,7 +134,7 @@ and pp_eexpr fmt e = and pp_expr_annot fmt expr_ann = let pp_annot fmt (kwds, ee) = - Format.fprintf fmt "(*! %t: %a *)" + Format.fprintf fmt "(*! %t: %a; *)" (fun fmt -> match kwds with | [] -> assert false | [x] -> Format.pp_print_string fmt x | _ -> Format.fprintf fmt "/%a/" (fprintf_list ~sep:"/" Format.pp_print_string) kwds) pp_eexpr ee in @@ -205,7 +208,7 @@ and pp_var_type_dec_desc fmt tdesc = | Tydec_any -> fprintf fmt "<any>" | Tydec_int -> fprintf fmt "int" | Tydec_real -> fprintf fmt "real" - | Tydec_float -> fprintf fmt "float" + (* | Tydec_float -> fprintf fmt "float" *) | Tydec_bool -> fprintf fmt "bool" | Tydec_clock t -> fprintf fmt "%a clock" pp_var_type_dec_desc t | Tydec_const t -> fprintf fmt "%s" t diff --git a/src/scheduling.ml b/src/scheduling.ml index 8238aa7c8e69fbca13cc7a478ea27dfbf6b39ccf..d2d608e6100e9ed8ffecb251bbdc765ce1c5237a 100644 --- a/src/scheduling.ml +++ b/src/scheduling.ml @@ -17,14 +17,18 @@ open Causality type schedule_report = { + (* the scheduled node *) + node : node_desc; (* a schedule computed wrt the dependency graph *) schedule : ident list list; (* the set of unused variables (no output or mem depends on them) *) unused_vars : ISet.t; (* the table mapping each local var to its in-degree *) fanin_table : (ident, int) Hashtbl.t; + (* the dependency graph *) + dep_graph : IdentDepGraph.t; (* the table mapping each assignment to a reusable variable *) - reuse_table : (ident, var_decl) Hashtbl.t + (*reuse_table : (ident, var_decl) Hashtbl.t*) } (* Topological sort with a priority for variables belonging in the same equation lhs. @@ -125,7 +129,7 @@ let filter_original n vl = if vdecl.var_orig then v :: res else res) vl [] let schedule_node n = - let node_vars = get_node_vars n in + (* let node_vars = get_node_vars n in *) try let eq_equiv = ExprDep.node_eq_equiv n in let eq_equiv v1 v2 = @@ -134,13 +138,6 @@ let schedule_node n = with Not_found -> false in let n', g = global_dependency n in - Log.report ~level:5 - (fun fmt -> - Format.fprintf fmt - "dependency graph for node %s: %a" - n'.node_id - pp_dep_graph g - ); (* TODO X: extend the graph with inputs (adapt the causality analysis to deal with inputs compute: coi predecessors of outputs @@ -152,17 +149,17 @@ let schedule_node n = let sort = topological_sort eq_equiv g in let unused = Liveness.compute_unused_variables n gg in let fanin = Liveness.compute_fanin n gg in + { node = n'; schedule = sort; unused_vars = unused; fanin_table = fanin; dep_graph = gg; } - let (disjoint, reuse) = - if !Options.optimization >= 3 - then - let disjoint = Disjunction.clock_disjoint_map node_vars in - (disjoint, - Liveness.compute_reuse_policy n sort disjoint gg) - else - (Hashtbl.create 1, - Hashtbl.create 1) in + with (Causality.Cycle vl) as exc -> + let vl = filter_original n vl in + pp_error Format.err_formatter vl; + raise exc +let compute_node_reuse_table report = + let disjoint = Disjunction.clock_disjoint_map (get_node_vars report.node) in + let reuse = Liveness.compute_reuse_policy report.node report.schedule disjoint report.dep_graph in +(* if !Options.print_reuse then begin @@ -186,24 +183,44 @@ let schedule_node n = Liveness.pp_reuse_policy reuse ); end; - n', { schedule = sort; unused_vars = unused; fanin_table = fanin; reuse_table = reuse } - with (Causality.Cycle vl) as exc -> - let vl = filter_original n vl in - pp_error Format.err_formatter vl; - raise exc +*) + reuse + let schedule_prog prog = List.fold_right ( fun top_decl (accu_prog, sch_map) -> match top_decl.top_decl_desc with | Node nd -> - let nd', report = schedule_node nd in - {top_decl with top_decl_desc = Node nd'}::accu_prog, + let report = schedule_node nd in + {top_decl with top_decl_desc = Node report.node}::accu_prog, IMap.add nd.node_id report sch_map | _ -> top_decl::accu_prog, sch_map ) prog ([],IMap.empty) + + +let compute_prog_reuse_table report = + IMap.map compute_node_reuse_table report + +(* removes inlined local variables from schedule report, + which are now useless *) +let remove_node_inlined_locals locals report = + let is_inlined v = IMap.exists (fun l _ -> v = l) locals in + let schedule' = + List.fold_right (fun heads q -> let heads' = List.filter (fun v -> not (is_inlined v)) heads + in if heads' = [] then q else heads'::q) + report.schedule [] in + begin + IMap.iter (fun v _ -> Hashtbl.remove report.fanin_table v) locals; + IMap.iter (fun v _ -> let iv = ExprDep.mk_instance_var v + in Liveness.replace_in_dep_graph v iv report.dep_graph) locals; + { report with schedule = schedule' } + end + +let remove_prog_inlined_locals removed reuse = + IMap.mapi (fun id -> remove_node_inlined_locals (IMap.find id removed)) reuse let pp_eq_schedule fmt vl = match vl with @@ -222,7 +239,13 @@ let pp_schedule fmt node_schs = let pp_fanin_table fmt node_schs = IMap.iter (fun nd report -> - Format.fprintf fmt "%s : %a" nd Liveness.pp_fanin report.fanin_table) + Format.fprintf fmt "%s: %a" nd Liveness.pp_fanin report.fanin_table) + node_schs + +let pp_dep_graph fmt node_schs = + IMap.iter + (fun nd report -> + Format.fprintf fmt "%s dependency graph: %a" nd pp_dep_graph report.dep_graph) node_schs let pp_warning_unused fmt node_schs = @@ -236,11 +259,12 @@ let pp_warning_unused fmt node_schs = (fun u -> let vu = get_node_var u nd in if vu.var_orig - then Format.fprintf fmt "Warning: variable '%s' seems unused@.%a@." u Location.pp_loc vu.var_loc) + then Format.fprintf fmt " Warning: variable '%s' seems unused@, %a@,@," u Location.pp_loc vu.var_loc) unused ) node_schs + (* Local Variables: *) (* compile-command:"make -C .." *) (* End: *) diff --git a/src/splitting.ml b/src/splitting.ml index e830b614526893b5df3fabf83b73506f885d68af..a41001d31ef3792557cf3b98f51be218cf39dd13 100644 --- a/src/splitting.ml +++ b/src/splitting.ml @@ -21,7 +21,7 @@ let rec tuple_split_expr expr = | Expr_ident _ -> [expr] | Expr_tuple elist -> elist | Expr_appl (id, args, r) -> - if Basic_library.is_internal_fun id + if Basic_library.is_homomorphic_fun id then let args_list = List.map tuple_split_expr (expr_list_of_expr args) in List.map diff --git a/src/stateless.ml b/src/stateless.ml index 3148e032dbe599d42776636a814c04a92499afe0..10acf40c03139383fb3266103f9defcd42d95c82 100755 --- a/src/stateless.ml +++ b/src/stateless.ml @@ -13,8 +13,9 @@ open LustreSpec open Corelang type error = -| Stateful_kwd of ident -| Stateful_imp of ident +| Stateful_kwd of ident +| Stateful_imp of ident +| Stateful_ext_C of ident exception Error of Location.t * error @@ -34,7 +35,7 @@ let rec check_expr expr = | Expr_merge (i, hl) -> List.for_all (fun (t, h) -> check_expr h) hl | Expr_appl (i, e', i') -> check_expr e' && - (Basic_library.is_internal_fun i || check_node (node_from_name i)) + (Basic_library.is_stateless_fun i || check_node (node_from_name i)) and compute_node nd = List.for_all (fun eq -> check_expr eq.eq_rhs) (get_node_eqs nd) and check_node td = @@ -50,12 +51,28 @@ and check_node td = else (nd.node_dec_stateless <- stateless; stateless) end | Some stl -> stl) - | ImportedNode nd -> nd.nodei_stateless + | ImportedNode nd -> + begin + (if nd.nodei_prototype = Some "C" && not nd.nodei_stateless + then raise (Error (td.top_decl_loc, Stateful_ext_C nd.nodei_id))); + nd.nodei_stateless + end | _ -> true let check_prog decls = List.iter (fun td -> ignore (check_node td)) decls + +let force_prog decls = + let force_node td = + match td.top_decl_desc with + | Node nd -> ( + nd.node_dec_stateless <- false; + nd.node_stateless <- Some false) + | _ -> () + in + List.iter (fun td -> ignore (force_node td)) decls + let check_compat_decl decl = match decl.top_decl_desc with | ImportedNode nd -> @@ -75,13 +92,17 @@ let check_compat header = let pp_error fmt err = match err with | Stateful_kwd nd -> - Format.fprintf fmt - "node %s should be stateless but is actually stateful.@." - nd + Format.fprintf fmt + "node %s should be stateless but is actually stateful.@." + nd | Stateful_imp nd -> - Format.fprintf fmt - "node %s is declared stateless but is actually stateful.@." - nd + Format.fprintf fmt + "node %s is declared stateless but is actually stateful.@." + nd + | Stateful_ext_C nd -> + Format.fprintf fmt + "node %s with declared prototype C cannot be stateful, it has to be a function.@." + nd (* Local Variables: *) (* compile-command:"make -C .." *) diff --git a/src/type_predef.ml b/src/type_predef.ml index 0690be222ffd8afb77707d1437f84f12290e3ac5..e9c1cfb2370fe42acfc6e395a43ea053d49291d1 100755 --- a/src/type_predef.ml +++ b/src/type_predef.ml @@ -26,7 +26,6 @@ let type_arrow ty1 ty2 = new_ty (Tarrow (ty1, ty2)) let type_array d ty = new_ty (Tarray (d, ty)) let type_static d ty = new_ty (Tstatic (d, ty)) - let type_unary_bool_op = new_ty (Tarrow (type_bool, type_bool)) diff --git a/src/types.ml b/src/types.ml index 299131ffe81e9efb3e213be30960da4161c875fa..8c4bf2def9d14484fcbe63bdd4dfc29ee3ea40ba 100755 --- a/src/types.ml +++ b/src/types.ml @@ -173,6 +173,9 @@ let pp_error fmt = function let new_id = ref (-1) +let rec bottom = + { tdesc = Tlink bottom; tid = -666 } + let new_ty desc = incr new_id; {tdesc = desc; tid = !new_id } @@ -198,14 +201,30 @@ let get_field_type ty label = | Tstruct fl -> (try Some (List.assoc label fl) with Not_found -> None) | _ -> None -let is_numeric_type ty = +let rec is_scalar_type ty = + match (repr ty).tdesc with + | Tstatic (_, ty) -> is_scalar_type ty + | Tbool + | Tint + | Treal -> true + | _ -> false + +let rec is_numeric_type ty = match (repr ty).tdesc with + | Tstatic (_, ty) -> is_numeric_type ty | Tint | Treal -> true | _ -> false -let is_bool_type ty = +let rec is_real_type ty = + match (repr ty).tdesc with + | Tstatic (_, ty) -> is_real_type ty + | Treal -> true + | _ -> false + +let rec is_bool_type ty = match (repr ty).tdesc with + | Tstatic (_, ty) -> is_bool_type ty | Tbool -> true | _ -> false @@ -288,7 +307,7 @@ let rec array_base_type ty = | _ -> ty let is_address_type ty = - is_array_type ty || is_struct_type ty + is_array_type ty || is_struct_type ty || (is_real_type ty && !Options.mpfr) let rec is_generic_type ty = match (dynamic_type ty).tdesc with @@ -313,10 +332,11 @@ let type_of_type_list tyl = else List.hd tyl -let type_list_of_type ty = +let rec type_list_of_type ty = match (repr ty).tdesc with - | Ttuple tl -> tl - | _ -> [ty] + | Tstatic (_, ty) -> type_list_of_type ty + | Ttuple tl -> tl + | _ -> [ty] (** [is_polymorphic ty] returns true if [ty] is polymorphic. *) let rec is_polymorphic ty = diff --git a/src/typing.ml b/src/typing.ml index 747240eedc75ad237749555b438d1f0291a77f85..d20b3c0ffaa2177dcda5f6d555cf49c3fa39d5b6 100755 --- a/src/typing.ml +++ b/src/typing.ml @@ -103,7 +103,7 @@ let rec type_coretype type_dim cty = | Tydec_any -> new_var () | Tydec_int -> Type_predef.type_int | Tydec_real -> Type_predef.type_real - | Tydec_float -> Type_predef.type_real + (* | Tydec_float -> Type_predef.type_real *) | Tydec_bool -> Type_predef.type_bool | Tydec_clock ty -> Type_predef.type_clock (type_coretype type_dim ty) | Tydec_const c -> Type_predef.type_const c @@ -261,7 +261,7 @@ and type_const loc c = match c with | Const_int _ -> Type_predef.type_int | Const_real _ -> Type_predef.type_real - | Const_float _ -> Type_predef.type_real + (* | Const_float _ -> Type_predef.type_real *) | Const_array ca -> let d = Dimension.mkdim_int loc (List.length ca) in let ty = new_var () in List.iter (fun e -> try_unify ty (type_const loc e) loc) ca; @@ -344,7 +344,7 @@ and type_subtyping_arg env in_main ?(sub=true) const real_arg formal_type = *) and type_appl env in_main loc const f args = let targs = List.map (type_expr env in_main const) args in - if Basic_library.is_internal_fun f && List.exists is_tuple_type targs + if Basic_library.is_homomorphic_fun f && List.exists is_tuple_type targs then try let targs = Utils.transpose_list (List.map type_list_of_type targs) in @@ -575,14 +575,13 @@ let type_var_decl vd_env env vdecl = let type_dim d = begin type_subtyping_arg (env, vd_env) false true (expr_of_dimension d) Type_predef.type_int; - Dimension.eval Basic_library.eval_env eval_const d; end in let ty = type_coretype type_dim vdecl.var_dec_type.ty_dec_desc in let ty_static = if vdecl.var_dec_const - then Type_predef.type_static (Dimension.mkdim_var ()) ty + then Type_predef.type_static (Dimension.mkdim_var ()) ty else ty in (match vdecl.var_dec_value with | None -> () diff --git a/src/utils.ml b/src/utils.ml index 7be8bb142fc4715106acb29d9c8e8cdc10dd9dac..ee8d9dd6d0aacfba6fc7b75553235644e643dcb1 100755 --- a/src/utils.ml +++ b/src/utils.ml @@ -36,7 +36,8 @@ module IMap = Map.Make(IdentModule) module ISet = Set.Make(IdentModule) -let desome x = match x with Some x -> x | None -> failwith "desome" +exception DeSome +let desome x = match x with Some x -> x | None -> raise DeSome let option_map f o = match o with diff --git a/test/test-compile.sh b/test/test-compile.sh old mode 100755 new mode 100644 index ceafcdd05e5c58cd76f85a3f8f96b010c283cf8d..f68224e87dff90e98ea45ee1012242b2015bc05e --- a/test/test-compile.sh +++ b/test/test-compile.sh @@ -5,16 +5,18 @@ eval set -- $(getopt -n $0 -o "-aciwvh:" -- "$@") declare c i w h a v declare -a files -#SRC_PREFIX="../.." -SRC_PREFIX=`svn info --xml | grep wcroot | sed "s/<[^>]*>//g"`/lustre_compiler +SRC_PREFIX=/home/thirioux/RECHERCHE/lustrec-tests/ +#SRC_PREFIX=`svn info --xml | grep wcroot | sed "s/<[^>]*>//g"`/lustre_compiler NOW=`date "+%y%m%d%H%M"` -report=`pwd`/report-$NOW -#LUSTREC="../../_build/src/lustrec" +report=`pwd`/report-1.1-440-$NOW LUSTREC=lustrec mkdir -p build build=`pwd`"/build" gcc_compile() { + if [ $verbose -gt 1 ]; then + echo "gcc -c -Wall -Wno-unused-but-set-variable -I ../../include/ $1.c > /dev/null" + fi gcc -c -Wall -Wno-unused-but-set-variable -I ../../include/ "$1".c > /dev/null; if [ $? -ne 0 ]; then rgcc="INVALID"; @@ -24,6 +26,9 @@ gcc_compile() { } lustrec_compile() { + if [ $verbose -gt 1 ]; then + echo "$LUSTREC $@" + fi $LUSTREC "$@"; if [ $? -ne 0 ]; then rlustrec="INVALID"; @@ -112,37 +117,59 @@ inline_compile_with_check () { while IFS=, read -r file main opts do name=`basename "$file" .lus` - if [ "$name" = "$file" ]; then - return 0 + ext=".lus" + if [ `dirname "$file"`/"$name" = "$file" ]; then + name=`basename "$file" .lusi` + ext=".lusi" fi dir=${SRC_PREFIX}/`dirname "$file"` pushd $dir > /dev/null - lustrec_compile -d $build -verbose 0 $opts -inline -witnesses -node $main $name".lus" - pushd $build > /dev/null - gcc_compile "$name" + if [ "$main" != "" ]; then + lustrec_compile -d $build -verbose 0 $opts -inline -witnesses -node $main $name$ext; + else + if [ "$ext" = ".lusi" ]; then + lustrec_compile -d $build -verbose 0 $opts $name$ext; + else + rlustrec="NONE" + rgcc="NONE" + fi + fi + popd > /dev/null + pushd $build > /dev/null - popd > /dev/null + if [ "$main" != "" ] && [ $ext = ".lus" ] && [ "$opts" != "-lusi" ]; then + gcc_compile "$name"; + else + rgcc="NONE" + fi # Cheching witness - pushd $build > /dev/null - lustrec_compile -verbose 0 -horn-traces -d $build/${name}_witnesses -node check $build/${name}_witnesses/inliner_witness.lus - popd > /dev/null - z3="`z3 -T:10 $build/${name}_witnesses/inliner_witness.smt2 | xargs`" - if [ "x`echo $z3 | grep unsat`" == "xunsat" ]; then - rinlining="VALID"; - elif [ "x`echo $z3 | xargs | grep -o error`" == "xerror" ]; then - rinlining="ERROR"; - elif [ "x`echo $z3 | xargs | grep -o unknown`" == "xunknown" ]; then - rinlining="UNKNOWN"; - else - rinlining="INVALID/TIMEOUT" - fi - if [ $verbose -gt 0 ]; then - echo "lustrec inlined ($rlustrec), gcc ($rgcc), inlining valid ($rinlining), $dir, ${name}.lus, node $main" | column -t -s',' | tee -a $report; - else - echo "lustrec inlined ($rlustrec), gcc ($rgcc), inlining valid ($rinlining), $dir, ${name}.lus, node $main" | column -t -s',' | tee -a $report | grep "INVALID\|ERROR\|UNKNOWN" - fi - popd > /dev/null + + if [ "$main" != "" ] && [ $ext = ".lus" ] && [ "$opts" != "-lusi" ]; then + mv ${name}_witnesses/inliner_witness.lus ${name}_inliner_witness.lus + lustrec_compile -verbose 0 -horn-traces -node check ${name}_inliner_witness.lus + z3="`z3 -T:10 ${name}_inliner_witness.smt2 | xargs`" + if [ "x`echo $z3 | grep -o unsat`" == "xunsat" ]; then + rinlining="VALID"; + elif [ "x`echo $z3 | xargs | grep -o error`" == "xerror" ]; then + rinlining="ERROR"; + elif [ "x`echo $z3 | xargs | grep -o unknown`" == "xunknown" ]; then + rinlining="UNKNOWN"; + elif [ "x`echo $z3 | xargs | grep -o timeout`" == "xtimeout" ]; then + rinlining="TIMEOUT" + else + rinlining="INVALID" + fi + else + rinlining="NONE" + fi + popd > /dev/null + + if [ $verbose -gt 0 ]; then + echo "lustrec inlined ($rlustrec), gcc ($rgcc), inlining check ($rinlining), $dir, ${name}${ext}, node $main" | column -t -s',' | tee -a $report; + else + echo "lustrec inlined ($rlustrec), gcc ($rgcc), inlining check ($rinlining), $dir, ${name}${ext}, node $main" | column -t -s',' | tee -a $report | grep "TIMEOUT\|INVALID\|ERROR\|UNKNOWN" + fi done < $file_list } @@ -159,18 +186,24 @@ check_prop () { # Checking horn backend if [ "$main" != "" ]; then - lustrec_compile -horn-traces -horn-queries -d $build -verbose 0 $opts -node $main $name".lus"; + lustrec_compile -horn-traces -horn-query -d $build -verbose 0 $opts -node $main $name".lus"; else - lustrec_compile -horn-traces -horn-queries -d $build -verbose 0 $opts $name".lus" + lustrec_compile -horn-traces -horn-query -d $build -verbose 0 $opts $name".lus" fi # echo "z3 $build/$name".smt2 # TODO: This part of the script has to be optimized - z3 -T:10 "$build/$name".smt2 | grep unsat > /dev/null - if [ $? -ne 0 ]; then - rhorn="INVALID"; + z3="`z3 -T:10 ${build}/${name}.smt2 | xargs`" + if [ "x`echo $z3 | grep -o unsat`" == "xunsat" ]; then + rhorn="VALID"; + elif [ "x`echo $z3 | xargs | grep -o error`" == "xerror" ]; then + rhorn="ERROR"; + elif [ "x`echo $z3 | xargs | grep -o unknown`" == "xunknown" ]; then + rhorn="UNKNOWN"; + elif [ "x`echo $z3 | xargs | grep -o timeout`" == "xtimeout" ]; then + rhorn="TIMEOUT" else - rhorn="VALID" + rhorn="INVALID" fi if [ $verbose -gt 0 ]; then echo "lustrec ($rlustrec), horn-pdr ($rhorn), $dir, ${name}.lus, node $main" | column -t -s',' | tee -a $report; diff --git a/test/tests_ok_dev.list b/test/tests_ok_dev.list index 527cdab142267edcc74df69888b9c6a9bc2d69d5..098d691fbc01586908cd26ea6c2c1520ef3ccec1 100644 --- a/test/tests_ok_dev.list +++ b/test/tests_ok_dev.list @@ -1,6 +1,7 @@ ./tests/tuples/tuples1.lus ./tests/tuples/tuples2.lus ./tests/arrays_arnaud/dummy_lib.lusi +./tests/arrays_arnaud/arrays.lusi ./tests/arrays_arnaud/arrays.lus,,-check-access ./tests/arrays_arnaud/RelOpMatrix.lus ./tests/arrays_arnaud/access1.lus,,-check-access @@ -20,6 +21,7 @@ ./tests/clocks/oversampling0.lus,,-lusi ./tests/clocks/oversampling0.lusi ./tests/clocks/oversampling0.lus +./tests/clocks/oversampling0.lus,,-O 3 ./tests/lusic/test2.lusi ./tests/lusic/test1.lusi ./tests/lusic/test1.lus,as_soon_as