From dc54bea118ab8ca4191ef86cc3f8fe04cff024d1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Loi=CC=88c=20Correnson?= <loic.correnson@cea.fr>
Date: Thu, 28 Jan 2021 19:23:20 +0100
Subject: [PATCH] [wp] complete & disjoint & side conditions

---
 src/kernel_services/ast_queries/ast_info.ml   |  8 ++--
 src/kernel_services/ast_queries/ast_info.mli  |  6 ++-
 .../ast_queries/logic_const.ml                |  6 ++-
 .../ast_queries/logic_const.mli               |  6 ++-
 src/plugins/wp/cfgAnnot.ml                    | 42 +++++++++++++++++--
 src/plugins/wp/cfgAnnot.mli                   |  4 ++
 src/plugins/wp/cfgCalculus.ml                 | 33 +++++++++++----
 7 files changed, 84 insertions(+), 21 deletions(-)

diff --git a/src/kernel_services/ast_queries/ast_info.ml b/src/kernel_services/ast_queries/ast_info.ml
index b2830548195..90397e1a578 100644
--- a/src/kernel_services/ast_queries/ast_info.ml
+++ b/src/kernel_services/ast_queries/ast_info.ml
@@ -117,15 +117,15 @@ let behavior_postcondition b k =
   in
   Logic_const.pimplies (assumes,postcondition)
 
-let behavior_precondition b =
+let behavior_precondition ?check b =
   let assumes = behavior_assumes b in
   let requires = Logic_const.pands
-      (List.rev_map Logic_const.pred_of_id_pred b.b_requires)
+      (List.rev_map (Logic_const.pred_of_id_pred ?check) b.b_requires)
   in
   Logic_const.pimplies (assumes,requires)
 
-let precondition spec =
-  Logic_const.pands (List.map behavior_precondition spec.spec_behavior)
+let precondition ?check spec =
+  Logic_const.pands (List.map (behavior_precondition ?check) spec.spec_behavior)
 
 (** find the behavior named [name] in the list *)
 let get_named_bhv bhv_list name =
diff --git a/src/kernel_services/ast_queries/ast_info.mli b/src/kernel_services/ast_queries/ast_info.mli
index 22cef1f7030..cce23bff9a1 100644
--- a/src/kernel_services/ast_queries/ast_info.mli
+++ b/src/kernel_services/ast_queries/ast_info.mli
@@ -65,16 +65,18 @@ val term_lvals_of_term: term -> term_lval list
 (** @return the list of all the term lvals of a given term.
     Purely syntactic function. *)
 
-val precondition : funspec -> predicate
+val precondition : ?check:bool -> funspec -> predicate
 (** Builds the precondition from [b_assumes] and [b_requires] clauses.
+    If [~check:false] is specified, check-only requires are skipped.
     @since Carbon-20101201 *)
 
 val behavior_assumes : funbehavior -> predicate
 (** Builds the conjunction of the [b_assumes].
     @since Nitrogen-20111001 *)
 
-val behavior_precondition : funbehavior -> predicate
+val behavior_precondition : ?check:bool -> funbehavior -> predicate
 (** Builds the precondition from [b_assumes] and [b_requires] clauses.
+    If [~check:false] is specified, check-only requires are skipped.
     @since Carbon-20101201 *)
 
 val behavior_postcondition : funbehavior -> termination_kind -> predicate
diff --git a/src/kernel_services/ast_queries/logic_const.ml b/src/kernel_services/ast_queries/logic_const.ml
index e53a0d86219..36830964006 100644
--- a/src/kernel_services/ast_queries/logic_const.ml
+++ b/src/kernel_services/ast_queries/logic_const.ml
@@ -51,8 +51,6 @@ let new_predicate ?only_check p =
 
 let fresh_predicate_id = PredicateId.next
 
-let pred_of_id_pred p = p.ip_content.tp_statement
-
 let refresh_predicate p = { p with ip_id = PredicateId.next () }
 
 let new_identified_term t =
@@ -342,6 +340,10 @@ let unamed ?(loc=Cil_datatype.Location.unknown) p =
 let ptrue = unamed Ptrue
 let pfalse = unamed Pfalse
 
