From f6acf47bfb217703fccb6dd39821668de8caa553 Mon Sep 17 00:00:00 2001
From: ploc <ploc@041b043f-8d7c-46b2-b46e-ef0dd855326e>
Date: Thu, 26 Nov 2015 17:17:51 +0000
Subject: [PATCH] Plugin based framework

---
 configure.ac                      | 70 +++++++++++++++++++++----------
 src/_tags                         |  1 +
 src/backends/C/c_backend_main.ml  |  6 +--
 src/global.ml                     |  1 +
 src/main_lustre_compiler.ml       | 48 ++-------------------
 src/options.ml                    |  5 +--
 src/pluginType.ml                 | 17 ++++++++
 src/plugins.ml                    | 35 ++++++++++++++--
 src/{ => plugins/mpfr}/mpfr.ml    |  0
 src/plugins/salsa/salsa_plugin.ml | 42 +++++++++++++++++++
 src/plugins/scopes/scopes.ml      | 30 ++++++++++++-
 11 files changed, 174 insertions(+), 81 deletions(-)
 create mode 100644 src/pluginType.ml
 rename src/{ => plugins/mpfr}/mpfr.ml (100%)
 create mode 100644 src/plugins/salsa/salsa_plugin.ml

diff --git a/configure.ac b/configure.ac
index 0059f094..23099589 100644
--- a/configure.ac
+++ b/configure.ac
@@ -7,9 +7,24 @@ AC_SUBST(SVN_REVISION)
 
 AC_CONFIG_SRCDIR([src/main_lustre_compiler.ml])
 
+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 12 ); then
+  AC_MSG_ERROR([Ocaml version must be at least 3.12. You have version $ocamlc_version])
+fi
+AC_MSG_RESULT(valid ocaml version detected: $ocamlc_version)
+
+AC_PATH_PROG([OCAMLBUILD],[ocamlbuild],[:])
+
+
 # default prefix is /usr/local
 AC_PREFIX_DEFAULT(/usr/local)
 
+# Checking libs
+
 AC_ARG_WITH([ocamlgraph-path],
         [AS_HELP_STRING([--ocamlgraph-path],
               [specify the path of ocamlgraph library. graph.cmxa should be in ocamlgraph-path @<:@default=$(ocamlfind query ocamlgraph)@:>@])],
@@ -23,32 +38,25 @@ AC_ARG_WITH([ocamlgraph-path],
 )
 AC_SUBST(OCAMLGRAPH_PATH)
 
-
-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])
-fi
-AC_MSG_RESULT(valid ocaml version detected: $ocamlc_version)
-
-AC_PATH_PROG([OCAMLBUILD],[ocamlbuild],[:])
-
-
-# Checking libs
-
-# 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"`
-      AC_MSG_RESULT(library detected: $ocamlgraph_lib_full )
-   else
+	ocamlgraph_lib_full=`find $OCAMLGRAPH_PATH -iname graph.cmxa -nowarn | grep -m 1 "graph.cmxa"`
+      AC_MSG_RESULT($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"
@@ -86,11 +94,27 @@ AC_DEFINE_DIR([abs_datadir], [datadir])
 # Instanciation
 AC_CONFIG_FILES([Makefile
 		 src/Makefile
- 		 src/myocamlbuild.ml
+                 src/myocamlbuild.ml
 		 src/version.ml])
 
 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 ********)
+AC_MSG_NOTICE(******** Configuration ********)
+
diff --git a/src/_tags b/src/_tags
index e3fd0e0e..139426ce 100644
--- a/src/_tags
+++ b/src/_tags
@@ -2,6 +2,7 @@
 "backends/Horn": include
 "plugins/salsa": include
 "plugins/scopes": include
+"plugins/mpfr": include
 <**/.svn>: -traverse
 <**/.svn>: not_hygienic
 "main_lustre_compiler.native": use_graph
diff --git a/src/backends/C/c_backend_main.ml b/src/backends/C/c_backend_main.ml
index f17f617e..d01a9e56 100644
--- a/src/backends/C/c_backend_main.ml
+++ b/src/backends/C/c_backend_main.ml
@@ -139,10 +139,8 @@ let print_main_code fmt m =
   print_main_memory_allocation mname main_mem fmt m;
   print_main_initialize mname main_mem fmt m;
   print_main_loop mname main_mem fmt m;
