From 3ee159f6a6260605d14e9ed062447095e7fb08d8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Loi=CC=88c=20Correnson?= <loic.correnson@cea.fr>
Date: Mon, 8 Feb 2021 16:40:09 +0100
Subject: [PATCH] [wp] refactor function-body

---
 src/plugins/wp/cfgCalculus.ml | 34 ++++++++--------
 src/plugins/wp/cfgInfos.ml    | 77 ++++++++++++++++++-----------------
 src/plugins/wp/cfgInfos.mli   |  3 +-
 3 files changed, 59 insertions(+), 55 deletions(-)

diff --git a/src/plugins/wp/cfgCalculus.ml b/src/plugins/wp/cfgCalculus.ml
index e12ad3ebe43..d418ba2488d 100644
--- a/src/plugins/wp/cfgCalculus.ml
+++ b/src/plugins/wp/cfgCalculus.ml
@@ -129,7 +129,8 @@ struct
   type env = {
     mode: mode;
     props: props;
-    cfg: Cfg.automaton option;
+    body: Cfg.automaton option;
+    succ: Cfg.vertex -> Cfg.G.edge list;
     we: W.t_env;
     wp: W.t_prop option Vhash.t; (* None is used for non-dag detection *)
     mutable wk: W.t_prop; (* end point *)
@@ -179,8 +180,6 @@ struct
 
   exception NonNaturalLoop
 
-  let succ env a = G.succ_e (Option.get env.cfg).graph a
-
   let rec wp (env:env) (a:vertex) : W.t_prop =
     match Vhash.find env.wp a with
     | None -> raise NonNaturalLoop
@@ -240,7 +239,7 @@ struct
     W.merge env.we established presersed
 
   (* Merge transitions *)
-  and successors env (a : vertex) = transitions env (succ env a)
+  and successors env (a : vertex) = transitions env (env.succ a)
   and transitions env (es : G.edge list) = fmerge env (transition env) es
   and transition env (_,edge,dst) : W.t_prop =
     let p = wp env dst in
@@ -355,21 +354,26 @@ struct
     List.fold_right (prove_property env) b.bhv_exits @@
     prove_assigns env b.bhv_exit_assigns w
 
-  let do_funbehavior env ~formals (b : CfgAnnot.behavior) w =
-    let cfg = Option.get env.cfg in
-    let wpost = do_post env ~formals b w in
-    let wexit = do_exit env ~formals b w in
-    Vhash.add env.wp cfg.return_point (Some wpost) ;
-    env.wk <- wexit ;
-    wp env cfg.entry_point
+  let do_funbehavior env ~formals (b:CfgAnnot.behavior) w =
+    match env.body with
+    | None -> w
+    | Some cfg ->
+        let wpost = do_post env ~formals b w in
+        let wexit = do_exit env ~formals b w in
+        Vhash.add env.wp cfg.return_point (Some wpost) ;
+        env.wk <- wexit ;
+        wp env cfg.entry_point
 
   (* Putting everything together *)
   let compute ~mode ~props =
     let kf = mode.kf in
     let infos = mode.infos in
-    let cfg = CfgInfos.cfg infos in
+    let body = CfgInfos.body infos in
+    let succ = match body with
+      | None -> (fun _ -> [])
+      | Some cfg -> Cfg.G.succ_e cfg.graph in
     let env = {
-      mode ; props ; cfg ;
+      mode ; props ; body ; succ ;
       we = W.new_env kf ;
       wp = Vhash.create 32 ;
       wk = W.empty ;
@@ -382,9 +386,7 @@ struct
       do_global_init env @@
       do_preconditions env ~formals bhv @@
       do_complete_disjoint env @@
-      (if Kernel_function.has_definition kf
-       then do_funbehavior env ~formals bhv
-       else Extlib.id) @@
+      do_funbehavior env ~formals bhv @@
       W.empty
     end
 
diff --git a/src/plugins/wp/cfgInfos.ml b/src/plugins/wp/cfgInfos.ml
index 013e77df4fc..ac9c245b0ad 100644
--- a/src/plugins/wp/cfgInfos.ml
+++ b/src/plugins/wp/cfgInfos.ml
@@ -31,7 +31,7 @@ module Shash = Cil_datatype.Stmt.Hashtbl
 module Reachability = Graph.Path.Check(Cfg.G)
 
 type t = {
-  cfg : Cfg.automaton option ;
+  body : Cfg.automaton option ;
   reachability : Reachability.path_checker option ;
   mutable annots : bool; (* has goals to prove *)
   mutable doomed : WpPropId.prop_id Bag.t;
@@ -42,15 +42,17 @@ type t = {
 (* --- Getters                                                            --- *)
 (* -------------------------------------------------------------------------- *)
 
-let cfg infos = infos.cfg
+let body infos = infos.body
 let calls infos = infos.calls
 let annots infos = infos.annots
 let doomed infos = infos.doomed
 
 let unreachable infos v =
-  let reachability = Option.get infos.reachability in
-  let entry = (Option.get infos.cfg).entry_point in
-  not @@ Reachability.check_path reachability entry v
+  match infos.body, infos.reachability with
+  | Some cfg , Some reach ->
+      let entry = cfg.entry_point in
+      not @@ Reachability.check_path reach entry v
+  | _ -> true
 
 (* -------------------------------------------------------------------------- *)
 (* --- Selected Properties                                                --- *)
@@ -191,51 +193,52 @@ let loop_contract_pids kf stmt =
   | _ -> []
 
 let compile Key.{ kf ; bhv ; prop } =
-  let cfg, reachability =
+  let body, reachability =
     if Kernel_function.has_definition kf then
       let cfg = Cfg.get_automaton kf in
       Some cfg, Some (Reachability.create cfg.graph)
     else None, None
   in
   let infos = {
-    cfg ;
+    body ;
     annots = false ;
     doomed = Bag.empty ;
     calls = Fset.empty ;
-    reachability
+    reachability ;
   } in
   let behaviors = Annotations.behaviors kf in
+  (* Inits *)
   if WpStrategy.is_main_init kf then
     infos.annots <- List.exists (selected_main_bhv ~bhv ~prop) behaviors ;
-
-  if Kernel_function.has_definition kf then begin
-    let cfg = Option.get cfg in
-    (* Spec Iteration *)
-    if selected_disjoint_complete kf ~bhv ~prop ||
-       (List.exists (selected_bhv ~bhv ~prop) behaviors)
-    then infos.annots <- true ;
-    (* Stmt Iteration *)
-    Shash.iter
-      (fun stmt (src,_) ->
-         let fs = collect_calls ~bhv stmt in
-         let dead = unreachable infos src in
-         let ca = CfgAnnot.get_code_assertions kf stmt in
-         let ca_pids = List.map fst ca.code_verified in
-         let loop_pids = loop_contract_pids kf stmt in
-         if dead then begin
-           infos.doomed <- Bag.concat infos.doomed (Bag.list ca_pids) ;
-           infos.doomed <- Bag.concat infos.doomed (Bag.list loop_pids) ;
-         end else
-           begin
-             if not infos.annots &&
-                ( List.exists (selected ~bhv ~prop) ca_pids ||
-                  List.exists (selected ~bhv ~prop) loop_pids ||
-                  Fset.exists (selected_call ~bhv ~prop) fs )
-             then infos.annots <- true ;
-             infos.calls <- Fset.union fs infos.calls ;
-           end
-      ) cfg.stmt_table ;
-  end ;
+  (* Function Body *)
+  Option.iter
+    begin fun (cfg : Cfg.automaton) ->
+      (* Spec Iteration *)
+      if selected_disjoint_complete kf ~bhv ~prop ||
+         (List.exists (selected_bhv ~bhv ~prop) behaviors)
+      then infos.annots <- true ;
+      (* Stmt Iteration *)
+      Shash.iter
+        (fun stmt (src,_) ->
+           let fs = collect_calls ~bhv stmt in
+           let dead = unreachable infos src in
+           let ca = CfgAnnot.get_code_assertions kf stmt in
+           let ca_pids = List.map fst ca.code_verified in
+           let loop_pids = loop_contract_pids kf stmt in
+           if dead then begin
+             infos.doomed <- Bag.concat infos.doomed (Bag.list ca_pids) ;
+             infos.doomed <- Bag.concat infos.doomed (Bag.list loop_pids) ;
+           end else
+             begin
+               if not infos.annots &&
+                  ( List.exists (selected ~bhv ~prop) ca_pids ||
+                    List.exists (selected ~bhv ~prop) loop_pids ||
+                    Fset.exists (selected_call ~bhv ~prop) fs )
+               then infos.annots <- true ;
+               infos.calls <- Fset.union fs infos.calls ;
+             end
+        ) cfg.stmt_table ;
+    end body ;
   (* Collected Infos *)
   infos
 
diff --git a/src/plugins/wp/cfgInfos.mli b/src/plugins/wp/cfgInfos.mli
index b5420e9ffe8..89ff00c7da7 100644
--- a/src/plugins/wp/cfgInfos.mli
+++ b/src/plugins/wp/cfgInfos.mli
@@ -29,10 +29,9 @@ module Cfg = Interpreted_automata
 (** Memoized *)
 val get : Kernel_function.t -> ?bhv:string list -> ?prop:string list ->
   unit -> t
-
 val clear : unit -> unit
 
-val cfg : t -> Cfg.automaton option
+val body : t -> Cfg.automaton option
 val annots : t -> bool
 val doomed : t -> WpPropId.prop_id Bag.t
 val calls : t -> Kernel_function.Set.t
-- 
GitLab