+let pred_of_id_pred ?(check=true) p =
+  let tp = p.ip_content in
+  if tp.tp_only_check && not check then ptrue else tp.tp_statement
+
 let pold ?(loc=Cil_datatype.Location.unknown) p = match p.pred_content with
   | Ptrue | Pfalse -> p
   | _ -> {p with pred_content = Pat(p, old_label); pred_loc = loc}
diff --git a/src/kernel_services/ast_queries/logic_const.mli b/src/kernel_services/ast_queries/logic_const.mli
index 2c2ebd716d2..fadbb859a37 100644
--- a/src/kernel_services/ast_queries/logic_const.mli
+++ b/src/kernel_services/ast_queries/logic_const.mli
@@ -75,8 +75,10 @@ val refresh_predicate: identified_predicate -> identified_predicate
 (** @return a fresh id for predicates *)
 val fresh_predicate_id: unit -> int
 
-(** extract a named predicate for an identified predicate. *)
-val pred_of_id_pred: identified_predicate -> predicate
+(** extract a named predicate for an identified predicate.
+    When [~check:false] is specified, check-only predicate
+    returns a [ptrue] condition. *)
+val pred_of_id_pred: ?check:bool -> identified_predicate -> predicate
 
 (** creates a new identified term with a fresh id*)
 val new_identified_term: term -> identified_term
diff --git a/src/plugins/wp/cfgAnnot.ml b/src/plugins/wp/cfgAnnot.ml
index c6579e0f850..6bc07d26997 100644
--- a/src/plugins/wp/cfgAnnot.ml
+++ b/src/plugins/wp/cfgAnnot.ml
@@ -104,6 +104,43 @@ let get_behavior kf ki ~active bhv =
     bhv_assigns = assigns ;
   }
 
+(* -------------------------------------------------------------------------- *)
+(* --- Side Behavior Requires                                             --- *)
+(* -------------------------------------------------------------------------- *)
+
+let get_assumes kf bhv =
+  normalize_assumes kf Kglobal (Ast_info.behavior_assumes bhv)
+
+let get_preconditions kf =
+  (*TODO use this code instead! *)
+  (*
+  let assumes = get_assumes kf bhv in
+  List.map (normalize_pre kf Kglobal ~assumes bhv) bhv.b_requires
+  *)
+  List.map
+    (fun bhv ->
+       let p = Ast_info.behavior_precondition ~check:false bhv in
+       normalize_pre kf Kglobal bhv (Logic_const.new_predicate p)
+    ) (Annotations.behaviors kf)
+
+let get_complete_behaviors kf =
+  let spec = Annotations.funspec kf in
+  let module L = NormAtLabels in
+  List.map
+    (fun bs ->
+       WpPropId.mk_compl_bhv_id (kf,Kglobal,[],bs) ,
+       L.preproc_annot L.labels_fct_pre @@ Ast_info.complete_behaviors spec bs
+    ) spec.spec_complete_behaviors
+
+let get_disjoint_behaviors kf =
+  let spec = Annotations.funspec kf in
+  let module L = NormAtLabels in
+  List.map
+    (fun bs ->
+       WpPropId.mk_disj_bhv_id (kf,Kglobal,[],bs) ,
+       L.preproc_annot L.labels_fct_pre @@ Ast_info.disjoint_behaviors spec bs
+    ) spec.spec_disjoint_behaviors
+
 (* -------------------------------------------------------------------------- *)
 (* --- Called Contract                                                    --- *)
 (* -------------------------------------------------------------------------- *)
@@ -112,7 +149,7 @@ let get_behavior kf ki ~active bhv =
 module AllPrecondStatus =
   State_builder.Hashtbl(Kernel_function.Hashtbl)(Datatype.Unit)
     (struct
-      let name = "Call Preconditions Proxy Generated"
+      let name = "Wp.CfgAnnot.AllPrecondStatus"
       let dependencies = [Ast.self]
       let size = 32
     end)
@@ -164,8 +201,7 @@ let get_call_contract kf =
   setup_preconditions kf ;
   List.iter
     begin fun bhv ->