-  if Scopes.Plugin.is_active () then
-    begin
-      fprintf fmt "@ %t" Scopes.Plugin.pp 
-    end;    
+
+  Plugins.c_backend_main_loop_body_suffix fmt ();
   fprintf fmt "@]@ }@ @ ";
   print_main_clear mname main_mem fmt m;
   fprintf fmt "@ return 1;";
diff --git a/src/global.ml b/src/global.ml
index 892f630c..08f09908 100644
--- a/src/global.ml
+++ b/src/global.ml
@@ -3,6 +3,7 @@ let clock_env : (Clocks.clock_expr Env.t) ref = ref Env.initial
 let basename = ref ""
 let main_node = ref ""
 
+
 module TypeEnv =
 struct
 let lookup_value ident = Env.lookup_value !type_env ident
diff --git a/src/main_lustre_compiler.ml b/src/main_lustre_compiler.ml
index 5bc03a73..ab22f4bd 100644
--- a/src/main_lustre_compiler.ml
+++ b/src/main_lustre_compiler.ml
@@ -112,7 +112,7 @@ let stage1 prog dirname basename =
   in
 
   (* Checking stateless/stateful status *)
-  if Scopes.Plugin.is_active () then
+  if Plugins.check_force_stateful () then
     force_stateful_decls prog
   else
     check_stateless_decls prog;
@@ -275,27 +275,6 @@ let stage2 prog =
   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);
@@ -391,23 +370,8 @@ let compile_source dirname basename extension =
   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
+  let machine_code = Plugins.refine_machine_code prog machine_code in
   
   stage3 prog machine_code dependencies basename;
   begin
@@ -443,13 +407,7 @@ let _ =
   try
     Printexc.record_backtrace true;
 
-    let options = Options.options @ 
-      List.flatten (
-	List.map Options.plugin_opt [
-	  Scopes.Plugin.name, Scopes.Plugin.activate, Scopes.Plugin.options
-	]
-      )
-    in
+    let options = Options.options @ (Plugins.options ()) in
     
     Arg.parse options anonymous usage
   with
diff --git a/src/options.ml b/src/options.ml
index 99744c53..0426588b 100755
--- a/src/options.ml
+++ b/src/options.ml
@@ -41,13 +41,12 @@ let horntraces = ref false
 let horn_cex = ref false
 let horn_queries = ref false
 
-let salsa_enabled = ref false
 
 let set_mpfr prec =
   if prec > 0 then (
     mpfr := true;
     mpfr_prec := prec;
-    salsa_enabled := false; (* We deactivate salsa *)
+    (* salsa_enabled := false; (* We deactivate salsa *) TODO *)
   )
   else
     failwith "mpfr requires a positive integer"
@@ -69,8 +68,6 @@ let options =
     "-horn-traces", Arg.Unit (fun () -> output := "horn"; horntraces:=true), "produce traceability file for Horn backend. Enable the horn backend.";
     "-horn-cex", Arg.Unit (fun () -> output := "horn"; horn_cex:=true), "generate cex enumeration. Enable the horn backend (work in progress)";
     "-horn-queries", Arg.Unit (fun () -> output := "horn"; horn_queries:=true), "generate queries in generated Horn file. Enable the horn backend (work in progress)";
-    "-salsa", Arg.Set salsa_enabled, "activate Salsa optimization <default>";
-    "-no-salsa", Arg.Clear salsa_enabled, "deactivate Salsa optimization";
     "-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.Unit (fun () -> global_inline := true; const_unfold := true), "inline all node calls (require a main node). Implies constant unfolding";
diff --git a/src/pluginType.ml b/src/pluginType.ml
new file mode 100644
index 00000000..fda050a6
--- /dev/null
+++ b/src/pluginType.ml
@@ -0,0 +1,17 @@
+module type PluginType =
+sig
+  val name: string
+  val activate: unit -> unit
+  val options: (string * Arg.spec * string) list
+  val check_force_stateful : unit -> bool
+  val refine_machine_code: LustreSpec.top_decl list ->
+    Machine_code.machine_t list -> Machine_code.machine_t list
+  val c_backend_main_loop_body_suffix : Format.formatter ->  unit -> unit
+end
+
+module Default =
+struct
+  let check_force_stateful () = false
+  let refine_machine_code prog machines = machines
+  let c_backend_main_loop_body_suffix fmt () = ()
+end
diff --git a/src/plugins.ml b/src/plugins.ml
index 44fccd4b..f6700914 100644
--- a/src/plugins.ml
+++ b/src/plugins.ml
@@ -1,11 +1,40 @@
 open LustreSpec
 
