From e7cecff76e6c1352d0e71132d59017f8283ea6e9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Loi=CC=88c=20Correnson?= <loic.correnson@cea.fr>
Date: Thu, 21 Jan 2021 18:34:29 +0100
Subject: [PATCH] [wp] compute modes for new calculus

---
 src/libraries/utils/bag.mli    |   1 +
 src/plugins/wp/Generator.ml    |  26 ++---
 src/plugins/wp/cfgCalculus.ml  |  61 +++---------
 src/plugins/wp/cfgCalculus.mli |  10 +-
 src/plugins/wp/cfgGenerator.ml | 176 +++++++++++++++++++++++++++++++--
 5 files changed, 201 insertions(+), 73 deletions(-)

diff --git a/src/libraries/utils/bag.mli b/src/libraries/utils/bag.mli
index 1e466b2e6e2..ef515cb71fc 100644
--- a/src/libraries/utils/bag.mli
+++ b/src/libraries/utils/bag.mli
@@ -36,6 +36,7 @@ val concat : 'a t -> 'a t -> 'a t
 
 val map : ('a -> 'b) -> 'a t -> 'b t
 val umap : ('a -> 'b t) -> 'a t -> 'b t
+val umap_list : ('a -> 'b t) -> 'a list -> 'b t
 
 val iter : ('a -> unit) -> 'a t -> unit
 val fold_left : ('b -> 'a -> 'b) -> 'b -> 'a t -> 'b
diff --git a/src/plugins/wp/Generator.ml b/src/plugins/wp/Generator.ml
index dbe19558090..2af03b61f95 100644
--- a/src/plugins/wp/Generator.ml
+++ b/src/plugins/wp/Generator.ml
@@ -67,17 +67,19 @@ let create
   let legacy = default Wp_parameters.Dump.get legacy in
   let driver = default Driver.load_driver driver in
   let setup = default user_setup setup in
-  ignore legacy ;
-  let cc =
-    if dump
-    then WpGenerator.dumper ()
-    else WpGenerator.computer setup driver in
-  let the_model = cc#model in
-  object
-    method model = the_model
-    method compute_ip = WpGenerator.compute_ip cc
-    method compute_call = WpGenerator.compute_call cc
-    method compute_main = WpGenerator.compute_selection cc
-  end
+  if legacy then
+    let cc =
+      if dump
+      then WpGenerator.dumper ()
+      else WpGenerator.computer setup driver in
+    let the_model = cc#model in
+    object
+      method model = the_model
+      method compute_ip = WpGenerator.compute_ip cc
+      method compute_call = WpGenerator.compute_call cc
+      method compute_main = WpGenerator.compute_selection cc
+    end
+  else
+    CfgGenerator.generator setup driver
 
 (* -------------------------------------------------------------------------- *)
diff --git a/src/plugins/wp/cfgCalculus.ml b/src/plugins/wp/cfgCalculus.ml
index eb8175580fd..9205c53e4fe 100644
--- a/src/plugins/wp/cfgCalculus.ml
+++ b/src/plugins/wp/cfgCalculus.ml
@@ -40,37 +40,12 @@ type assigns = WpPropId.assigns_full_info
 (* -------------------------------------------------------------------------- *)
 
 type mode = {
+  kf: kernel_function;
   bhv : funbehavior ; (* Selected behavior (None is default) *)
-  stmt : stmt option ;  (* Stmt contract under proof *)
 }
 
 type props = [ `All | `Names of string list | `PropId of Property.t ]
 
-module MODES = WpContext.StaticGenerator(Kernel_function)
-    (struct
-      type key = kernel_function
-      type data = mode list
-      let name = "Wp.CfgCalculus.Modes"
-      let compile kf =
-        Annotations.fold_behaviors
-          (fun _emitter bhv ms -> { bhv ; stmt = None } :: ms)
-          kf @@
-        List.fold_right
-          (fun stmt ms ->
-             Annotations.fold_code_annot (fun _emitter ca ms ->
-                 match ca.annot_content with
-                 | AStmtSpec(_, { spec_behavior = bs } ) ->
-                     List.fold_right (fun bhv ms -> {
-                           bhv ;
-                           stmt = Some stmt ;
-                         }::ms) bs ms
-                 | _ -> ms
-               ) stmt ms
-          ) (Kernel_function.get_definition kf).sallstmts []
-    end)
-
-let modes = MODES.get
-
 let default_requires mode kf =
   if Cil.is_default_behavior mode.bhv then [] else
     try
@@ -139,10 +114,8 @@ struct
   (* --- Traversal Environment --- *)
 
   type env = {
-    kf: kernel_function;
     mode: mode;
     props: props;
-    mutable ki: kinstr; (* Current localisation *)
     cfg: Cfg.automaton;
     we: W.t_env;
     wp: W.t_prop option Vhash.t; (* None is used for non-dag detection *)
@@ -189,13 +162,13 @@ struct
 
   (* --- Decomposition of WP Rules --- *)
 
-  exception NonNaturalLoop of kernel_function * kinstr
+  exception NonNaturalLoop
 
   let succ env a = G.succ_e env.cfg.graph a
 
   let rec wp (env:env) (a:vertex) : W.t_prop =
     match Vhash.find env.wp a with
-    | None -> raise (NonNaturalLoop(env.kf,env.ki))
+    | None -> raise NonNaturalLoop
     | Some pi -> pi
     | exception Not_found ->
         (* cut circularities *)
@@ -207,23 +180,19 @@ struct
 
   (* Compute a stmt node *)
   and stmt env a (s: stmt) : W.t_prop =
-    let ki = env.ki in
     let kl = Cil.CurrentLoc.get () in
     try
-      env.ki <- Kstmt s ;
       Cil.CurrentLoc.set (Stmt.loc s) ;
-      let ca = CfgAnnot.get_code_assertions env.kf s in
+      let ca = CfgAnnot.get_code_assertions env.mode.kf s in
       let pi =
         W.label env.we (Some s) (Clabels.stmt s) @@
         List.fold_right (prove_property env) ca.code_verified @@
         List.fold_right (use_property env) ca.code_admitted @@
         control env a s
       in
-      Cil.CurrentLoc.set kl ;
-      env.ki <- ki ; pi
+      Cil.CurrentLoc.set kl ; pi
     with err ->
-      Cil.CurrentLoc.set kl ;
-      env.ki <- ki ; raise err
+      Cil.CurrentLoc.set kl ; raise err
 
   (* Branching wrt control-flow *)
   and control env a s : W.t_prop =
@@ -234,7 +203,7 @@ struct
         W.switch env.we s value
           (List.map (fun (e,v) -> [e], wp env v) cases)
           (wp env default)
-    | Loop _ -> loop env a s (CfgAnnot.get_loop_contract env.kf s)
+    | Loop _ -> loop env a s (CfgAnnot.get_loop_contract env.mode.kf s)
     | Edges -> successors env a
 
   (* Compute loops *)
@@ -322,21 +291,21 @@ struct
     wp env env.cfg.entry_point
 
   (* Putting everything together *)
-  let compute ~mode ~props kf =
+  let compute ~mode ~props =
     let env = {
-      kf ; ki = Kglobal ; mode ; props ;
-      cfg = Cfg.get_automaton kf ;
-      we = W.new_env kf ;
+      mode ; props ;
+      cfg = Cfg.get_automaton mode.kf ;
+      we = W.new_env mode.kf ;
       wp = Vhash.create 32 ;
       wk = W.empty ;
     } in
-    let xs = Kernel_function.get_formals kf in
-    let req = default_requires mode kf in
-    let bhv = CfgAnnot.get_behavior kf Kglobal ~active:[] mode.bhv in
+    let xs = Kernel_function.get_formals mode.kf in
+    let req = default_requires mode mode.kf in
+    let bhv = CfgAnnot.get_behavior mode.kf Kglobal ~active:[] mode.bhv in
     env.we ,
     (* global init *)
     W.close env.we @@
-    I.process_global_init env.we kf @@
+    I.process_global_init env.we mode.kf @@
     W.scope env.we [] SC_Global @@
     (* pre-state *)
     W.label env.we None Clabels.pre @@
diff --git a/src/plugins/wp/cfgCalculus.mli b/src/plugins/wp/cfgCalculus.mli
index 6e7ec0f5ef0..e49d6dd72a9 100644
--- a/src/plugins/wp/cfgCalculus.mli
+++ b/src/plugins/wp/cfgCalculus.mli
@@ -27,20 +27,16 @@ open Cil_types
 (* -------------------------------------------------------------------------- *)
 
 type mode = {
-  bhv : funbehavior ; (* Selected behavior (None is default) *)
-  stmt : stmt option ;  (* Stmt contract under proof *)
+  kf : kernel_function ; (* Selected function *)
+  bhv : funbehavior ; (* Selected behavior *)
 }
 
 type props = [ `All | `Names of string list | `PropId of Property.t ]
 
-(* Memoized *)
-val modes : kernel_function -> mode list
-
 module Make(W : Mcfg.S) :
 sig
 
-  val compute : mode:mode -> props:props -> kernel_function ->
-    W.t_env * W.t_prop
+  val compute : mode:mode -> props:props -> W.t_env * W.t_prop
 
 end
 
diff --git a/src/plugins/wp/cfgGenerator.ml b/src/plugins/wp/cfgGenerator.ml
index 0350785f987..e9cd98fec7e 100644
--- a/src/plugins/wp/cfgGenerator.ml
+++ b/src/plugins/wp/cfgGenerator.ml
@@ -20,6 +20,170 @@
 (*                                                                        *)
 (**************************************************************************)
 
+open Cil_types
+open Wp_parameters
+
+(* -------------------------------------------------------------------------- *)
+(* --- Task Manager                                                       --- *)
+(* -------------------------------------------------------------------------- *)
+
+type task = {
+  mutable lemmas: LogicUsage.logic_lemma list ;
+  mutable modes: CfgCalculus.mode list ;
+  mutable props: CfgCalculus.props ;
+}
+
+let empty () = {
+  lemmas = [];
+  modes = [];
+  props = `All ;
+}
+
+(* -------------------------------------------------------------------------- *)
+(* --- Property Guided Selection                                          --- *)
+(* -------------------------------------------------------------------------- *)
+
+let default kf =
+  List.filter
+    Cil.is_default_behavior
+    (Annotations.behaviors kf)
+
+let select kf bnames =
+  List.filter
+    (fun b -> List.mem b.b_name bnames)
+    (Annotations.behaviors kf)
+
+let apply task ~kf ?bhvs ?prop () =
+  begin
+    let bhvs = match bhvs with
+      | None -> Annotations.behaviors kf
+      | Some bhvs -> bhvs in
+    List.iter (fun bhv ->
+        task.modes <- { kf ; bhv } :: task.modes
+      ) bhvs ;
+    Extlib.may (fun ip -> task.props <- `PropId ip) prop ;
+  end
+
+let notyet prop =
+  Wp_parameters.warning ~once:true
+    "Not yet implemented wp for '%a'" Property.pretty prop
+
+let rec strategy task prop =
+  let open Property in
+  match prop with
+  | IPLemma { il_name } ->
+      let l = LogicUsage.logic_lemma il_name in
+      task.lemmas <- l :: task.lemmas
+  | IPAxiomatic { iax_props } ->
+      List.iter (strategy task) iax_props
+  | IPBehavior { ib_kf = kf ; ib_bhv = bhv } ->
+      apply task ~kf ~bhvs:[bhv] ()
+  | IPPredicate { ip_kf = kf ; ip_kind ; ip_kinstr = ki } ->
+      begin match ip_kind with
+        | PKAssumes _ -> ()
+        | PKRequires bhv ->
+            begin
+              match ki with
+              | Kglobal -> (*TODO*) notyet prop
+              | Kstmt _ -> apply task ~kf ~bhvs:[bhv] ~prop ()
+            end
+        | PKEnsures(bhv,_) ->
+            apply task ~kf ~bhvs:[bhv] ~prop ()
+        | PKTerminates ->
+            apply task ~kf ~bhvs:(default kf) ~prop ()
+      end
+  | IPDecrease { id_kf = kf } ->
+      apply task ~kf ~bhvs:(default kf) ~prop ()
+  | IPAssigns { ias_kf=kf ; ias_bhv=Id_loop ca }
+  | IPAllocation { ial_kf=kf ; ial_bhv=Id_loop ca } ->
+      let bhvs = match ca.annot_content with
+        | AAssigns(bhvs,_) | AAllocation(bhvs,_) -> bhvs
+        | _ -> [] in
+      apply task ~kf ~bhvs:(select kf bhvs) ~prop ()
+  | IPAssigns { ias_kf=kf ; ias_bhv=Id_contract(_,bhv) }
+  | IPAllocation { ial_kf=kf ; ial_bhv=Id_contract(_,bhv) }
+    -> apply task ~kf ~bhvs:[bhv] ~prop ()
+  | IPCodeAnnot { ica_kf = kf ; ica_ca = ca } ->
+      begin match ca.annot_content with
+        | AExtended _ | APragma _ -> ()
+        | AStmtSpec(fors,_) ->
+            (*TODO*) notyet prop ;
+            apply task ~kf ~bhvs:(select kf fors) ()
+        | AVariant _ ->
+            apply task ~kf ~prop ()
+        | AAssert(fors, _)
+        | AInvariant(fors, _, _)
+        | AAssigns(fors, _)
+        | AAllocation(fors, _) ->
+            apply task ~kf ~bhvs:(select kf fors) ~prop ()
+      end
+  | IPComplete _ -> (*TODO*) notyet prop
+  | IPDisjoint _ -> (*TODO*) notyet prop
+  | IPFrom _ | IPReachable _ | IPTypeInvariant _ | IPGlobalInvariant _
+  | IPPropertyInstance _ -> notyet prop (* ? *)
+  | IPExtended _ | IPAxiom _ | IPOther _ -> ()
+
+(* -------------------------------------------------------------------------- *)
+(* --- Compute All Tasks                                                  --- *)
+(* -------------------------------------------------------------------------- *)
+
+module Make(VCG : CfgWP.VCgen) =
+struct
+
+  module WP = CfgCalculus.Make(VCG)
+
+  let compute model task =
+    begin
+      let collection = ref Bag.empty in
+      Lang.F.release () ;
+      if task.lemmas <> [] then
+        WpContext.on_context (model,WpContext.Global)
+          begin fun () ->
+            LogicUsage.iter_lemmas VCG.register_lemma ;
+            List.iter (fun l ->
+               let wpo = VCG.compile_lemma l in
+               collection := Bag.add wpo !collection
+              ) task.lemmas ;
+          end () ;
+      List.iter
+        (fun (mode : CfgCalculus.mode) ->
+           WpContext.on_context (model,WpContext.Kf mode.kf)
+             begin fun () ->
+               let wp = snd @@ WP.compute ~mode ~props:task.props in
+               let bhv =
+                 if Cil.is_default_behavior mode.bhv then None
+                 else Some mode.bhv.b_name in
+               let index = Wpo.Function(mode.kf,bhv) in
+               let wcs = VCG.compile_wp index wp in
+               collection := Bag.concat !collection wcs
+             end ()
+        ) task.modes ;
+      !collection
+    end
+
+  let compute_ip model ip =
+    let task = empty () in
+    strategy task ip ;
+    compute model task
+
+  let compute_call _model _stmt =
+    Wp_parameters.warning
+      ~once:true "Not yet implemented call preconds" ;
+    Bag.empty
+
+  let compute_main model ?(fct=Fct_all) ?bhv ?prop () =
+    let task = empty () in
+    Wp_parameters.iter_fct
+      (fun kf ->
+         match bhv with
+         | None -> apply task ~kf ()
+         | Some bs -> apply task ~kf ~bhvs:(select kf bs) ()
+      ) fct ;
+    task.props <- (match prop with None -> `All | Some ps -> `Names ps) ;
+    compute model task
+
+end
+
 (* -------------------------------------------------------------------------- *)
 (* --- New WP Computer (main entry points)                                --- *)
 (* -------------------------------------------------------------------------- *)
@@ -31,17 +195,13 @@ let generator setup driver =
   try WpContext.MINDEX.find generators model
   with Not_found ->
     let module VCG = (val CfgWP.vcgen setup driver) in
-    let module WP = CfgCalculus.Make(VCG) in
+    let module CC = Make(VCG) in
     let generator : Wpo.generator =
       object
         method model = model
-        method compute_ip _ = Bag.empty
-        method compute_call _ = Bag.empty
-        method compute_main ?fct ?bhv ?prop () =
-          ignore fct ;
-          ignore bhv ;
-          ignore prop ;
-          Bag.empty
+        method compute_ip = CC.compute_ip model
+        method compute_call = CC.compute_call model
+        method compute_main = CC.compute_main model
       end in
     WpContext.MINDEX.add generators model generator ;
     generator
-- 
GitLab