-      let assumes =
-        normalize_assumes kf Kglobal (Ast_info.behavior_assumes bhv) in
+      let assumes = get_assumes kf bhv in
       let mk_pre = normalize_pre kf Kglobal bhv ~assumes in
       let mk_post = normalize_post kf Kglobal bhv ~assumes in
       List.iter (add cpre @@ mk_pre) bhv.b_requires ;
diff --git a/src/plugins/wp/cfgAnnot.mli b/src/plugins/wp/cfgAnnot.mli
index 5da0e8ab665..44a71ff4ed8 100644
--- a/src/plugins/wp/cfgAnnot.mli
+++ b/src/plugins/wp/cfgAnnot.mli
@@ -44,6 +44,10 @@ val get_requires : kernel_function -> kinstr -> funbehavior -> pred_info list
 val get_behavior : kernel_function -> kinstr -> active:string list ->
   funbehavior -> behavior
 
+val get_preconditions : kernel_function -> pred_info list
+val get_complete_behaviors : kernel_function -> pred_info list
+val get_disjoint_behaviors : kernel_function -> pred_info list
+
 (* -------------------------------------------------------------------------- *)
 (* --- Property Accessors : Assertions                                    --- *)
 (* -------------------------------------------------------------------------- *)
diff --git a/src/plugins/wp/cfgCalculus.ml b/src/plugins/wp/cfgCalculus.ml
index 32afaa6c367..8a1ef560ed0 100644
--- a/src/plugins/wp/cfgCalculus.ml
+++ b/src/plugins/wp/cfgCalculus.ml
@@ -146,7 +146,7 @@ struct
     is_active_mode ~mode pi &&
     ( not goal || is_selected_props props ~pi pid )
 
-  let is_selected_precond { props } (pid,_) =
+  let is_selected_callpre { props } (pid,_) =
     is_selected_props props pid
 
   let use_assigns env (a : assigns) w =
@@ -296,13 +296,25 @@ struct
     if is_default_bhv env.mode then
       let pre =
         List.filter_map (fun p ->
-            if is_selected_precond env p then
+            if is_selected_callpre env p then
               Some (CfgAnnot.get_precond_at kf s p)
             else None
           ) c.call_pre
       in W.call_goal_precond env.we s kf es ~pre w_call
     else w_call
 
+  let behaviors kf =
+    if WpStrategy.is_main_init kf || WpLog.PrecondWeakening.get () then []
+    else CfgAnnot.get_preconditions kf
+
+  let complete mode kf =
+    if not (is_default_bhv mode) then []
+    else CfgAnnot.get_complete_behaviors kf
+
+  let disjoint mode kf =
+    if not (is_default_bhv mode) then []
+    else CfgAnnot.get_disjoint_behaviors kf
+
   let body env ~ensures ~exits w =
     let rw = List.fold_right (prove_property env) ensures w in
     let rk = List.fold_right (prove_property env) exits w in
@@ -312,26 +324,31 @@ struct
 
   (* Putting everything together *)
   let compute ~mode ~props =
+    let kf = mode.kf in
     let env = {
       mode ; props ;
-      cfg = Cfg.get_automaton mode.kf ;
-      we = W.new_env mode.kf ;
+      cfg = Cfg.get_automaton kf ;
+      we = W.new_env kf ;
       wp = Vhash.create 32 ;
       wk = W.empty ;
     } 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
+    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
+
     env.we ,
     (* global init *)
     W.close env.we @@
-    I.process_global_init env.we mode.kf @@
+    I.process_global_init env.we kf @@
     W.scope env.we [] SC_Global @@
     (* pre-state *)
     W.label env.we None Clabels.pre @@
     List.fold_right (use_property env) req @@
     List.fold_right (use_property env) bhv.bhv_assumes @@
     List.fold_right (use_property env) bhv.bhv_requires @@
+    List.fold_right (use_property env) (behaviors kf) @@
+    List.fold_right (use_property env) (complete mode kf) @@
+    List.fold_right (use_property env) (disjoint mode kf) @@
     (* frame-in *)
     W.scope env.we xs SC_Frame_in @@
     (* function body *)
-- 
GitLab