-module type PluginType =
-sig
+let plugins =
+  [
+    (module Scopes.Plugin : PluginType.PluginType);
+    (module Salsa_plugin.Plugin : PluginType.PluginType)
+  ]
 
-end
 
+let options () = 
+  List.flatten (
+    List.map Options.plugin_opt (
+      List.map (fun m ->
+	let module M = (val m : PluginType.PluginType) in
+	(M.name, M.activate, M.options)
+      ) plugins
+    ))
 
+let check_force_stateful () =
+  List.exists (fun m ->
+	let module M = (val m : PluginType.PluginType) in
+	M.check_force_stateful ()
+  ) plugins
+
+let refine_machine_code prog machine_code =
+  List.fold_left (fun accu m ->
+    let module M = (val m : PluginType.PluginType) in
+    M.refine_machine_code prog accu
+  ) machine_code plugins
+
+
+let c_backend_main_loop_body_suffix fmt () = 
+  List.iter (fun (m: (module PluginType.PluginType)) -> 
+    let module M = (val m : PluginType.PluginType) in
+    M.c_backend_main_loop_body_suffix fmt ()) plugins
+
+(* Specific treatment of annotations when inlining, specific of declared plugins *)
 
 let inline_annots rename_var_fun annot_list =
   List.map (
diff --git a/src/mpfr.ml b/src/plugins/mpfr/mpfr.ml
similarity index 100%
rename from src/mpfr.ml
rename to src/plugins/mpfr/mpfr.ml
diff --git a/src/plugins/salsa/salsa_plugin.ml b/src/plugins/salsa/salsa_plugin.ml
new file mode 100644
index 00000000..ca713ab9
--- /dev/null
+++ b/src/plugins/salsa/salsa_plugin.ml
@@ -0,0 +1,42 @@
+open Format 
+open LustreSpec
+
+let salsa_enabled = ref false
+    (* "-salsa", Arg.Set salsa_enabled, "activate Salsa optimization <default>"; *)
+    (* "-no-salsa", Arg.Clear salsa_enabled, "deactivate Salsa optimization"; *)
+
+
+module Plugin =
+(struct
+  include PluginType.Default
+  let name = "salsa"
+  
+  let options = [
+
+  ]
+
+  let activate () = salsa_enabled := true
+
+  let refine_machine_code prog machine_code = 
+    if !salsa_enabled then
+      begin
+	Compiler_common.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
+  
+  
+ end: PluginType.PluginType)
diff --git a/src/plugins/scopes/scopes.ml b/src/plugins/scopes/scopes.ml
index 1f1920bd..19e5b52d 100644
--- a/src/plugins/scopes/scopes.ml
+++ b/src/plugins/scopes/scopes.ml
@@ -227,7 +227,7 @@ let update_machine machine =
   }
     
 
-module Plugin =
+module Plugin : PluginType.PluginType =
 struct
   let name = "scopes"
   let is_active () = 
@@ -250,7 +250,8 @@ struct
   let activate () = 
     option_scopes := true;
     Options.optimization := 0; (* no optimization *)
-    Options.salsa_enabled := false; (* No salsa *)
+    
+    (* Options.salsa_enabled := false; (\* No salsa *\) TODO *)
     ()
 
   let rec is_valid_path path nodename prog machines =
@@ -312,6 +313,31 @@ struct
 
   let pp fmt = pp_scopes fmt !scopes_map
 
+  let check_force_stateful () = true
+
+  let refine_machine_code prog machine_code =
+    if show_scopes () then
+      begin
+	let all_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@ @]@.@?" print_scopes all_scopes;
+	exit 0
+      end;
+    if is_active () then
+      process_scopes !Options.main_node prog machine_code
+    else
+      machine_code
+	
+
+
+  let c_backend_main_loop_body_suffix fmt () =
+    if is_active () then
+      begin
+	Format.fprintf fmt "@ %t" pp 
+      end;    
+ 
 end
     
 (* Local Variables: *)
-- 
GitLab